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); } }
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); } }
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); } } }
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); }
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); }
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); }
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); }
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); }
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); } }
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); }
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); }
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); }