コード例 #1
0
        private static IEnumerable <MemberDeclarationSyntax> MixinPartialClasses(SourceFileContext ctx, ServiceDetails svc)
        {
            if (svc.Mixins.Any())
            {
                // Emit partial class to give access to clients for mixin APIs.
                // (We may well have one of these *and* an LRO partial class, but that's okay.)
                var grpcOuterCls = Class(Public | Static | Partial, svc.GrpcClientTyp.DeclaringTyp);
                using (ctx.InClass(grpcOuterCls))
                {
                    var grpcInnerClass = Class(Public | Partial, svc.GrpcClientTyp);
                    using (ctx.InClass(grpcInnerClass))
                    {
                        var callInvoker = Property(Private, ctx.TypeDontCare, "CallInvoker");

                        foreach (var mixin in svc.Mixins)
                        {
                            var grpcClientType     = ctx.Type(mixin.GrpcClientType);
                            var createClientMethod = Method(Public | Virtual, grpcClientType, "Create" + mixin.GrpcClientType.Name)()
                                                     .WithBody(New(grpcClientType)(callInvoker))
                                                     .WithXmlDoc(
                                XmlDoc.Summary("Creates a new instance of ", grpcClientType, " using the same call invoker as this client."),
                                XmlDoc.Returns("A new ", grpcClientType, " for the same target as this client.")
                                );
                            grpcInnerClass = grpcInnerClass.AddMembers(createClientMethod);
                        }
                    }
                    grpcOuterCls = grpcOuterCls.AddMembers(grpcInnerClass);
                }
                yield return(grpcOuterCls);
            }
        }
コード例 #2
0
 private static IEnumerable <MemberDeclarationSyntax> LroPartialClasses(SourceFileContext ctx, ServiceDetails svc)
 {
     if (svc.Methods.Any(m => m is MethodDetails.Lro))
     {
         // Emit partial class to give access to an LRO operations client.
         var grpcOuterCls = Class(Public | Static | Partial, svc.GrpcClientTyp.DeclaringTyp);
         using (ctx.InClass(grpcOuterCls))
         {
             var grpcInnerClass = Class(Public | Partial, svc.GrpcClientTyp);
             using (ctx.InClass(grpcInnerClass))
             {
                 var callInvoker = Property(Private, ctx.TypeDontCare, "CallInvoker");
                 var opTyp       = ctx.Type <Operations.OperationsClient>();
                 var createOperationsClientMethod = Method(Public | Virtual, opTyp, "CreateOperationsClient")()
                                                    .WithBody(New(opTyp)(callInvoker))
                                                    .WithXmlDoc(
                     XmlDoc.Summary("Creates a new instance of ", opTyp, " using the same call invoker as this client."),
                     XmlDoc.Returns("A new Operations client for the same target as this client.")
                     );
                 grpcInnerClass = grpcInnerClass.AddMembers(createOperationsClientMethod);
             }
             grpcOuterCls = grpcOuterCls.AddMembers(grpcInnerClass);
         }
         yield return(grpcOuterCls);
     }
 }
コード例 #3
0
        private static IEnumerable <MemberDeclarationSyntax> PaginatedPartialClasses(SourceFileContext ctx, ServiceDetails svc, HashSet <Typ> seenPaginatedResponseTyps)
        {
            var paginatedMethods = svc.Methods.OfType <MethodDetails.Paginated>();

            foreach (var representingMethod in paginatedMethods
                     .GroupBy(m => m.RequestTyp)
                     .Select(typMethodGrp => typMethodGrp.First()))
            {
                yield return(PaginatedPartialInterfaceClass(ctx, representingMethod.RequestTyp, representingMethod.RequestMessageDesc));
            }

            foreach (var method in paginatedMethods)
            {
                if (seenPaginatedResponseTyps.Add(method.ResponseTyp))
                {
                    var cls = Class(Public | Partial, method.ResponseTyp, baseTypes: ctx.Type(Typ.Generic(typeof(IPageResponse <>), method.ResourceTyp)));
                    using (ctx.InClass(cls))
                    {
                        var propertyName         = method.ResourcesFieldName;
                        var genericGetEnumerator = Method(Public, ctx.Type(Typ.Generic(typeof(IEnumerator <>), method.ResourceTyp)), "GetEnumerator")()
                                                   .WithBody(Property(Public, ctx.TypeDontCare, propertyName).Call(nameof(IEnumerable <int> .GetEnumerator))())
                                                   .WithXmlDoc(XmlDoc.Summary("Returns an enumerator that iterates through the resources in this response."));
                        var getEnumerator = Method(None, ctx.Type <IEnumerator>(), "GetEnumerator")()
                                            .WithExplicitInterfaceSpecifier(ctx.Type <IEnumerable>())
                                            .WithBody(This.Call(genericGetEnumerator)());
                        cls = cls.AddMembers(genericGetEnumerator, getEnumerator);
                    }
                    yield return(cls);
                }
            }
        }
