コード例 #1
0
        public HostJsonFile(string filePath)
        {
            var fileText = Helpers.SafelyReadFromFile(filePath);


            Data = JsonConvert.DeserializeObject <HostJson>(fileText, _settings);
        }
コード例 #2
0
        public FunctionsCSharpFile(string file, HostJson hostData)
        {
            Name     = Path.GetFileNameWithoutExtension(file);
            FileName = file;

            var fileText = Helpers.SafelyReadFromFile(file);


            Syntax = CSharpSyntaxTree.ParseText(fileText, new CSharpParseOptions(LanguageVersion.Latest, DocumentationMode.None, SourceCodeKind.Regular));

            Context = new GenerationContext();
            Root    = Syntax.GetRoot() as CompilationUnitSyntax;
            var usingStatements = Root.DescendantNodes().OfType <UsingDirectiveSyntax>().ToList();

            Regex allowedUsings;
            Regex unallowedUsings;

            if (Settings.AllowedNamespaces?.Any() ?? false)
            {
                allowedUsings = new Regex($"({string.Join("|", Settings.AllowedNamespaces)})");
            }
            else
            {
                allowedUsings = new Regex($"(.+)");
            }

            if (Settings.ExcludedNamespaces?.Any() ?? false)
            {
                unallowedUsings = new Regex($"({string.Join("|", Settings.ExcludedNamespaces)})");
            }
            else
            {
                unallowedUsings = new Regex($"(^[.]+)");
            }

            Context.UsingStatements = usingStatements.Select(x => x.WithoutLeadingTrivia().WithoutTrailingTrivia().ToFullString())
                                      .Where(x => allowedUsings.IsMatch(x) &&
                                             !unallowedUsings.IsMatch(x))
                                      .ToList();

            var namespaceDeclarations = Root.DescendantNodes().OfType <NamespaceDeclarationSyntax>().ToList();

            foreach (var nsd in namespaceDeclarations)
            {
                var classDeclarations = nsd.DescendantNodes().OfType <ClassDeclarationSyntax>().ToList();

                foreach (var cd in classDeclarations)
                {
                    var methods = cd.DescendantNodes().OfType <MethodDeclarationSyntax>()
                                  .Where(x => x.Modifiers.Any(y => y.Text == "public") && x.Modifiers.Any(y => y.Text == "static"))
                                  .ToList();

                    foreach (var method in methods)
                    {
                        Context.Functions.Add(ClassParser.ReadMethodAsFunction(method, hostData));
                    }
                }
            }
        }
