Ejemplo n.º 1
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);
        }
Ejemplo n.º 2
0
            public StandardLro(ServiceDetails svc, MethodDescriptor desc) : base(svc, desc)
            {
                OperationInfo lroData = desc.GetExtension(OperationsExtensions.OperationInfo);

                if (lroData is null)
                {
                    throw new InvalidOperationException("LRO method must contain a `google.api.operation` option.");
                }
                ApiCallTyp = Typ.Generic(typeof(ApiCall <,>), RequestTyp, Typ.Of <Operation>());
                if (string.IsNullOrEmpty(lroData.ResponseType) || string.IsNullOrEmpty(lroData.MetadataType))
                {
                    throw new InvalidOperationException($"Both response-type and metadata-type must be present for method: '{desc.FullName}'.");
                }
                var responseTypeMsg = svc.Catalog.GetMessageByName(lroData.ResponseType);
                var metadataTypeMsg = svc.Catalog.GetMessageByName(lroData.MetadataType);

                if (responseTypeMsg is null || metadataTypeMsg is null)
                {
                    throw new InvalidOperationException(
                              $"Response-type and Metadata-type must both exist in method '{desc.FullName}': '{lroData.ResponseType}', '{lroData.MetadataType}'.");
                }
                OperationResponseTyp = ProtoTyp.Of(responseTypeMsg);
                OperationMetadataTyp = ProtoTyp.Of(metadataTypeMsg);
                SyncReturnTyp        = Typ.Generic(typeof(Operation <,>), OperationResponseTyp, OperationMetadataTyp);
            }
        private static MethodDeclarationSyntax GenerateMethod(SourceFileContext ctx, ServiceDetails service)
        {
            var name = $"Add{service.ClientAbstractTyp.Name}";
            var serviceCollection = ctx.Type <IServiceCollection>();
            var services          = Parameter(serviceCollection, "services")
                                    .WithModifiers(SyntaxTokenList.Create(Token(SyntaxKind.ThisKeyword).WithTrailingSpace()));
            var actionType = ctx.Type(Typ.Generic(typeof(Action <>), service.BuilderTyp));
            var action     = Parameter(actionType, "action", @default: Null);

            var builderType = ctx.Type(service.BuilderTyp);
            var builder     = Local(builderType, "builder");

            var provider = Parameter(ctx.Type <IServiceProvider>(), "provider");
            var lambda   = Lambda(provider)(
                builder.WithInitializer(New(builderType)()),
                action.Call("Invoke", true)(builder),
                Return(builder.Call("Build")(provider))
                );

            return(Method(Public | Static, serviceCollection, name)(services, action)
                   .WithBody(services.Call("AddSingleton")(lambda))
                   .WithXmlDoc(
                       XmlDoc.Summary("Adds a singleton ", ctx.Type(service.ClientAbstractTyp), " to ", services, "."),
                       XmlDoc.Param(services, "The service collection to add the client to. The services are used to configure the client when requested."),
                       XmlDoc.Param(action, "An optional action to invoke on the client builder. This is invoked before services from ", services, " are used.")
                       ));
        }
Ejemplo n.º 4
0
        public PackageModel(RestDescription discoveryDoc)
        {
            _discoveryDoc = discoveryDoc;
            ApiName       = discoveryDoc.Name;

            // Note that spaces are removed first, because the Python code doesn't Pascal-case them. For example,
            // the "Cloud Memorystore for Memcached" API has a package name of "CloudMemorystoreforMemcached".
            // It's awful, but that's the way it works...
            ClassName        = (discoveryDoc.CanonicalName ?? discoveryDoc.Name).Replace(" ", "").ToMemberName();
            ServiceClassName = $"{ClassName}Service";
            ApiVersion       = discoveryDoc.Version;
            VersionNoDots    = discoveryDoc.Version.Replace('.', '_');
            PackageName      = $"Google.Apis.{ClassName}.{VersionNoDots}";
            DataModels       = discoveryDoc.Schemas.ToReadOnlyList(pair => new DataModel(this, parent: null, name: pair.Key, schema: pair.Value));

            // Populate the data model dictionary early, as methods and resources refer to the data model types.
            foreach (var dm in DataModels)
            {
                _dataModels[dm.Id] = dm;
            }
            Resources   = discoveryDoc.Resources.ToReadOnlyList(pair => new ResourceModel(this, parent: null, pair.Key, pair.Value));
            ApiFeatures = discoveryDoc.Features.ToReadOnlyList();
            // TODO: Ordering?
            AuthScopes = (discoveryDoc.Auth?.Oauth2?.Scopes).ToReadOnlyList(pair => new AuthScope(pair.Key, pair.Value.Description));
            ServiceTyp = Typ.Manual(PackageName, ServiceClassName);
            GenericBaseRequestTypDef = Typ.Manual(PackageName, $"{ClassName}BaseServiceRequest");
            BaseRequestTyp           = Typ.Generic(GenericBaseRequestTypDef, Typ.GenericParam("TResponse"));
            BaseUri   = discoveryDoc.RootUrl + discoveryDoc.ServicePath;
            BasePath  = discoveryDoc.ServicePath;
            BatchUri  = discoveryDoc.RootUrl + discoveryDoc.BatchPath;
            BatchPath = discoveryDoc.BatchPath;
            Title     = discoveryDoc.Title;
            Methods   = discoveryDoc.Methods.ToReadOnlyList(pair => new MethodModel(this, null, pair.Key, pair.Value));
        }