コード例 #4
0
            public ClassDeclarationSyntax Generate()
            {
                var cls = Class(Public | Sealed | Partial, _def.ResourceNameTyp, _ctx.Type <IResourceName>(), _ctx.Type(Typ.Generic(typeof(IEquatable <>), _def.ResourceNameTyp)))
                          .WithXmlDoc(XmlDoc.Summary("Resource name for the ", XmlDoc.C(_def.DocName), " resource."));

                using (_ctx.InClass(cls))
                {
                    cls = cls.AddMembers(ResourceTypeEnum());
                    cls = cls.AddMembers(TemplateFields().ToArray());
                    cls = cls.AddMembers(FromUnparsedMethod());
                    cls = cls.AddMembers(FromMethods().ToArray());
                    cls = cls.AddMembers(FormatMethods().ToArray());
                    cls = cls.AddMembers(ParseMethods().ToArray());
                    cls = cls.AddMembers(Constructors(cls).ToArray());
                    cls = cls.AddMembers(ResourceType());
                    cls = cls.AddMembers(UnparsedResourceNameProperty());
                    cls = cls.AddMembers(Properties().ToArray());
                    cls = cls.AddMembers(IsKnownPattern());
                    cls = cls.AddMembers(ToString());
                    cls = cls.AddMembers(GetHashCode());
                    cls = cls.AddMembers(Equals());
                    cls = cls.AddMembers(EqualsIEquatable());
                    cls = cls.AddMembers(EqualityOperator());
                    cls = cls.AddMembers(InequalityOperator());
                }
                return(cls);
            }
コード例 #5
0
        public ClassDeclarationSyntax GenerateBaseRequestClass(SourceFileContext ctx)
        {
            var cls = Class(
                Modifier.Public | Modifier.Abstract,
                BaseRequestTyp,
                ctx.Type(Typ.Generic(typeof(ClientServiceRequest <>), Typ.GenericParam("TResponse"))))
                      .WithXmlDoc(XmlDoc.Summary($"A base abstract class for {ClassName} requests."));

            using (ctx.InClass(BaseRequestTyp))
            {
                var serviceParam = Parameter(ctx.Type <IClientService>(), "service");
                var ctor         = Ctor(Modifier.Protected, cls, BaseInitializer(serviceParam))(serviceParam)
                                   .WithBody()
                                   .WithXmlDoc(XmlDoc.Summary($"Constructs a new {ClassName}BaseServiceRequest instance."));

                var parameters = CreateParameterList(BaseRequestTyp);

                cls = cls.AddMembers(ctor);
                cls = cls.AddMembers(parameters.SelectMany(p => p.GenerateDeclarations(ctx)).ToArray());

                var initParameters = Method(Modifier.Protected | Modifier.Override, VoidType, "InitParameters")()
                                     .WithBlockBody(
                    BaseExpression().Call("InitParameters")(),
                    parameters.Select(p => p.GenerateInitializer(ctx)).ToArray())
                                     .WithXmlDoc(XmlDoc.Summary($"Initializes {ClassName} parameter list."));

                cls = cls.AddMembers(initParameters);
            }
            return(cls);
        }
