StructuredSwift+ServiceMetadata.swift 10 KB

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