Ejemplo n.º 5
0
 public ServerStreaming(ServiceDetails svc, MethodDescriptor desc) : base(svc, desc)
 {
     ApiCallTyp         = Typ.Generic(typeof(ApiServerStreamingCall <,>), RequestTyp, ResponseTyp);
     AbstractStreamTyp  = Typ.Nested(svc.ClientAbstractTyp, $"{SyncMethodName}Stream");
     ImplStreamTyp      = Typ.Nested(svc.ClientImplTyp, $"{SyncMethodName}StreamImpl");
     AsyncEnumeratorTyp = Typ.Generic(typeof(AsyncResponseStream <>), ResponseTyp);
 }
Ejemplo n.º 6
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);
                }
            }
        }
Ejemplo n.º 7
0
        public ClassDeclarationSyntax GenerateBaseRequestClass(SourceFileContext ctx)
        {
            var cls = Class(
                Modifier.Public,
                Typ.Generic(Typ.Manual(PackageName, $"{ClassName}BaseServiceRequest"), Typ.GenericParam("TResponse")),
                ctx.Type(Typ.Generic(typeof(ClientServiceRequest <>), Typ.GenericParam("TResponse"))))
                      .WithXmlDoc(XmlDoc.Summary($"A base abstract class for {ClassName} requests."));

            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."));

            cls = cls.AddMembers(ctor);

            var parameters = _discoveryDoc.Parameters.Select(p => new ParameterModel(p.Key, p.Value))
                             .OrderBy(p => p.PropertyName)
                             .ToList();

            cls = cls.AddMembers(parameters.Select(p => p.GenerateProperty(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);
        }
 public ClientStreaming(ServiceDetails svc, MethodDescriptor desc) : base(svc, desc)
 {
     ApiCallTyp            = Typ.Generic(typeof(ApiClientStreamingCall <,>), RequestTyp, ResponseTyp);
     AbstractStreamTyp     = Typ.Nested(svc.ClientAbstractTyp, $"{SyncMethodName}Stream");
     ImplStreamTyp         = Typ.Nested(svc.ClientImplTyp, $"{SyncMethodName}StreamImpl");
     StreamingSettingsName = $"{desc.Name}StreamingSettings";
     ModifyStreamingCallSettingsMethodName = $"Modify_{RequestTyp.Name}CallSettings";
     ModifyStreamingRequestMethodName      = $"Modify_{RequestTyp.Name}Request";
 }
Ejemplo n.º 9
0
 public Paginated(ServiceDetails svc, MethodDescriptor desc,
                  FieldDescriptor responseResourceField, int pageSizeFieldNumber, int pageTokenFieldNumber) : base(svc, desc)
 {
     ResourceTyp          = ProtoTyp.Of(responseResourceField, forceRepeated: false);
     ApiCallTyp           = Typ.Generic(typeof(ApiCall <,>), RequestTyp, ResponseTyp);
     SyncReturnTyp        = Typ.Generic(typeof(PagedEnumerable <,>), ResponseTyp, ResourceTyp);
     AsyncReturnTyp       = Typ.Generic(typeof(PagedAsyncEnumerable <,>), ResponseTyp, ResourceTyp);
     SyncGrpcType         = Typ.Generic(typeof(GrpcPagedEnumerable <, ,>), RequestTyp, ResponseTyp, ResourceTyp);
     AsyncGrpcType        = Typ.Generic(typeof(GrpcPagedAsyncEnumerable <, ,>), RequestTyp, ResponseTyp, ResourceTyp);
     ResourcesFieldName   = responseResourceField.CSharpPropertyName();
     PageSizeFieldNumber  = pageSizeFieldNumber;
     PageTokenFieldNumber = pageTokenFieldNumber;
 }
Ejemplo n.º 10
0
            public NonStandardLro(ServiceDetails svc, MethodDescriptor desc) : base(svc, desc)
            {
                OperationService = desc.GetExtension(ExtendedOperationsExtensions.OperationService);
                if (string.IsNullOrEmpty(OperationService))
                {
                    throw new InvalidOperationException($"{desc.FullName} is not a non-standard LRO; it does not have an operation_service option.");
                }
                var service = svc.Catalog.GetServiceByName(OperationService);

                OperationServiceDetails = ServiceDetails.NonStandardLroDetails.ForService(service);
                SyncReturnTyp           = Typ.Generic(typeof(Operation <,>), OperationResponseTyp, OperationMetadataTyp);
                ApiCallTyp = Typ.Generic(typeof(ApiCall <,>), RequestTyp, ResponseTyp);
            }
Ejemplo n.º 11
0
        /// <summary>
        /// Determines how code referring to this data model should be refer to it; this takes
        /// into account whether it's a placeholder, an array etc.
        /// </summary>
        internal Typ GetTypForReference()
        {
            var ret = IsPlaceholder ? Typ.Of <object>() : Typ;

            if (IsArray)
            {
                ret = Typ.Generic(typeof(IList <>), ret);
            }
            if (_schema.AdditionalProperties is object)
            {
                ret = SchemaTypes.GetTypFromAdditionalProperties(Package, _schema.AdditionalProperties, Name, ret, inParameter: false);
            }
            return(ret);
        }
Ejemplo n.º 12
0
 public Paginated(ServiceDetails svc, MethodDescriptor desc,
                  FieldDescriptor responseResourceField, int pageSizeFieldNumber, int pageTokenFieldNumber) : base(svc, desc)
 {
     ResourceTyp = ProtoTyp.Of(responseResourceField, forceRepeated: false);
     // For map fields, ResourceTyp is a constructed KeyValuePair<,> type: we need the open type in a cref.
     ResourceTypForCref = responseResourceField.IsMap
         ? Typ.Generic(typeof(KeyValuePair <,>), Typ.GenericParam("TKey"), Typ.GenericParam("TValue"))
         : ResourceTyp;
     ApiCallTyp           = Typ.Generic(typeof(ApiCall <,>), RequestTyp, ResponseTyp);
     SyncReturnTyp        = Typ.Generic(typeof(PagedEnumerable <,>), ResponseTyp, ResourceTyp);
     AsyncReturnTyp       = Typ.Generic(typeof(PagedAsyncEnumerable <,>), ResponseTyp, ResourceTyp);
     SyncGrpcType         = Typ.Generic(typeof(GrpcPagedEnumerable <, ,>), RequestTyp, ResponseTyp, ResourceTyp);
     AsyncGrpcType        = Typ.Generic(typeof(GrpcPagedAsyncEnumerable <, ,>), RequestTyp, ResponseTyp, ResourceTyp);
     ResourcesFieldName   = responseResourceField.CSharpPropertyName();
     PageSizeFieldNumber  = pageSizeFieldNumber;
     PageTokenFieldNumber = pageTokenFieldNumber;
 }
Ejemplo n.º 13
0
                    internal static IEnumerable <ResourceName> Create(Signature signature)
                    {
                        var ctx    = signature.Ctx;
                        var fields = signature._sig.Fields;

                        if (!fields.Any(f => f.FieldResources is object))
                        {
                            return(Enumerable.Empty <ResourceName>());
                        }
                        if (fields.Aggregate(1, (acc, f) => acc * (f.FieldResources?.Count ?? 1)) > 32)
                        {
                            throw new InvalidOperationException($"Cannot generate >32 overloads for method signature: '{signature._def.MethodDetails.SyncMethodName}'");
                        }
                        var allOverloads = fields.Aggregate(ImmutableList.Create(ImmutableList <ParameterInfo> .Empty), (overloads, f) =>
                        {
                            IEnumerable <ParameterInfo> paramInfos;
                            if (f.FieldResources is null)
                            {
                                var parameter = Parameter(ctx.Type(f.Typ), f.ParameterName);
                                var xmlDoc    = XmlDoc.ParamPreFormatted(parameter, f.DocLines);
                                paramInfos    = new[] { new ParameterInfo(f.Descs, parameter, signature.InitExpr(f, parameter), null, xmlDoc) };
                            }
                            else
                            {
                                paramInfos = f.FieldResources.Where(resDetails => resDetails.ContainsWildcard != false).Select(resDetails =>
                                {
                                    var typ       = f.IsRepeated ? Typ.Generic(typeof(IEnumerable <>), resDetails.ResourceDefinition.ResourceNameTyp) : resDetails.ResourceDefinition.ResourceNameTyp;
                                    var parameter = Parameter(ctx.Type(typ), f.ParameterName);
                                    var xmlDoc    = XmlDoc.ParamPreFormatted(parameter, f.DocLines);
                                    return(new ParameterInfo(f.Descs, parameter, signature.InitExpr(f, parameter, resDetails), resDetails.ResourcePropertyName, xmlDoc));
                                }).ToList();
                            }
                            return(overloads.SelectMany(overload => paramInfos.Select(paramInfo => overload.Add(paramInfo))).ToImmutableList());
                        });

                        return(allOverloads.Select(parameters => new ResourceName(signature, parameters)));
                    }
Ejemplo n.º 14
0
 public Normal(ServiceDetails svc, MethodDescriptor desc) : base(svc, desc)
 {
     ApiCallTyp    = Typ.Generic(typeof(ApiCall <,>), RequestTyp, ResponseTyp);
     SyncReturnTyp = ResponseTyp.FullName == typeof(Empty).FullName ? Typ.Void : ResponseTyp;
 }
Ejemplo n.º 15
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);
        }