コード例 #6
0
        public ClassDeclarationSyntax GenerateClass(SourceFileContext ctx)
        {
            var cls = Class(Modifier.Public, Typ)
                      .WithXmlDoc(XmlDoc.Summary($"The \"{Name}\" collection of methods."));

            using (ctx.InClass(Typ))
            {
                // TODO: validate that lower camel case is the right option here.
                var resourceString = Field(Modifier.Private | Modifier.Const, ctx.Type <string>(), "Resource")
                                     .WithInitializer(Name.ToLowerCamelCase(upperAfterDigit: null));

                var service = Field(Modifier.Private | Modifier.Readonly, ctx.Type <IClientService>(), "service")
                              .WithXmlDoc(XmlDoc.Summary("The service which this resource belongs to."));

                var subresources = Subresources.Select(subresource => (property: subresource.GenerateProperty(ctx), resource: subresource));

                var ctorParameter = Parameter(ctx.Type <IClientService>(), "service");
                var ctor          = Ctor(Modifier.Public, cls)(ctorParameter)
                                    .WithBlockBody(
                    new[] { service.AssignThisQualified(ctorParameter) }
                    .Concat(subresources.Select(pair => pair.property.Assign(New(ctx.Type(pair.resource.Typ))(ctorParameter))))
                    .ToArray()
                    )
                                    .WithXmlDoc(XmlDoc.Summary("Constructs a new resource."));

                cls = cls.AddMembers(resourceString, service, ctor);

                foreach (var subresourceProperty in subresources)
                {
                    cls = cls.AddMembers(subresourceProperty.property, subresourceProperty.resource.GenerateClass(ctx));
                }

                foreach (var method in Methods)
                {
                    cls = cls.AddMembers(method.GenerateDeclarations(ctx).ToArray());
                }
            }
            return(cls);
        }
コード例 #7
0
        private static MemberDeclarationSyntax PaginatedPartialInterfaceClass(SourceFileContext ctx, Typ typ, MessageDescriptor messageDesc)
        {
            var partialInterfaceCls = Class(Public | Partial, typ, baseTypes: ctx.Type <IPageRequest>());

            if (messageDesc.FindFieldByName("page_size") is null)
            {
                //DiREGapic scenario where `max_results` is an option for a page size-semantic field.
                var maxResMessage = messageDesc.FindFieldByName("max_results");
                if (maxResMessage is null)
                {
                    throw new InvalidOperationException("Paginated request should have either page_size or max_results field.");
                }

                using (ctx.InClass(partialInterfaceCls))
                {
                    var underlyingProperty = Property(DontCare, ctx.TypeDontCare, "MaxResults");

                    var getBody = ProtoTyp.Of(maxResMessage) == Typ.Of <int>()
                        ? Return(underlyingProperty)
                        : Return(CheckedCast(ctx.Type <int>(), underlyingProperty));

                    var assignFrom = ProtoTyp.Of(maxResMessage) == Typ.Of <int>()
                        ? Value
                        : CheckedCast(ctx.Type(ProtoTyp.Of(maxResMessage)), Value);
                    var setBody = underlyingProperty.Assign(assignFrom);

                    var property = Property(Public, ctx.Type <int>(), "PageSize")
                                   .WithGetBody(getBody)
                                   .WithSetBody(setBody)
                                   .WithXmlDoc(XmlDoc.InheritDoc);
                    partialInterfaceCls = partialInterfaceCls.AddMembers(property);
                }
            }

            return(partialInterfaceCls);
        }
コード例 #8
0
        public ClassDeclarationSyntax GenerateClass(SourceFileContext ctx)
        {
            var cls = Class(Modifier.Public, Typ, Parent is null ? new[] { ctx.Type <IDirectResponseSchema>() } : Array.Empty <TypeSyntax>());

            using (ctx.InClass(Typ))
            {
                if (_schema.Description is string description)
                {
                    cls = cls.WithXmlDoc(XmlDoc.Summary(description));
                }
                cls = cls.AddMembers(Properties.SelectMany(p => p.GeneratePropertyDeclarations(ctx)).ToArray());

                // Top-level data models automatically have an etag property if one isn't otherwise generated.
                if (Parent is null && !Properties.Any(p => p.Name == "etag"))
                {
                    var etag = AutoProperty(Modifier.Public | Modifier.Virtual, ctx.Type <string>(), "ETag", hasSetter: true)
                               .WithXmlDoc(XmlDoc.Summary("The ETag of the item."));
                    cls = cls.AddMembers(etag);
                }

                cls = cls.AddMembers(Properties.SelectMany(p => p.GenerateAnonymousModels(ctx)).ToArray());
            }
            return(cls);
        }