コード例 #3
0
        public static FunctionEndpoint ReadMethodAsFunction(MethodDeclarationSyntax syntax, HostJson hostData)
        {
            var attributes = syntax.DescendantNodes().OfType <AttributeListSyntax>().SelectMany(x => x.Attributes).ToList();

            var endpoint = new FunctionEndpoint();

            try
            {
                var endpointName = attributes.GetAttribute <FunctionNameAttribute>();

                if (endpointName == null)
                {
                    endpoint.Ignored = true;
                    return(endpoint);
                }

                endpoint.Name = endpointName.GetAttributeValue();

                //Ignore generator attribute
                endpoint.Ignored = attributes.HasAttribute <NotGeneratedAttribute>();


                //Obsolete Attribute
                var obsoleteAttribute = attributes.GetAttribute <ObsoleteAttribute>();
                if (obsoleteAttribute != null)
                {
                    endpoint.Obsolete        = true;
                    endpoint.ObsoleteMessage = obsoleteAttribute.GetAttributeValue();
                }

                //Response types
                var responseTypes = attributes.GetAttributes <ProducesResponseTypeAttribute>();
                var responses     = responseTypes.Select(x => new ResponseTypeDefinition(x)).ToList();
                responses.Add(new ResponseTypeDefinition(true));

                endpoint.ResponseTypes = responses.Select(x => new ResponseType(x.Type, Helpers.EnumParse <HttpStatusCode>(x.StatusValue))).ToList();

                var duplicateResponseTypes = endpoint.GetResponseTypes().GroupBy(x => x.Status).Where(x => x.Count() > 1).ToList();

                if (duplicateResponseTypes.Any())
                {
                    throw new NotSupportedException($"Endpoint has multiple response types of the same status defined. {string.Join(", ", duplicateResponseTypes.Select(x => x.Key?.ToString()))}");
                }
                //Add after so we don't get duplicate error from the null Status
                endpoint.ResponseTypes.Add(new ExceptionResponseType());


                //Need to check if the function has a HttpTrigger
                var httpTriggerAttribute = syntax.ParameterList.Parameters.SingleOrDefault(x => x.AttributeLists.SelectMany(y => y.Attributes).HasAttribute <HttpTriggerAttribute>());

                if (httpTriggerAttribute == null)
                {
                    endpoint.Ignored = true;
                    return(endpoint);
                }

                var triggerAttribute = new HttpTriggerParameter(httpTriggerAttribute);

                endpoint.SupportedMethods = triggerAttribute.Methods;

                var routePrefix = hostData?.http?.routePrefix ?? "api";

                if (triggerAttribute.Route != null)
                {
                    var route = triggerAttribute.Route.TrimStart('/');

                    if (!string.IsNullOrEmpty(routePrefix))
                    {
                        if (!route.StartsWith(routePrefix))
                        {
                            route = $"{routePrefix}/" + route;
                        }

                        route = "/" + route;
                    }

                    endpoint.Route = new HttpRoute(route);
                }
                else
                {
                    if (!string.IsNullOrEmpty(routePrefix))
                    {
                        endpoint.Route = new HttpRoute($"{routePrefix}/{endpoint.Name}");
                    }
                    else
                    {
                        endpoint.Route = new HttpRoute($"{endpoint.Name}");
                    }
                }


                var expectedBodyParameters = attributes.GetAttributes <ExpectedBodyParameterAttribute>()
                                             .Select(x => new ExpectedBodyParamterDefinition(x))
                                             .GroupBy(x => x.Method)
                                             .ToDictionary(x => x.Key, y => y.Select(z => (IParameter) new BodyParameter("body", z.Type, null)));

                var expectedQueryParameters = attributes.GetAttributes <ExpectedQueryParameterAttribute>()
                                              .Select(x => new ExpectedQueryParamterDefinition(x))
                                              .GroupBy(x => x.Method)
                                              .ToDictionary(x => x.Key, y => y.Select(z => (IParameter) new QueryParameter(z.Name, z.Type, null, z.IsQueryObject)));

                endpoint.HttpParameters = expectedBodyParameters.Union(expectedQueryParameters).ToDictionary();

                var parameters = syntax.ParameterList.Parameters.Select(x => new ParameterDefinition(x, endpoint.GetFullRoute())).ToList();

                var routeParams = parameters.Where(x => x.Options.FromRoute).Select(x => new RouteParameter(x.RouteName, x.Type, x.Default)).ToList();

                endpoint.Parameters = routeParams.Cast <IParameter>().NotNull().ToList();

                endpoint.Parameters.Add(new CancellationTokenModifier());
                endpoint.Parameters.Add(new CookieModifier());
                endpoint.Parameters.Add(new HeadersModifier());
                endpoint.Parameters.Add(new TimeoutModifier());

                if (triggerAttribute.AuthLevel == AuthorizationLevel.User)
                {
                    if (!endpoint.ResponseTypes.Any(x => x.Status == HttpStatusCode.Unauthorized))
                    {
                        endpoint.ResponseTypes.Add(new ResponseType(HttpStatusCode.Unauthorized));
                    }

                    endpoint.Parameters.Add(new SecurityModifier());
                }
                else if (triggerAttribute.AuthLevel == AuthorizationLevel.Anonymous)
                {
                }
                else
                {
                    if (!endpoint.ResponseTypes.Any(x => x.Status == HttpStatusCode.Unauthorized))
                    {
                        endpoint.ResponseTypes.Add(new ResponseType(HttpStatusCode.Unauthorized));
                    }

                    endpoint.Parameters.Add(new FunctionAuthModifier());
                }


                var parameterHeaders = attributes.GetAttributes <HeaderParameterAttribute>()
                                       .Select(x => new ParameterHeaderDefinition(x))
                                       .ToList();
                endpoint.ParameterHeader = parameterHeaders.Select(x => new ParameterHeader(x.Name, x.Type, x.DefaultValue)).ToList();



                var headers = attributes.GetAttributes <IncludeHeaderAttribute>()
                              .Select(x => new HeaderDefinition(x))
                              .ToList();
                endpoint.ConstantHeader = headers.Select(x => new ConstantHeader(x.Name, x.Value)).ToList();


                var rawReturnType = syntax.ReturnType?.ToFullString();

                var returnType = Helpers.GetTypeFromString(rawReturnType.Trim());

                while (returnType.IsContainerReturnType())
                {
                    returnType = returnType.Arguments.SingleOrDefault();
                }

                if (Helpers.IsType(typeof(IActionResult).FullName, returnType?.Name))
                {
                    returnType = null;
                }

                if (returnType?.Name == "void" ||
                    (Helpers.IsType(typeof(Task).FullName, returnType?.Name) && (!returnType?.Arguments.Any() ?? false)))
                {
                    returnType = null;
                }

                if (returnType.IsFileReturnType())
                {
                    returnType             = new Helpers.TypeString(typeof(Stream).FullName);
                    endpoint.ReturnsStream = true;
                }

                rawReturnType = returnType?.ToString();

                endpoint.ReturnType = rawReturnType?.Trim();

                foreach (var method in endpoint.SupportedMethods)
                {
                    var duplicateParameters = endpoint.GetParametersWithoutResponseTypesForHttpMethod(method).GroupBy(x => x.Name).Where(x => x.Count() > 1).ToList();

                    if (duplicateParameters.Any())
                    {
                        throw new NotSupportedException($"Function has multiple parameters of the same name defined. {string.Join(", ", duplicateParameters.Select(x => x.Key?.ToString()))}");
                    }


                    var invalidParameters = endpoint.GetParametersForHttpMethod(method).Where(x => !Microsoft.CodeAnalysis.CSharp.SyntaxFacts.IsValidIdentifier(x.Name)).ToList();

                    if (invalidParameters.Any())
                    {
                        throw new NotSupportedException($"Function {endpoint.Name} has parameters that are invalid variable names. {string.Join(", ", invalidParameters.Select(x => x.Name))}");
                    }
                }
            }
            catch (NotSupportedException nse)
            {
                if (endpoint.Ignored)
                {
                    return(endpoint);
                }

                endpoint.Failed = true;
                endpoint.Error  = nse.Message;
            }
#if !DEBUG
            catch (Exception ex)
            {
                endpoint.Failed            = true;
                endpoint.UnexpectedFailure = true;
                endpoint.Error             = ex.ToString();
            }
#endif


            return(endpoint);
        }
コード例 #4
0
        public HostJsonFile(string filePath)
        {
            var fileText = Helpers.SafelyReadFromFile(filePath);

            Data = Helpers.DeserializeFromJson <HostJson>(fileText);
        }