ProtobufCodeGenParser.swift 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. /*
  2. * Copyright 2024, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import Foundation
  17. import SwiftProtobuf
  18. import SwiftProtobufPluginLibrary
  19. import struct GRPCCodeGen.CodeGenerationRequest
  20. /// Parses a ``FileDescriptor`` object into a ``CodeGenerationRequest`` object.
  21. internal struct ProtobufCodeGenParser {
  22. internal init() {}
  23. internal func parse(input: FileDescriptor) throws -> CodeGenerationRequest {
  24. var header = input.header
  25. // Ensuring there is a blank line after the header.
  26. if !header.isEmpty && !header.hasSuffix("\n\n") {
  27. header.append("\n")
  28. }
  29. let leadingTrivia = """
  30. // DO NOT EDIT.
  31. // swift-format-ignore-file
  32. //
  33. // Generated by the gRPC Swift generator plugin for the protocol buffer compiler.
  34. // Source: \(input.name)
  35. //
  36. // For information on using the generated types, please see the documentation:
  37. // https://github.com/grpc/grpc-swift
  38. """
  39. var dependencies = input.dependencies.map {
  40. CodeGenerationRequest.Dependency(module: $0.name)
  41. }
  42. dependencies.append(CodeGenerationRequest.Dependency(module: "GRPCProtobuf"))
  43. let lookupSerializer: (String) -> String = { messageType in
  44. "ProtobufSerializer<\(messageType)>()"
  45. }
  46. let lookupDeserializer: (String) -> String = { messageType in
  47. "ProtobufDeserializer<\(messageType)>()"
  48. }
  49. let services = input.services.map {
  50. CodeGenerationRequest.ServiceDescriptor(descriptor: $0, package: input.package)
  51. }
  52. return CodeGenerationRequest(
  53. fileName: input.name,
  54. leadingTrivia: header + leadingTrivia,
  55. dependencies: dependencies,
  56. services: services,
  57. lookupSerializer: lookupSerializer,
  58. lookupDeserializer: lookupDeserializer
  59. )
  60. }
  61. }
  62. extension CodeGenerationRequest.ServiceDescriptor {
  63. fileprivate init(descriptor: ServiceDescriptor, package: String) {
  64. let methods = descriptor.methods.map {
  65. CodeGenerationRequest.ServiceDescriptor.MethodDescriptor(descriptor: $0)
  66. }
  67. let name = CodeGenerationRequest.Name(
  68. base: descriptor.name,
  69. generatedUpperCase: NamingUtils.toUpperCamelCase(descriptor.name),
  70. generatedLowerCase: NamingUtils.toLowerCamelCase(descriptor.name)
  71. )
  72. let namespace = CodeGenerationRequest.Name(
  73. base: package,
  74. generatedUpperCase: NamingUtils.toUpperCamelCase(package),
  75. generatedLowerCase: NamingUtils.toLowerCamelCase(package)
  76. )
  77. let documentation = descriptor.protoSourceComments()
  78. self.init(documentation: documentation, name: name, namespace: namespace, methods: methods)
  79. }
  80. }
  81. extension CodeGenerationRequest.ServiceDescriptor.MethodDescriptor {
  82. fileprivate init(descriptor: MethodDescriptor) {
  83. let name = CodeGenerationRequest.Name(
  84. base: descriptor.name,
  85. generatedUpperCase: NamingUtils.toUpperCamelCase(descriptor.name),
  86. generatedLowerCase: NamingUtils.toLowerCamelCase(descriptor.name)
  87. )
  88. let documentation = descriptor.protoSourceComments()
  89. self.init(
  90. documentation: documentation,
  91. name: name,
  92. isInputStreaming: descriptor.clientStreaming,
  93. isOutputStreaming: descriptor.serverStreaming,
  94. inputType: descriptor.inputType.name,
  95. outputType: descriptor.outputType.name
  96. )
  97. }
  98. }
  99. extension FileDescriptor {
  100. fileprivate var header: String {
  101. var header = String()
  102. // Field number used to collect the syntax field which is usually the first
  103. // declaration in a.proto file.
  104. // See more here:
  105. // https://github.com/apple/swift-protobuf/blob/main/Protos/SwiftProtobuf/google/protobuf/descriptor.proto
  106. let syntaxPath = IndexPath(index: 12)
  107. if let syntaxLocation = self.sourceCodeInfoLocation(path: syntaxPath) {
  108. header = syntaxLocation.asSourceComment(
  109. commentPrefix: "///",
  110. leadingDetachedPrefix: "//"
  111. )
  112. }
  113. return header
  114. }
  115. }