コード例 #9
0
        private static IEnumerable <MemberDeclarationSyntax> LroPartialClasses(SourceFileContext ctx, ServiceDetails svc)
        {
            if (svc.Methods.Any(m => m is MethodDetails.StandardLro))
            {
                // Emit partial class to give access to an LRO operations client.
                var grpcOuterCls = Class(Public | Static | Partial, svc.GrpcClientTyp.DeclaringTyp);
                using (ctx.InClass(grpcOuterCls))
                {
                    var grpcInnerClass = Class(Public | Partial, svc.GrpcClientTyp);
                    using (ctx.InClass(grpcInnerClass))
                    {
                        var callInvoker = Property(Private, ctx.TypeDontCare, "CallInvoker");
                        var opTyp       = ctx.Type <Operations.OperationsClient>();
                        var createOperationsClientMethod = Method(Public | Virtual, opTyp, "CreateOperationsClient")()
                                                           .WithBody(New(opTyp)(callInvoker))
                                                           .WithXmlDoc(
                            XmlDoc.Summary("Creates a new instance of ", opTyp, " using the same call invoker as this client."),
                            XmlDoc.Returns("A new Operations client for the same target as this client.")
                            );
                        grpcInnerClass = grpcInnerClass.AddMembers(createOperationsClientMethod);
                    }
                    grpcOuterCls = grpcOuterCls.AddMembers(grpcInnerClass);
                }
                yield return(grpcOuterCls);
            }

            // Generate partial classes to delegate to other services handling operations
            if (svc.Methods.Any(m => m is MethodDetails.NonStandardLro))
            {
                var operationServices = svc.Methods.OfType <MethodDetails.NonStandardLro>().Select(lro => lro.OperationService).Distinct().ToList();

                // Emit partial class to give access to an LRO operations client.
                var grpcOuterCls = Class(Public | Static | Partial, svc.GrpcClientTyp.DeclaringTyp);
                using (ctx.InClass(grpcOuterCls))
                {
                    var grpcInnerClass = Class(Public | Partial, svc.GrpcClientTyp);
                    using (ctx.InClass(grpcInnerClass))
                    {
                        var callInvoker = Property(Private, ctx.TypeDontCare, "CallInvoker");
                        var opTyp       = ctx.Type <Operations.OperationsClient>();

                        foreach (var operationService in operationServices)
                        {
                            var grpcClient = ctx.Type(Typ.Nested(Typ.Manual(ctx.Namespace, operationService), $"{operationService}Client"));
                            var createOperationsClientMethod = Method(Public | Virtual, opTyp, $"CreateOperationsClientFor{operationService}")()
                                                               .WithBody(grpcClient.Call("CreateOperationsClient")(callInvoker))
                                                               .WithXmlDoc(
                                XmlDoc.Summary("Creates a new instance of ", opTyp, $" using the same call invoker as this client, delegating to {operationService}."),
                                XmlDoc.Returns("A new Operations client for the same target as this client.")
                                );
                            grpcInnerClass = grpcInnerClass.AddMembers(createOperationsClientMethod);
                        }
                    }
                    grpcOuterCls = grpcOuterCls.AddMembers(grpcInnerClass);
                }
                yield return(grpcOuterCls);
            }

            // Generate partial classes for the operation-handling services
            if (svc.NonStandardLro is ServiceDetails.NonStandardLroDetails lroDetails)
            {
                // Emit partial class to give access to an LRO operations client.
                var grpcOuterCls = Class(Public | Static | Partial, svc.GrpcClientTyp.DeclaringTyp);
                using (ctx.InClass(grpcOuterCls))
                {
                    var grpcInnerClass = Class(Public | Partial, svc.GrpcClientTyp);
                    using (ctx.InClass(grpcInnerClass))
                    {
                        var callInvoker                  = Parameter(ctx.Type <CallInvoker>(), "callInvoker");
                        var request                      = Parameter(ctx.TypeDontCare, "request");
                        var response                     = Parameter(ctx.TypeDontCare, "response");
                        var opTyp                        = ctx.Type <Operations.OperationsClient>();
                        var forwardingCallInvoker        = Local(ctx.Type <CallInvoker>(), "forwardingCallInvoker");
                        var createOperationsClientMethod = Method(Internal | Static, opTyp, "CreateOperationsClient")(callInvoker)
                                                           .WithBody(
                            forwardingCallInvoker.WithInitializer(
                                // Note: can't use Typ.Of<ForwardingCallInvoker<GetOperationRequest>> as it's a static class.
                                ctx.Type(Typ.Generic(Typ.Of(typeof(ForwardingCallInvoker <>)), Typ.Of <GetOperationRequest>())).Call("Create")(
                                    callInvoker,
                                    "/google.longrunning.Operations/GetOperation",
                                    Property(Private, ctx.TypeDontCare, $"__Method_{lroDetails.PollingMethod.Name}"),
                                    ctx.Type(lroDetails.PollingRequestTyp).Access("ParseLroRequest"),     // Method group conversion
                                    Lambda(request, response)(response.Call("ToLroResponse")(request.Access("Name")))
                                    )),
                            Return(New(opTyp)(forwardingCallInvoker)))
                                                           .WithXmlDoc(
                            XmlDoc.Summary(
                                "Creates a new instance of ", opTyp, "using the specified call invoker, but ",
                                $"redirecting Google.LongRunning RPCs to {lroDetails.Service.Name} RPCs."),
                            XmlDoc.Returns("A new Operations client for the same target as this client.")
                            );
                        grpcInnerClass = grpcInnerClass.AddMembers(createOperationsClientMethod);
                    }
                    grpcOuterCls = grpcOuterCls.AddMembers(grpcInnerClass);
                }
                yield return(grpcOuterCls);
            }
        }
