StructuredSwift+ServiceMetadata.swift 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  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. .commentable(
  125. .doc("Service descriptor for the \"\(literalFullyQualifiedService)\" service."),
  126. .variable(
  127. accessModifier: accessModifier,
  128. isStatic: true,
  129. kind: .let,
  130. left: .identifier(.pattern(propertyName)),
  131. right: .functionCall(
  132. .serviceDescriptor(literalFullyQualifiedService: literalFullyQualifiedService)
  133. )
  134. )
  135. )
  136. ]
  137. )
  138. }
  139. }
  140. extension VariableDescription {
  141. /// ```
  142. /// static let descriptors: [GRPCCore.MethodDescriptor] = [<Name1>.descriptor, ...]
  143. /// ```
  144. package static func methodDescriptorsArray(
  145. accessModifier: AccessModifier? = nil,
  146. methodNamespaceNames names: [String]
  147. ) -> Self {
  148. return VariableDescription(
  149. accessModifier: accessModifier,
  150. isStatic: true,
  151. kind: .let,
  152. left: .identifier(.pattern("descriptors")),
  153. type: .array(.methodDescriptor),
  154. right: .literal(.array(names.map { name in .identifierPattern(name).dot("descriptor") }))
  155. )
  156. }
  157. }
  158. extension EnumDescription {
  159. /// ```
  160. /// enum <Method> {
  161. /// typealias Input = <InputType>
  162. /// typealias Output = <OutputType>
  163. /// static let descriptor = GRPCCore.MethodDescriptor(
  164. /// service: <ServiceNamespace>.descriptor.fullyQualifiedService,
  165. /// method: "<LiteralMethod>"
  166. /// )
  167. /// }
  168. /// ```
  169. package static func methodNamespace(
  170. accessModifier: AccessModifier? = nil,
  171. name: String,
  172. literalMethod: String,
  173. literalFullyQualifiedService: String,
  174. inputType: String,
  175. outputType: String
  176. ) -> Self {
  177. return EnumDescription(
  178. accessModifier: accessModifier,
  179. name: name,
  180. members: [
  181. .commentable(
  182. .doc("Request type for \"\(literalMethod)\"."),
  183. .typealias(.methodInput(accessModifier: accessModifier, name: inputType))
  184. ),
  185. .commentable(
  186. .doc("Response type for \"\(literalMethod)\"."),
  187. .typealias(.methodOutput(accessModifier: accessModifier, name: outputType))
  188. ),
  189. .commentable(
  190. .doc("Descriptor for \"\(literalMethod)\"."),
  191. .variable(
  192. .methodDescriptor(
  193. accessModifier: accessModifier,
  194. literalFullyQualifiedService: literalFullyQualifiedService,
  195. literalMethodName: literalMethod
  196. )
  197. )
  198. ),
  199. ]
  200. )
  201. }
  202. /// ```
  203. /// enum Method {
  204. /// enum <Method> {
  205. /// typealias Input = <MethodInput>
  206. /// typealias Output = <MethodOutput>
  207. /// static let descriptor = GRPCCore.MethodDescriptor(
  208. /// service: <serviceNamespaceName>.descriptor.fullyQualifiedService,
  209. /// method: "<Method>"
  210. /// )
  211. /// }
  212. /// ...
  213. /// static let descriptors: [GRPCCore.MethodDescriptor] = [
  214. /// <Method>.descriptor,
  215. /// ...
  216. /// ]
  217. /// }
  218. /// ```
  219. package static func methodsNamespace(
  220. accessModifier: AccessModifier? = nil,
  221. literalFullyQualifiedService: String,
  222. methods: [MethodDescriptor]
  223. ) -> EnumDescription {
  224. var description = EnumDescription(accessModifier: accessModifier, name: "Method")
  225. // Add a namespace for each method.
  226. let methodNamespaces: [Declaration] = methods.map { method in
  227. return .commentable(
  228. .doc("Namespace for \"\(method.name.base)\" metadata."),
  229. .enum(
  230. .methodNamespace(
  231. accessModifier: accessModifier,
  232. name: method.name.base,
  233. literalMethod: method.name.base,
  234. literalFullyQualifiedService: literalFullyQualifiedService,
  235. inputType: method.inputType,
  236. outputType: method.outputType
  237. )
  238. )
  239. )
  240. }
  241. description.members.append(contentsOf: methodNamespaces)
  242. // Add an array of method descriptors
  243. let methodDescriptorsArray: VariableDescription = .methodDescriptorsArray(
  244. accessModifier: accessModifier,
  245. methodNamespaceNames: methods.map { $0.name.base }
  246. )
  247. description.members.append(
  248. .commentable(
  249. .doc("Descriptors for all methods in the \"\(literalFullyQualifiedService)\" service."),
  250. .variable(methodDescriptorsArray)
  251. )
  252. )
  253. return description
  254. }
  255. /// ```
  256. /// enum <Name> {
  257. /// static let descriptor = GRPCCore.ServiceDescriptor.<namespacedServicePropertyName>
  258. /// enum Method {
  259. /// ...
  260. /// }
  261. /// }
  262. /// ```
  263. package static func serviceNamespace(
  264. accessModifier: AccessModifier? = nil,
  265. name: String,
  266. literalFullyQualifiedService: String,
  267. methods: [MethodDescriptor]
  268. ) -> EnumDescription {
  269. var description = EnumDescription(accessModifier: accessModifier, name: name)
  270. // static let descriptor = GRPCCore.ServiceDescriptor(fullyQualifiedService: "...")
  271. let descriptor = VariableDescription.serviceDescriptor(
  272. accessModifier: accessModifier,
  273. literalFullyQualifiedService: literalFullyQualifiedService
  274. )
  275. description.members.append(
  276. .commentable(
  277. .doc("Service descriptor for the \"\(literalFullyQualifiedService)\" service."),
  278. .variable(descriptor)
  279. )
  280. )
  281. // enum Method { ... }
  282. let methodsNamespace: EnumDescription = .methodsNamespace(
  283. accessModifier: accessModifier,
  284. literalFullyQualifiedService: literalFullyQualifiedService,
  285. methods: methods
  286. )
  287. description.members.append(
  288. .commentable(
  289. .doc("Namespace for method metadata."),
  290. .enum(methodsNamespace)
  291. )
  292. )
  293. return description
  294. }
  295. }
  296. extension [CodeBlock] {
  297. /// ```
  298. /// enum <Service> {
  299. /// ...
  300. /// }
  301. ///
  302. /// extension GRPCCore.ServiceDescriptor {
  303. /// ...
  304. /// }
  305. /// ```
  306. package static func serviceMetadata(
  307. accessModifier: AccessModifier? = nil,
  308. service: ServiceDescriptor
  309. ) -> Self {
  310. var blocks: [CodeBlock] = []
  311. let serviceNamespace: EnumDescription = .serviceNamespace(
  312. accessModifier: accessModifier,
  313. name: service.namespacedGeneratedName,
  314. literalFullyQualifiedService: service.fullyQualifiedName,
  315. methods: service.methods
  316. )
  317. blocks.append(
  318. CodeBlock(
  319. comment: .doc(
  320. "Namespace containing generated types for the \"\(service.fullyQualifiedName)\" service."
  321. ),
  322. item: .declaration(.enum(serviceNamespace))
  323. )
  324. )
  325. let descriptorExtension: ExtensionDescription = .serviceDescriptor(
  326. accessModifier: accessModifier,
  327. propertyName: service.namespacedServicePropertyName,
  328. literalFullyQualifiedService: service.fullyQualifiedName
  329. )
  330. blocks.append(CodeBlock(item: .declaration(.extension(descriptorExtension))))
  331. return blocks
  332. }
  333. }