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); }
public ServiceDetails(ProtoCatalog catalog, string ns, ServiceDescriptor desc, ServiceConfig grpcServiceConfig) { Catalog = catalog; Namespace = ns; ProtoPackage = desc.File.Package; DocLines = desc.Declaration.DocLines().ToList(); SnippetsNamespace = $"{ns}.Snippets"; UnitTestsNamespace = $"{ns}.Tests"; // Must come early; used by `MethodDetails.Create()` MethodGrpcConfigsByName = grpcServiceConfig?.MethodConfig .SelectMany(conf => conf.Name.Select(name => (name, conf))) .Where(x => x.name.Service == desc.FullName) .ToImmutableDictionary(x => $"{x.name.Service}/{x.name.Method}", x => x.conf) ?? ImmutableDictionary <string, MethodConfig> .Empty; ServiceFullName = desc.FullName; ServiceName = desc.Name; DocumentationName = desc.Name; // TODO: There may be a more suitable name than this. ProtoTyp = Typ.Manual(ns, desc.Name); GrpcClientTyp = Typ.Nested(ProtoTyp, $"{desc.Name}Client"); SettingsTyp = Typ.Manual(ns, $"{desc.Name}Settings"); BuilderTyp = Typ.Manual(ns, $"{desc.Name}ClientBuilder"); ClientAbstractTyp = Typ.Manual(ns, $"{desc.Name}Client"); ClientImplTyp = Typ.Manual(ns, $"{desc.Name}ClientImpl"); DefaultHost = desc.GetExtension(ClientExtensions.DefaultHost) ?? ""; DefaultPort = 443; // Hardcoded; this is not specifiable by proto annotation. var oauthScopes = desc.GetExtension(ClientExtensions.OauthScopes); DefaultScopes = string.IsNullOrEmpty(oauthScopes) ? Enumerable.Empty <string>() : oauthScopes.Split(',', ' '); Methods = desc.Methods.Select(x => MethodDetails.Create(this, x)).ToList(); SnippetsTyp = Typ.Manual(SnippetsNamespace, $"Generated{desc.Name}ClientSnippets"); StandaloneSnippetsTyp = Typ.Manual(SnippetsNamespace, $"Generated{desc.Name}ClientStandaloneSnippets"); SnippetsClientName = $"{desc.Name.ToLowerCamelCase()}Client"; UnitTestsTyp = Typ.Manual(UnitTestsNamespace, $"Generated{desc.Name}ClientTest"); NonStandardLro = NonStandardLroDetails.ForService(desc); }
public ResourceClassBuilder(SourceFileContext ctx, ResourceDetails.Definition def) { _ctx = ctx; _def = def; ResourceNameTypeTyp = Typ.Nested(def.ResourceNameTyp, "ResourceNameType", isEnum: true); PatternDetails = _def.Patterns.Where(x => !x.IsWildcard).Select(x => new PatternDetails(ctx, def, x)).ToList(); }
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"; }
public EnumDeclarationSyntax GenerateDeclaration(SourceFileContext ctx) { var declaration = Enum(Modifier.Public, Typ.Nested(ctx.CurrentTyp, TypeName, isEnum: true)) (Members.Select(m => m.GenerateDeclaration(ctx)).ToArray()); if (Description is string description) { declaration = declaration.WithXmlDoc(XmlDoc.Summary(description)); } return(declaration); }
public ResourceModel(PackageModel package, ResourceModel parent, string name, RestResource discoveryResource) { Name = name; PropertyName = name.ToMemberName(); string className = name.ToClassName(package, parent?.Typ.Name) + "Resource"; Typ = parent is null?Typ.Manual(package.PackageName, className) : Typ.Nested(parent.Typ, className); Subresources = discoveryResource.Resources.ToReadOnlyList(pair => new ResourceModel(package, this, pair.Key, pair.Value)); Methods = discoveryResource.Methods.ToReadOnlyList(pair => new MethodModel(package, this, pair.Key, pair.Value)); }
public MethodModel(PackageModel package, ResourceModel resource, string name, RestMethod restMethod) { Package = package; Resource = resource; Name = name; PascalCasedName = name.ToClassName(package, resource.ClassName); ParentTyp = resource?.Typ ?? package.ServiceTyp; RequestTyp = Typ.Nested(ParentTyp, $"{PascalCasedName}Request"); BodyTyp = restMethod.Request is object?package.GetDataModelByReference(restMethod.Request.Ref__).GetTypForReference() : null; ResponseTyp = restMethod.Response is object?package.GetDataModelByReference(restMethod.Response.Ref__).GetTypForReference() : Typ.Of <string>(); _restMethod = restMethod; }
public ServiceDetails(ProtoCatalog catalog, string ns, ServiceDescriptor desc, ServiceConfig grpcServiceConfig, Service serviceConfig, ApiTransports transports) { Catalog = catalog; Namespace = ns; ProtoPackage = desc.File.Package; PackageVersion = ProtoPackage.Split('.').FirstOrDefault(part => ApiVersionPattern.IsMatch(part)); DocLines = desc.Declaration.DocLines().ToList(); SnippetsNamespace = $"{ns}.Snippets"; UnitTestsNamespace = $"{ns}.Tests"; // Must come early; used by `MethodDetails.Create()` MethodGrpcConfigsByName = grpcServiceConfig?.MethodConfig .SelectMany(conf => conf.Name.Select(name => (name, conf))) .Where(x => x.name.Service == desc.FullName) .ToImmutableDictionary(x => $"{x.name.Service}/{x.name.Method}", x => x.conf) ?? ImmutableDictionary <string, MethodConfig> .Empty; ServiceFullName = desc.FullName; ServiceName = desc.Name; DocumentationName = desc.Name; // TODO: There may be a more suitable name than this. ProtoTyp = Typ.Manual(ns, desc.Name); GrpcClientTyp = Typ.Nested(ProtoTyp, $"{desc.Name}Client"); SettingsTyp = Typ.Manual(ns, $"{desc.Name}Settings"); BuilderTyp = Typ.Manual(ns, $"{desc.Name}ClientBuilder"); ClientAbstractTyp = Typ.Manual(ns, $"{desc.Name}Client"); ClientImplTyp = Typ.Manual(ns, $"{desc.Name}ClientImpl"); DefaultHost = desc.GetExtension(ClientExtensions.DefaultHost) ?? ""; // We need to account for regional default endpoints like "us-east1-pubsub.googleapis.com" DefaultHostServiceName = DefaultHost .Split('.', StringSplitOptions.RemoveEmptyEntries).FirstOrDefault() ?.Split('-', StringSplitOptions.RemoveEmptyEntries).LastOrDefault(); DefaultPort = 443; // Hardcoded; this is not specifiable by proto annotation. var oauthScopes = desc.GetExtension(ClientExtensions.OauthScopes); DefaultScopes = string.IsNullOrEmpty(oauthScopes) ? Enumerable.Empty <string>() : oauthScopes.Split(',', ' '); Methods = desc.Methods.Select(x => MethodDetails.Create(this, x)).ToList(); ServiceSnippetsTyp = Typ.Manual(SnippetsNamespace, $"AllGenerated{desc.Name}ClientSnippets"); SnippetsTyp = Typ.Manual(SnippetsNamespace, $"Generated{desc.Name}ClientSnippets"); SnippetsClientName = $"{desc.Name.ToLowerCamelCase()}Client"; UnitTestsTyp = Typ.Manual(UnitTestsNamespace, $"Generated{desc.Name}ClientTest"); NonStandardLro = NonStandardLroDetails.ForService(desc); Mixins = serviceConfig?.Apis .Select(api => AvailableMixins.GetValueOrDefault(api.Name)) .Where(mixin => mixin is object) // Don't use mixins within the package that contains that mixin. .Where(mixin => mixin.GapicClientType.Namespace != ns) .ToList() ?? Enumerable.Empty <MixinDetails>(); Transports = transports; }
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 DataModel(PackageModel package, DataModel parent, string name, JsonSchema schema) { _schema = schema; Name = name; Id = schema.Id; Package = package; Parent = parent; // TODO: Move this logic into Naming somehow, but noting that we *don't* escape keywords here. <sigh> string className = schema.Id is object && IsArray ? name + "Items" : name; className = className.ToUpperCamelCase(upperAfterDigit: null); if (className == parent?.Typ.Name) { className += "Schema"; } Typ = parent is null?Typ.Manual(Package.PackageName + ".Data", className) : Typ.Nested(parent.Typ, className); // We may get a JsonSchema for an array as a nested model. Just use the properties from schema.Items for simplicity. Properties = GetProperties(schema).ToReadOnlyList(pair => new DataPropertyModel(this, pair.Key, pair.Value)); }
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); }