Ejemplo n.º 16
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);
        }
            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);
            }
Ejemplo n.º 18
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);
            }
        }
Ejemplo n.º 19
0
 private object InitExpr(MethodDetails.Signature.Field field, ParameterSyntax param, ResourceDetails.Field treatAsResource = null)
 {
     // Type                  | Single optional | Single required | Repeated optional | Repeated required
     // ----------------------|-----------------|-----------------|-------------------|------------------
     // Primitive & enum      | nothing to do   | nothing to do   | null -> empty     | check not null
     // string                | null -> ""      | check not empty | null -> empty     | check not null
     // bytes                 | null -> byte[0] | check not null  | null -> empty     | check not null
     // message               | null ok         | check not null  | null -> empty     | check not null
     // resourcename (string) | null -> ""      | check not null  | null -> empty     | check not null
     // resourcenames use the generated partial resource-name-type properties, which perform the string conversion.
     if (field.IsMap)
     {
         return(CollectionInitializer(field.IsRequired ?
                                      Ctx.Type(typeof(GaxPreconditions)).Call(nameof(GaxPreconditions.CheckNotNull))(param, Nameof(param)) :
                                      param.NullCoalesce(New(Ctx.Type(Typ.Generic(typeof(Dictionary <,>),
                                                                                  field.Typ.GenericArgTyps.First(), field.Typ.GenericArgTyps.ElementAt(1))))())));
     }
     else if (field.IsRepeated)
     {
         if (treatAsResource is object)
         {
             return(CollectionInitializer(field.IsRequired ?
                                          Ctx.Type(typeof(GaxPreconditions)).Call(nameof(GaxPreconditions.CheckNotNull))(param, Nameof(param)) :
                                          param.NullCoalesce(Ctx.Type(typeof(Enumerable)).Call(
                                                                 nameof(Enumerable.Empty), Ctx.Type(treatAsResource.ResourceDefinition.ResourceNameTyp))())));
         }
         else
         {
             return(CollectionInitializer(field.IsRequired ?
                                          Ctx.Type(typeof(GaxPreconditions)).Call(nameof(GaxPreconditions.CheckNotNull))(param, Nameof(param)) :
                                          param.NullCoalesce(Ctx.Type(typeof(Enumerable)).Call(nameof(Enumerable.Empty), Ctx.Type(field.Typ.GenericArgTyps.First()))())));
         }
     }
     else
     {
         if (treatAsResource is object)
         {
             return(field.IsRequired ?
                    Ctx.Type(typeof(GaxPreconditions)).Call(nameof(GaxPreconditions.CheckNotNull))(param, Nameof(param)) :
                    (object)param);
         }
         else if (field.Typ.IsPrimitive || field.Typ.IsEnum)
         {
             return(param);
         }
         else if (field.Typ.FullName == typeof(string).FullName)
         {
             return(field.IsRequired ?
                    Ctx.Type(typeof(GaxPreconditions)).Call(
                        field.IsWrapperType ? nameof(GaxPreconditions.CheckNotNull) : nameof(GaxPreconditions.CheckNotNullOrEmpty))(
                        param, Nameof(param)) :
                    field.IsWrapperType?param : (object)param.NullCoalesce(""));
         }
         else if (field.Typ.FullName == typeof(ByteString).FullName)
         {
             return(field.IsRequired ?
                    Ctx.Type(typeof(GaxPreconditions)).Call(nameof(GaxPreconditions.CheckNotNull))(param, Nameof(param)) :
                    field.IsWrapperType?param : (object)param.NullCoalesce(Ctx.Type <ByteString>().Access(nameof(ByteString.Empty))));
         }
         else if (field.IsWrapperType)
         {
             return(field.IsRequired ?
                    param.NullCoalesce(Throw(New(Ctx.Type <ArgumentNullException>())(Nameof(param)))) :
                    (object)param);
         }
         else
         {
             return(field.IsRequired ?
                    Ctx.Type(typeof(GaxPreconditions)).Call(nameof(GaxPreconditions.CheckNotNull))(param, Nameof(param)) :
                    (object)param);
         }
     }
 }