コード例 #10
0
        public ClassDeclarationSyntax GenerateServiceClass(SourceFileContext ctx)
        {
            var cls = Class(Modifier.Public, ServiceTyp, ctx.Type <BaseClientService>()).WithXmlDoc(XmlDoc.Summary($"The {ClassName} Service."));

            using (ctx.InClass(cls))
            {
                var discoveryVersionTyp = Typ.Manual("Google.Apis.Discovery", "DiscoveryVersion");
                var version             = Field(Modifier.Public | Modifier.Const, ctx.Type <string>(), "Version")
                                          .WithInitializer(ApiVersion)
                                          .WithXmlDoc(XmlDoc.Summary("The API version."));
                var discoveryVersion = Field(Modifier.Public | Modifier.Static, ctx.Type(discoveryVersionTyp), "DiscoveryVersionUsed")
                                       .WithInitializer(ctx.Type(discoveryVersionTyp).Access(nameof(DiscoveryVersion.Version_1_0)))
                                       .WithXmlDoc(XmlDoc.Summary("The discovery version used to generate this service."));

                var parameterlessCtor = Ctor(Modifier.Public, cls, ThisInitializer(New(ctx.Type <BaseClientService.Initializer>())()))()
                                        .WithBody()
                                        .WithXmlDoc(XmlDoc.Summary("Constructs a new service."));

                var initializerParam = Parameter(ctx.Type <BaseClientService.Initializer>(), "initializer");

                var featuresArrayInitializer = ApiFeatures.Any()
                    ? NewArray(ctx.ArrayType(Typ.Of <string[]>()))(ApiFeatures.ToArray())
                    : NewArray(ctx.ArrayType(Typ.Of <string[]>()), LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(0)));
                var features = Property(Modifier.Public | Modifier.Override, ctx.Type <IList <string> >(), "Features")
                               .WithGetBody(featuresArrayInitializer)
                               .WithXmlDoc(XmlDoc.Summary("Gets the service supported features."));

                var nameProperty = Property(Modifier.Public | Modifier.Override, ctx.Type <string>(), "Name")
                                   .WithGetBody(ApiName)
                                   .WithXmlDoc(XmlDoc.Summary("Gets the service name."));

                // Note: the following 4 properties have special handling post-generation, in terms
                // of adding the #if directives in.
                var baseUri = Property(Modifier.Public | Modifier.Override, ctx.Type <string>(), "BaseUri")
                              .WithGetBody(IdentifierName("BaseUriOverride").NullCoalesce(BaseUri))
                              .WithXmlDoc(XmlDoc.Summary("Gets the service base URI."));

                var basePath = Property(Modifier.Public | Modifier.Override, ctx.Type <string>(), "BasePath")
                               .WithGetBody(BasePath)
                               .WithXmlDoc(XmlDoc.Summary("Gets the service base path."));

                var batchUri = Property(Modifier.Public | Modifier.Override, ctx.Type <string>(), "BatchUri")
                               .WithGetBody(BatchUri)
                               .WithXmlDoc(XmlDoc.Summary("Gets the batch base URI; ", XmlDoc.C("null"), " if unspecified."));
                var batchPath = Property(Modifier.Public | Modifier.Override, ctx.Type <string>(), "BatchPath")
                                .WithGetBody(BatchPath)
                                .WithXmlDoc(XmlDoc.Summary("Gets the batch base path; ", XmlDoc.C("null"), " if unspecified."));

                var resourceProperties = Resources.Select(resource => resource.GenerateProperty(ctx)).ToArray();

                var parameterizedCtor = Ctor(Modifier.Public, cls, BaseInitializer(initializerParam))(initializerParam)
                                        .WithBlockBody(resourceProperties.Zip(Resources).Select(pair => pair.First.Assign(New(ctx.Type(pair.Second.Typ))(This))).ToArray())
                                        .WithXmlDoc(
                    XmlDoc.Summary("Constructs a new service."),
                    XmlDoc.Param(initializerParam, "The service initializer."));

                cls = cls.AddMembers(version, discoveryVersion, parameterlessCtor, parameterizedCtor, features, nameProperty, baseUri, basePath, batchUri, batchPath);

                if (AuthScopes.Any())
                {
                    var scopeClass = Class(Modifier.Public, Typ.Manual(PackageName, "Scope"))
                                     .WithXmlDoc(XmlDoc.Summary($"Available OAuth 2.0 scopes for use with the {Title}."));
                    using (ctx.InClass(scopeClass))
                    {
                        foreach (var scope in AuthScopes)
                        {
                            var field = Field(Modifier.Public | Modifier.Static, ctx.Type <string>(), scope.Name)
                                        .WithInitializer(scope.Value)
                                        .WithXmlDoc(XmlDoc.Summary(scope.Description));
                            scopeClass = scopeClass.AddMembers(field);
                        }
                    }

                    var scopeConstantsClass = Class(Modifier.Public | Modifier.Static, Typ.Manual(PackageName, "ScopeConstants"))
                                              .WithXmlDoc(XmlDoc.Summary($"Available OAuth 2.0 scope constants for use with the {Title}."));
                    using (ctx.InClass(scopeConstantsClass))
                    {
                        foreach (var scope in AuthScopes)
                        {
                            var field = Field(Modifier.Public | Modifier.Const, ctx.Type <string>(), scope.Name)
                                        .WithInitializer(scope.Value)
                                        .WithXmlDoc(XmlDoc.Summary(scope.Description));
                            scopeConstantsClass = scopeConstantsClass.AddMembers(field);
                        }
                    }

                    cls = cls.AddMembers(scopeClass, scopeConstantsClass);
                }

                // TODO: Find an example of this...
                foreach (var method in Methods)
                {
                    cls = cls.AddMembers(method.GenerateDeclarations(ctx).ToArray());
                }

                cls = cls.AddMembers(resourceProperties);
            }
            return(cls);
        }
