StructuredSwift+ServiceMetadata.swift 11 KB

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