StructuredSwift+ServiceMetadata.swift 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  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. extension TypealiasDescription {
  17. /// `typealias Input = <name>`
  18. package static func methodInput(
  19. accessModifier: AccessModifier? = nil,
  20. name: String
  21. ) -> Self {
  22. return TypealiasDescription(
  23. accessModifier: accessModifier,
  24. name: "Input",
  25. existingType: .member(name)
  26. )
  27. }
  28. /// `typealias Output = <name>`
  29. package static func methodOutput(
  30. accessModifier: AccessModifier? = nil,
  31. name: String
  32. ) -> Self {
  33. return TypealiasDescription(
  34. accessModifier: accessModifier,
  35. name: "Output",
  36. existingType: .member(name)
  37. )
  38. }
  39. }
  40. extension VariableDescription {
  41. /// ```
  42. /// static let descriptor = GRPCCore.MethodDescriptor(
  43. /// service: GRPCCore.ServiceDescriptor(fullyQualifiedServiceName: "<literalFullyQualifiedService>"),
  44. /// method: "<literalMethodName>"
  45. /// ```
  46. package static func methodDescriptor(
  47. accessModifier: AccessModifier? = nil,
  48. literalFullyQualifiedService: String,
  49. literalMethodName: String
  50. ) -> Self {
  51. return VariableDescription(
  52. accessModifier: accessModifier,
  53. isStatic: true,
  54. kind: .let,
  55. left: .identifier(.pattern("descriptor")),
  56. right: .functionCall(
  57. FunctionCallDescription(
  58. calledExpression: .identifierType(.methodDescriptor),
  59. arguments: [
  60. FunctionArgumentDescription(
  61. label: "service",
  62. expression: .functionCall(
  63. .serviceDescriptor(
  64. literalFullyQualifiedService: literalFullyQualifiedService
  65. )
  66. )
  67. ),
  68. FunctionArgumentDescription(
  69. label: "method",
  70. expression: .literal(literalMethodName)
  71. ),
  72. ]
  73. )
  74. )
  75. )
  76. }
  77. /// ```
  78. /// static let descriptor = GRPCCore.ServiceDescriptor(fullyQualifiedService: <LiteralFullyQualifiedService>)
  79. /// ```
  80. package static func serviceDescriptor(
  81. accessModifier: AccessModifier? = nil,
  82. literalFullyQualifiedService name: String
  83. ) -> Self {
  84. return VariableDescription(
  85. accessModifier: accessModifier,
  86. isStatic: true,
  87. kind: .let,
  88. left: .identifierPattern("descriptor"),
  89. right: .functionCall(.serviceDescriptor(literalFullyQualifiedService: name))
  90. )
  91. }
  92. }
  93. extension FunctionCallDescription {
  94. package static func serviceDescriptor(
  95. literalFullyQualifiedService: String
  96. ) -> Self {
  97. FunctionCallDescription(
  98. calledExpression: .identifier(.type(.serviceDescriptor)),
  99. arguments: [
  100. FunctionArgumentDescription(
  101. label: "fullyQualifiedService",
  102. expression: .literal(literalFullyQualifiedService)
  103. )
  104. ]
  105. )
  106. }
  107. }
  108. extension ExtensionDescription {
  109. /// ```
  110. /// extension GRPCCore.ServiceDescriptor {
  111. /// static let <PropertyName> = Self(
  112. /// fullyQualifiedService: <LiteralFullyQualifiedService>
  113. /// )
  114. /// }
  115. /// ```
  116. package static func serviceDescriptor(
  117. accessModifier: AccessModifier? = nil,
  118. propertyName: String,
  119. literalFullyQualifiedService: String
  120. ) -> ExtensionDescription {
  121. return ExtensionDescription(
  122. onType: "GRPCCore.ServiceDescriptor",
  123. declarations: [
  124. .variable(
  125. accessModifier: accessModifier,
  126. isStatic: true,
  127. kind: .let,
  128. left: .identifier(.pattern(propertyName)),
  129. right: .functionCall(
  130. .serviceDescriptor(literalFullyQualifiedService: literalFullyQualifiedService)
  131. )
  132. )
  133. ]
  134. )
  135. }
  136. }
  137. extension VariableDescription {
  138. /// ```
  139. /// static let descriptors: [GRPCCore.MethodDescriptor] = [<Name1>.descriptor, ...]
  140. /// ```
  141. package static func methodDescriptorsArray(
  142. accessModifier: AccessModifier? = nil,
  143. methodNamespaceNames names: [String]
  144. ) -> Self {
  145. return VariableDescription(
  146. accessModifier: accessModifier,
  147. isStatic: true,
  148. kind: .let,
  149. left: .identifier(.pattern("descriptors")),
  150. type: .array(.methodDescriptor),
  151. right: .literal(.array(names.map { name in .identifierPattern(name).dot("descriptor") }))
  152. )
  153. }
  154. }
  155. extension EnumDescription {
  156. /// ```
  157. /// enum <Method> {
  158. /// typealias Input = <InputType>
  159. /// typealias Output = <OutputType>
  160. /// static let descriptor = GRPCCore.MethodDescriptor(
  161. /// service: <ServiceNamespace>.descriptor.fullyQualifiedService,
  162. /// method: "<LiteralMethod>"
  163. /// )
  164. /// }
  165. /// ```
  166. package static func methodNamespace(
  167. accessModifier: AccessModifier? = nil,
  168. name: String,
  169. literalMethod: String,
  170. literalFullyQualifiedService: String,
  171. inputType: String,
  172. outputType: String
  173. ) -> Self {
  174. return EnumDescription(
  175. accessModifier: accessModifier,
  176. name: name,
  177. members: [
  178. .typealias(.methodInput(accessModifier: accessModifier, name: inputType)),
  179. .typealias(.methodOutput(accessModifier: accessModifier, name: outputType)),
  180. .variable(
  181. .methodDescriptor(
  182. accessModifier: accessModifier,
  183. literalFullyQualifiedService: literalFullyQualifiedService,
  184. literalMethodName: literalMethod
  185. )
  186. ),
  187. ]
  188. )
  189. }
  190. /// ```
  191. /// enum Method {
  192. /// enum <Method> {
  193. /// typealias Input = <MethodInput>
  194. /// typealias Output = <MethodOutput>
  195. /// static let descriptor = GRPCCore.MethodDescriptor(
  196. /// service: <serviceNamespaceName>.descriptor.fullyQualifiedService,
  197. /// method: "<Method>"
  198. /// )
  199. /// }
  200. /// ...
  201. /// static let descriptors: [GRPCCore.MethodDescriptor] = [
  202. /// <Method>.descriptor,
  203. /// ...
  204. /// ]
  205. /// }
  206. /// ```
  207. package static func methodsNamespace(
  208. accessModifier: AccessModifier? = nil,
  209. literalFullyQualifiedService: String,
  210. methods: [MethodDescriptor]
  211. ) -> EnumDescription {
  212. var description = EnumDescription(accessModifier: accessModifier, name: "Method")
  213. // Add a namespace for each method.
  214. let methodNamespaces: [Declaration] = methods.map { method in
  215. return .enum(
  216. .methodNamespace(
  217. accessModifier: accessModifier,
  218. name: method.name.base,
  219. literalMethod: method.name.base,
  220. literalFullyQualifiedService: literalFullyQualifiedService,
  221. inputType: method.inputType,
  222. outputType: method.outputType
  223. )
  224. )
  225. }
  226. description.members.append(contentsOf: methodNamespaces)
  227. // Add an array of method descriptors
  228. let methodDescriptorsArray: VariableDescription = .methodDescriptorsArray(
  229. accessModifier: accessModifier,
  230. methodNamespaceNames: methods.map { $0.name.base }
  231. )
  232. description.members.append(.variable(methodDescriptorsArray))
  233. return description
  234. }
  235. /// ```
  236. /// enum <Name> {
  237. /// static let descriptor = GRPCCore.ServiceDescriptor.<namespacedServicePropertyName>
  238. /// enum Method {
  239. /// ...
  240. /// }
  241. /// }
  242. /// ```
  243. package static func serviceNamespace(
  244. accessModifier: AccessModifier? = nil,
  245. name: String,
  246. literalFullyQualifiedService: String,
  247. methods: [MethodDescriptor]
  248. ) -> EnumDescription {
  249. var description = EnumDescription(accessModifier: accessModifier, name: name)
  250. // static let descriptor = GRPCCore.ServiceDescriptor(fullyQualifiedService: "...")
  251. let descriptor = VariableDescription.serviceDescriptor(
  252. accessModifier: accessModifier,
  253. literalFullyQualifiedService: literalFullyQualifiedService
  254. )
  255. description.members.append(.variable(descriptor))
  256. // enum Method { ... }
  257. let methodsNamespace: EnumDescription = .methodsNamespace(
  258. accessModifier: accessModifier,
  259. literalFullyQualifiedService: literalFullyQualifiedService,
  260. methods: methods
  261. )
  262. description.members.append(.enum(methodsNamespace))
  263. return description
  264. }
  265. }
  266. extension [CodeBlock] {
  267. /// ```
  268. /// enum <Service> {
  269. /// ...
  270. /// }
  271. ///
  272. /// extension GRPCCore.ServiceDescriptor {
  273. /// ...
  274. /// }
  275. /// ```
  276. package static func serviceMetadata(
  277. accessModifier: AccessModifier? = nil,
  278. service: ServiceDescriptor
  279. ) -> Self {
  280. var blocks: [CodeBlock] = []
  281. let serviceNamespace: EnumDescription = .serviceNamespace(
  282. accessModifier: accessModifier,
  283. name: service.namespacedGeneratedName,
  284. literalFullyQualifiedService: service.fullyQualifiedName,
  285. methods: service.methods
  286. )
  287. blocks.append(CodeBlock(item: .declaration(.enum(serviceNamespace))))
  288. let descriptorExtension: ExtensionDescription = .serviceDescriptor(
  289. accessModifier: accessModifier,
  290. propertyName: service.namespacedServicePropertyName,
  291. literalFullyQualifiedService: service.fullyQualifiedName
  292. )
  293. blocks.append(CodeBlock(item: .declaration(.extension(descriptorExtension))))
  294. return blocks
  295. }
  296. }