コード例 #11
0
        private IEnumerable <MemberDeclarationSyntax> GenerateUploadMembers(SourceFileContext ctx)
        {
            var uploadTyp = Typ.Nested(ctx.CurrentTyp, PascalCasedName + "MediaUpload");

            var baseTypArgument1 = BodyTyp ?? Typ.Of <string>();
            var baseTyp          = _restMethod.Response is object
                                   ?Typ.Generic(Typ.Of(typeof(ResumableUpload <,>)), baseTypArgument1, ResponseTyp)
                                       : Typ.Generic(Typ.Of(typeof(ResumableUpload <>)), baseTypArgument1);

            var uploadCls = Class(Modifier.Public, uploadTyp, ctx.Type(baseTyp))
                            .WithXmlDoc(XmlDoc.Summary($"{PascalCasedName} media upload which supports resumable upload."));

            var parameters         = CreateParameterList(uploadTyp);
            var requiredParameters = parameters
                                     .TakeWhile(p => p.IsRequired)
                                     .Select(p => (param: p, decl: Parameter(ctx.Type(p.Typ), p.CodeParameterName)))
                                     .ToList();

            var insertMethodParameters = new List <ParameterSyntax>();

            if (BodyTyp is object)
            {
                insertMethodParameters.Add(Parameter(ctx.Type(BodyTyp), "body"));
            }
            insertMethodParameters.AddRange(requiredParameters.Select(pair => pair.decl));
            var streamParam = Parameter(ctx.Type <Stream>(), "stream");

            var contentTypeParam = Parameter(ctx.Type <string>(), "contentType");

            insertMethodParameters.Add(streamParam);
            insertMethodParameters.Add(contentTypeParam);

            // This doc comment is common between the method and the constructor.
            var remarks = XmlDoc.Remarks("Considerations regarding ", streamParam, ":",
                                         XmlDoc.BulletListOfItemNodes(
                                             XmlDoc.Item("If ", streamParam, " is seekable, then the stream position will be reset to ", 0, " before reading commences. If ", streamParam, " is not seekable, then it will be read from its current position"),
                                             XmlDoc.Item("Caller is responsible for maintaining the ", streamParam, " open until the upload is completed"),
                                             XmlDoc.Item("Caller is responsible for closing the ", streamParam)));

            var methodDocComments = new List <DocumentationCommentTriviaSyntax>
            {
                XmlDoc.Summary(_restMethod.Description),
                remarks
            };

            if (BodyTyp is object)
            {
                methodDocComments.Add(XmlDoc.Param(Parameter(ctx.Type(BodyTyp), "body"), "The body of the request."));
            }

            methodDocComments.AddRange(requiredParameters.Select(pair => XmlDoc.Param(pair.decl, pair.param.Description)));
            methodDocComments.Add(XmlDoc.Param(streamParam, "The stream to upload. See remarks for further information."));
            methodDocComments.Add(XmlDoc.Param(contentTypeParam, "The content type of the stream to upload."));

            // We're taking it from the field in the parent type, but it becomes a parameter for the constructor...
            // So long as it appears as "service" we don't really mind.
            var serviceParam   = Parameter(ctx.Type <IClientService>(), "service");
            var ctorParameters = new List <ParameterSyntax> {
                serviceParam
            };

            ctorParameters.AddRange(insertMethodParameters);

            var insertMethod = Method(Modifier.Public | Modifier.Virtual, ctx.Type(uploadTyp), PascalCasedName)(insertMethodParameters.ToArray())
                               .WithBlockBody(Return(New(ctx.Type(uploadTyp))(ctorParameters)))
                               .WithXmlDoc(methodDocComments.ToArray());

            using (ctx.InClass(uploadTyp))
            {
                var baseInitializerArgs = new List <object>
                {
                    serviceParam,
                    ctx.Type <string>().Call(nameof(string.Format))("/{0}/{1}{2}", "upload", serviceParam.Access("BasePath"), _restMethod.Path),
                    _restMethod.HttpMethod,
                    streamParam,
                    contentTypeParam
                };
                var baseInitializer = BaseInitializer(baseInitializerArgs).WithAdditionalAnnotations(Annotations.LineBreakAnnotation);
                var assignments     = requiredParameters.Select(p => Field(0, ctx.Type(p.param.Typ), p.param.PropertyName).Assign(p.decl)).ToList();

                if (BodyTyp is object)
                {
                    // The Body property is in the base class.
                    var bodyProperty = Property(Modifier.Public, ctx.Type(BodyTyp), "Body");
                    assignments.Add(bodyProperty.Assign(Parameter(ctx.Type(BodyTyp), "body")));
                }

                // The parameters to the constructor are the same as for the method.
                var uploadCtor = Ctor(Modifier.Public, uploadCls, baseInitializer)(ctorParameters.ToArray())
                                 .WithBlockBody(assignments)
                                 .WithXmlDoc(XmlDoc.Summary($"Constructs a new {PascalCasedName} media upload instance."), remarks);

                uploadCls = uploadCls.AddMembers(Package.CreateParameterList(uploadTyp).SelectMany(p => p.GenerateDeclarations(ctx)).ToArray());
                uploadCls = uploadCls.AddMembers(parameters.SelectMany(p => p.GenerateDeclarations(ctx)).ToArray());
                uploadCls = uploadCls.AddMembers(uploadCtor);
            }

            yield return(insertMethod);

            yield return(uploadCls);
        }
