Options.swift 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /*
  2. * Copyright 2017, 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 SwiftProtobufPluginLibrary
  17. enum GenerationError: Error, CustomStringConvertible {
  18. /// Raised when parsing the parameter string and found an unknown key
  19. case unknownParameter(name: String)
  20. /// Raised when a parameter was giving an invalid value
  21. case invalidParameterValue(name: String, value: String)
  22. /// Raised to wrap another error but provide a context message.
  23. case wrappedError(message: String, error: any Error)
  24. var description: String {
  25. switch self {
  26. case let .unknownParameter(name):
  27. return "Unknown generation parameter '\(name)'"
  28. case let .invalidParameterValue(name, value):
  29. return "Unknown value for generation parameter '\(name)': '\(value)'"
  30. case let .wrappedError(message, error):
  31. return "\(message): \(error)"
  32. }
  33. }
  34. }
  35. enum FileNaming: String {
  36. case fullPath = "FullPath"
  37. case pathToUnderscores = "PathToUnderscores"
  38. case dropPath = "DropPath"
  39. }
  40. struct GeneratorOptions {
  41. enum Visibility: String {
  42. case `internal` = "Internal"
  43. case `public` = "Public"
  44. case `package` = "Package"
  45. var sourceSnippet: String {
  46. switch self {
  47. case .internal:
  48. return "internal"
  49. case .public:
  50. return "public"
  51. case .package:
  52. return "package"
  53. }
  54. }
  55. }
  56. private(set) var visibility = Visibility.internal
  57. private(set) var generateServer = true
  58. private(set) var generateClient = true
  59. private(set) var protoToModuleMappings = ProtoFileToModuleMappings()
  60. private(set) var fileNaming = FileNaming.fullPath
  61. private(set) var extraModuleImports: [String] = []
  62. private(set) var gRPCModuleName = "GRPC"
  63. private(set) var swiftProtobufModuleName = "SwiftProtobuf"
  64. private(set) var generateReflectionData = false
  65. private(set) var useAccessLevelOnImports = false
  66. init(parameter: any CodeGeneratorParameter) throws {
  67. try self.init(pairs: parameter.parsedPairs)
  68. }
  69. init(pairs: [(key: String, value: String)]) throws {
  70. for pair in pairs {
  71. switch pair.key {
  72. case "Visibility":
  73. if let value = Visibility(rawValue: pair.value) {
  74. self.visibility = value
  75. } else {
  76. throw GenerationError.invalidParameterValue(name: pair.key, value: pair.value)
  77. }
  78. case "Server":
  79. if let value = Bool(pair.value.lowercased()) {
  80. self.generateServer = value
  81. } else {
  82. throw GenerationError.invalidParameterValue(name: pair.key, value: pair.value)
  83. }
  84. case "Client":
  85. if let value = Bool(pair.value.lowercased()) {
  86. self.generateClient = value
  87. } else {
  88. throw GenerationError.invalidParameterValue(name: pair.key, value: pair.value)
  89. }
  90. case "ProtoPathModuleMappings":
  91. if !pair.value.isEmpty {
  92. do {
  93. self.protoToModuleMappings = try ProtoFileToModuleMappings(path: pair.value)
  94. } catch let e {
  95. throw GenerationError.wrappedError(
  96. message: "Parameter 'ProtoPathModuleMappings=\(pair.value)'",
  97. error: e
  98. )
  99. }
  100. }
  101. case "FileNaming":
  102. if let value = FileNaming(rawValue: pair.value) {
  103. self.fileNaming = value
  104. } else {
  105. throw GenerationError.invalidParameterValue(name: pair.key, value: pair.value)
  106. }
  107. case "ExtraModuleImports":
  108. if !pair.value.isEmpty {
  109. self.extraModuleImports.append(pair.value)
  110. } else {
  111. throw GenerationError.invalidParameterValue(name: pair.key, value: pair.value)
  112. }
  113. case "GRPCModuleName":
  114. if !pair.value.isEmpty {
  115. self.gRPCModuleName = pair.value
  116. } else {
  117. throw GenerationError.invalidParameterValue(name: pair.key, value: pair.value)
  118. }
  119. case "SwiftProtobufModuleName":
  120. if !pair.value.isEmpty {
  121. self.swiftProtobufModuleName = pair.value
  122. } else {
  123. throw GenerationError.invalidParameterValue(name: pair.key, value: pair.value)
  124. }
  125. case "ReflectionData":
  126. if let value = Bool(pair.value.lowercased()) {
  127. self.generateReflectionData = value
  128. } else {
  129. throw GenerationError.invalidParameterValue(name: pair.key, value: pair.value)
  130. }
  131. case "UseAccessLevelOnImports":
  132. if let value = Bool(pair.value.lowercased()) {
  133. self.useAccessLevelOnImports = value
  134. } else {
  135. throw GenerationError.invalidParameterValue(name: pair.key, value: pair.value)
  136. }
  137. default:
  138. throw GenerationError.unknownParameter(name: pair.key)
  139. }
  140. }
  141. }
  142. static func parseParameter(string: String?) -> [(key: String, value: String)] {
  143. guard let string = string, !string.isEmpty else {
  144. return []
  145. }
  146. let parts = string.split(separator: ",")
  147. // Partitions the string into the section before the = and after the =
  148. let result = parts.map { string -> (key: String, value: String) in
  149. // Finds the equal sign and exits early if none
  150. guard let index = string.firstIndex(of: "=") else {
  151. return (String(string), "")
  152. }
  153. // Creates key/value pair and trims whitespace
  154. let key = string[..<index]
  155. .trimmingWhitespaceAndNewlines()
  156. let value = string[string.index(after: index)...]
  157. .trimmingWhitespaceAndNewlines()
  158. return (key: key, value: value)
  159. }
  160. return result
  161. }
  162. }
  163. extension String.SubSequence {
  164. func trimmingWhitespaceAndNewlines() -> String {
  165. let trimmedSuffix = self.drop(while: { $0.isNewline || $0.isWhitespace })
  166. let trimmed = trimmedSuffix.trimmingPrefix(while: { $0.isNewline || $0.isWhitespace })
  167. return String(trimmed)
  168. }
  169. }