CodeGenerator.swift 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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. @available(*, deprecated, renamed: "CodeGenerator")
  17. @available(gRPCSwift 2.0, *)
  18. public typealias SourceGenerator = CodeGenerator
  19. /// Generates ``SourceFile`` objects containing generated code for the RPCs represented
  20. /// in a ``CodeGenerationRequest`` object.
  21. @available(gRPCSwift 2.0, *)
  22. public struct CodeGenerator: Sendable {
  23. /// The options regarding the access level, indentation for the generated code
  24. /// and whether to generate server and client code.
  25. public var config: Config
  26. public init(config: Config) {
  27. self.config = config
  28. }
  29. /// User options for the CodeGeneration.
  30. public struct Config: Sendable {
  31. /// The access level the generated code will have.
  32. public var accessLevel: AccessLevel
  33. /// Whether imports have explicit access levels.
  34. public var accessLevelOnImports: Bool
  35. /// The indentation of the generated code as the number of spaces.
  36. public var indentation: Int
  37. /// Whether or not client code should be generated.
  38. public var client: Bool
  39. /// Whether or not server code should be generated.
  40. public var server: Bool
  41. /// The name of the core gRPC module.
  42. @available(gRPCSwift 2.1, *)
  43. public var grpcCoreModuleName: String
  44. /// The availability annotations to use on the generated code.
  45. @available(gRPCSwift 2.2, *)
  46. public var availability: AvailabilityAnnotations = .default
  47. /// Creates a new configuration.
  48. ///
  49. /// - Parameters:
  50. /// - accessLevel: The access level the generated code will have.
  51. /// - accessLevelOnImports: Whether imports have explicit access levels.
  52. /// - client: Whether or not client code should be generated.
  53. /// - server: Whether or not server code should be generated.
  54. /// - indentation: The indentation of the generated code as the number of spaces.
  55. public init(
  56. accessLevel: AccessLevel,
  57. accessLevelOnImports: Bool,
  58. client: Bool,
  59. server: Bool,
  60. indentation: Int = 4
  61. ) {
  62. self.accessLevel = accessLevel
  63. self.accessLevelOnImports = accessLevelOnImports
  64. self.indentation = indentation
  65. self.client = client
  66. self.server = server
  67. self.grpcCoreModuleName = "GRPCCore"
  68. }
  69. /// The possible access levels for the generated code.
  70. public struct AccessLevel: Sendable, Hashable {
  71. package var level: Level
  72. package enum Level {
  73. case `internal`
  74. case `public`
  75. case `package`
  76. }
  77. /// The generated code will have `internal` access level.
  78. public static var `internal`: Self { Self(level: .`internal`) }
  79. /// The generated code will have `public` access level.
  80. public static var `public`: Self { Self(level: .`public`) }
  81. /// The generated code will have `package` access level.
  82. public static var `package`: Self { Self(level: .`package`) }
  83. }
  84. // The availability that generated code is annotated with.
  85. @available(gRPCSwift 2.2, *)
  86. public struct AvailabilityAnnotations: Sendable, Hashable {
  87. public struct Platform: Sendable, Hashable {
  88. /// The name of the OS, e.g. 'macOS'.
  89. public var os: String
  90. /// The version of the OS, e.g. '15.0'.
  91. public var version: String
  92. public init(os: String, version: String) {
  93. self.os = os
  94. self.version = version
  95. }
  96. }
  97. fileprivate enum Wrapped: Sendable, Hashable {
  98. case macOS15Aligned
  99. case custom([Platform])
  100. }
  101. fileprivate var wrapped: Wrapped
  102. private init(_ wrapped: Wrapped) {
  103. self.wrapped = wrapped
  104. }
  105. /// Use the default availability.
  106. ///
  107. /// The default platform availability is:
  108. /// - macOS 15.0
  109. /// - iOS 18.0
  110. /// - tvOS 18.0
  111. /// - watchOS 11.0
  112. /// - visionOS 2.0
  113. public static var `default`: Self {
  114. Self(.macOS15Aligned)
  115. }
  116. /// Use a custom set of availability attributes.
  117. /// - Parameter platforms: Availability requirements.
  118. public static func custom(_ platforms: [Platform]) -> Self {
  119. Self(.custom(platforms))
  120. }
  121. }
  122. }
  123. /// Transforms a ``CodeGenerationRequest`` object into a ``SourceFile`` object containing
  124. /// the generated code.
  125. public func generate(
  126. _ request: CodeGenerationRequest
  127. ) throws -> SourceFile {
  128. let translator = IDLToStructuredSwiftTranslator()
  129. let textRenderer = TextBasedRenderer(indentation: self.config.indentation)
  130. let structuredSwiftRepresentation = try translator.translate(
  131. codeGenerationRequest: request,
  132. accessLevel: self.config.accessLevel,
  133. accessLevelOnImports: self.config.accessLevelOnImports,
  134. client: self.config.client,
  135. server: self.config.server,
  136. grpcCoreModuleName: self.config.grpcCoreModuleName,
  137. availability: AvailabilityDescription(self.config.availability)
  138. )
  139. let sourceFile = try textRenderer.render(structured: structuredSwiftRepresentation)
  140. return sourceFile
  141. }
  142. }
  143. @available(gRPCSwift 2.0, *)
  144. extension AvailabilityDescription {
  145. init(_ availability: CodeGenerator.Config.AvailabilityAnnotations) throws {
  146. switch availability.wrapped {
  147. case .macOS15Aligned:
  148. self = .macOS15Aligned
  149. case .custom(let platforms):
  150. self.osVersions = platforms.map {
  151. .init(os: .init(name: $0.os), version: $0.version)
  152. }
  153. }
  154. }
  155. }