コード例 #12
0
        private ClassDeclarationSyntax GenerateRequestType(SourceFileContext ctx)
        {
            var baseType = ctx.Type(Typ.Generic(Package.GenericBaseRequestTypDef, ResponseTyp));
            var cls      = Class(Modifier.Public, RequestTyp, baseType);

            if (_restMethod.Description is object)
            {
                cls = cls.WithXmlDoc(XmlDoc.Summary(_restMethod.Description));
            }

            using (ctx.InClass(RequestTyp))
            {
                // Service and optionally "body"
                var             serviceParam    = Parameter(ctx.Type <IClientService>(), "service");
                ParameterSyntax bodyParam       = null;
                var             extraParameters = new List <ParameterSyntax> {
                    serviceParam
                };

                var bodyDeclarations = new MemberDeclarationSyntax[0];
                if (BodyTyp is object)
                {
                    var bodyProperty = AutoProperty(Modifier.None, ctx.Type(BodyTyp), "Body", hasSetter: true)
                                       .WithXmlDoc(XmlDoc.Summary("Gets or sets the body of this request."));
                    var bodyMethod = Method(Modifier.Protected | Modifier.Override, ctx.Type <object>(), "GetBody")()
                                     .WithBody(Return(bodyProperty))
                                     .WithXmlDoc(XmlDoc.Summary("Returns the body of the request."));
                    bodyDeclarations = new MemberDeclarationSyntax[] { bodyProperty, bodyMethod };
                    bodyParam        = Parameter(ctx.Type(BodyTyp), "body");
                    extraParameters.Add(bodyParam);
                }

                var mediaDownloaderProperty = SupportsMediaDownload
                    ? AutoProperty(Modifier.Public, ctx.Type <IMediaDownloader>(), "MediaDownloader", hasSetter: true, setterIsPrivate: true)
                                              .WithXmlDoc(XmlDoc.Summary("Gets the media downloader."))
                    : null;

                var parameters         = CreateParameterList(RequestTyp);
                var requiredParameters = parameters
                                         .TakeWhile(p => p.IsRequired)
                                         .Select(p => (param: p, decl: Parameter(ctx.Type(p.Typ), p.CodeParameterName)))
                                         .ToList();

                var assignments = requiredParameters
                                  .Select(p => Field(0, ctx.Type(p.param.Typ), p.param.PropertyName).Assign(p.decl)).ToList();

                if (BodyTyp is object)
                {
                    var bodyProperty = (PropertyDeclarationSyntax)bodyDeclarations[0];
                    assignments.Add(bodyProperty.Assign(bodyParam));
                }

                if (SupportsMediaDownload)
                {
                    assignments.Add(mediaDownloaderProperty.Assign(New(ctx.Type <MediaDownloader>())(serviceParam)));
                }

                var allCtorParameters = extraParameters.Concat(requiredParameters.Select(p => p.decl)).ToArray();

                var ctor = Ctor(Modifier.Public, cls, BaseInitializer(serviceParam))(allCtorParameters)
                           .WithXmlDoc(XmlDoc.Summary($"Constructs a new {PascalCasedName} request."))
                           .WithBlockBody(assignments.Concat <object>(new[] { InvocationExpression(IdentifierName("InitParameters")) }).ToArray());

                var methodName = Property(Modifier.Public | Modifier.Override, ctx.Type <string>(), "MethodName")
                                 .WithGetBody(Name)
                                 .WithXmlDoc(XmlDoc.Summary("Gets the method name."));

                var httpMethod = Property(Modifier.Public | Modifier.Override, ctx.Type <string>(), "HttpMethod")
                                 .WithGetBody(_restMethod.HttpMethod)
                                 .WithXmlDoc(XmlDoc.Summary("Gets the HTTP method."));

                var restPath = Property(Modifier.Public | Modifier.Override, ctx.Type <string>(), "RestPath")
                               .WithGetBody(_restMethod.Path)
                               .WithXmlDoc(XmlDoc.Summary("Gets the REST path."));

                var initParameters = Method(Modifier.Protected | Modifier.Override, VoidType, "InitParameters")()
                                     .WithBlockBody(
                    BaseExpression().Call("InitParameters")(),
                    parameters.Select(p => p.GenerateInitializer(ctx)).ToArray())
                                     .WithXmlDoc(XmlDoc.Summary($"Initializes {PascalCasedName} parameter list."));

                // TODO: Media downloader members

                cls = cls.AddMembers(ctor);
                cls = cls.AddMembers(parameters.SelectMany(p => p.GenerateDeclarations(ctx)).ToArray());
                cls = cls.AddMembers(bodyDeclarations);
                cls = cls.AddMembers(methodName, httpMethod, restPath, initParameters);

                if (SupportsMediaDownload)
                {
                    cls = cls.AddMembers(mediaDownloaderProperty);
                    cls = AddMediaDownloadMethods(mediaDownloaderProperty, cls, ctx);
                }
            }
            return(cls);
        }