@typespec/emitter-framework 0.15.0-dev.3 → 0.15.0-dev.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. package/CHANGELOG.md +1 -16
  2. package/dist/src/python/builtins.d.ts +14 -0
  3. package/dist/src/python/builtins.d.ts.map +1 -0
  4. package/dist/src/python/builtins.js +29 -0
  5. package/dist/src/python/builtins.js.map +1 -0
  6. package/dist/src/python/components/array-expression/array-expression.d.ts +6 -0
  7. package/dist/src/python/components/array-expression/array-expression.d.ts.map +1 -0
  8. package/dist/src/python/components/array-expression/array-expression.js +11 -0
  9. package/dist/src/python/components/array-expression/array-expression.js.map +1 -0
  10. package/dist/src/python/components/array-expression/array-expression.test.d.ts +2 -0
  11. package/dist/src/python/components/array-expression/array-expression.test.d.ts.map +1 -0
  12. package/dist/src/python/components/array-expression/array-expression.test.js +19 -0
  13. package/dist/src/python/components/array-expression/array-expression.test.js.map +1 -0
  14. package/dist/src/python/components/array-expression/index.d.ts +2 -0
  15. package/dist/src/python/components/array-expression/index.d.ts.map +1 -0
  16. package/dist/src/python/components/array-expression/index.js +2 -0
  17. package/dist/src/python/components/array-expression/index.js.map +1 -0
  18. package/dist/src/python/components/atom/atom.d.ts +33 -0
  19. package/dist/src/python/components/atom/atom.d.ts.map +1 -0
  20. package/dist/src/python/components/atom/atom.js +88 -0
  21. package/dist/src/python/components/atom/atom.js.map +1 -0
  22. package/dist/src/python/components/atom/atom.test.d.ts +2 -0
  23. package/dist/src/python/components/atom/atom.test.d.ts.map +1 -0
  24. package/dist/src/python/components/atom/atom.test.js +224 -0
  25. package/dist/src/python/components/atom/atom.test.js.map +1 -0
  26. package/dist/src/python/components/atom/index.d.ts +2 -0
  27. package/dist/src/python/components/atom/index.d.ts.map +1 -0
  28. package/dist/src/python/components/atom/index.js +2 -0
  29. package/dist/src/python/components/atom/index.js.map +1 -0
  30. package/dist/src/python/components/class-declaration/class-bases.d.ts +45 -0
  31. package/dist/src/python/components/class-declaration/class-bases.d.ts.map +1 -0
  32. package/dist/src/python/components/class-declaration/class-bases.js +84 -0
  33. package/dist/src/python/components/class-declaration/class-bases.js.map +1 -0
  34. package/dist/src/python/components/class-declaration/class-body.d.ts +16 -0
  35. package/dist/src/python/components/class-declaration/class-body.d.ts.map +1 -0
  36. package/dist/src/python/components/class-declaration/class-body.js +52 -0
  37. package/dist/src/python/components/class-declaration/class-body.js.map +1 -0
  38. package/dist/src/python/components/class-declaration/class-declaration.d.ts +23 -0
  39. package/dist/src/python/components/class-declaration/class-declaration.d.ts.map +1 -0
  40. package/dist/src/python/components/class-declaration/class-declaration.js +118 -0
  41. package/dist/src/python/components/class-declaration/class-declaration.js.map +1 -0
  42. package/dist/src/python/components/class-declaration/class-declaration.test.d.ts +2 -0
  43. package/dist/src/python/components/class-declaration/class-declaration.test.d.ts.map +1 -0
  44. package/dist/src/python/components/class-declaration/class-declaration.test.js +1527 -0
  45. package/dist/src/python/components/class-declaration/class-declaration.test.js.map +1 -0
  46. package/dist/src/python/components/class-declaration/class-member.d.ts +16 -0
  47. package/dist/src/python/components/class-declaration/class-member.d.ts.map +1 -0
  48. package/dist/src/python/components/class-declaration/class-member.js +71 -0
  49. package/dist/src/python/components/class-declaration/class-member.js.map +1 -0
  50. package/dist/src/python/components/class-declaration/class-member.test.d.ts +2 -0
  51. package/dist/src/python/components/class-declaration/class-member.test.d.ts.map +1 -0
  52. package/dist/src/python/components/class-declaration/class-member.test.js +202 -0
  53. package/dist/src/python/components/class-declaration/class-member.test.js.map +1 -0
  54. package/dist/src/python/components/class-declaration/class-method.d.ts +22 -0
  55. package/dist/src/python/components/class-declaration/class-method.d.ts.map +1 -0
  56. package/dist/src/python/components/class-declaration/class-method.js +76 -0
  57. package/dist/src/python/components/class-declaration/class-method.js.map +1 -0
  58. package/dist/src/python/components/class-declaration/class-method.test.d.ts +2 -0
  59. package/dist/src/python/components/class-declaration/class-method.test.d.ts.map +1 -0
  60. package/dist/src/python/components/class-declaration/class-method.test.js +298 -0
  61. package/dist/src/python/components/class-declaration/class-method.test.js.map +1 -0
  62. package/dist/src/python/components/class-declaration/index.d.ts +7 -0
  63. package/dist/src/python/components/class-declaration/index.d.ts.map +1 -0
  64. package/dist/src/python/components/class-declaration/index.js +7 -0
  65. package/dist/src/python/components/class-declaration/index.js.map +1 -0
  66. package/dist/src/python/components/class-declaration/primitive-initializer.d.ts +22 -0
  67. package/dist/src/python/components/class-declaration/primitive-initializer.d.ts.map +1 -0
  68. package/dist/src/python/components/class-declaration/primitive-initializer.js +67 -0
  69. package/dist/src/python/components/class-declaration/primitive-initializer.js.map +1 -0
  70. package/dist/src/python/components/doc-element/doc-element.d.ts +46 -0
  71. package/dist/src/python/components/doc-element/doc-element.d.ts.map +1 -0
  72. package/dist/src/python/components/doc-element/doc-element.js +59 -0
  73. package/dist/src/python/components/doc-element/doc-element.js.map +1 -0
  74. package/dist/src/python/components/doc-element/index.d.ts +2 -0
  75. package/dist/src/python/components/doc-element/index.d.ts.map +1 -0
  76. package/dist/src/python/components/doc-element/index.js +2 -0
  77. package/dist/src/python/components/doc-element/index.js.map +1 -0
  78. package/dist/src/python/components/enum-declaration/enum-declaration.d.ts +8 -0
  79. package/dist/src/python/components/enum-declaration/enum-declaration.d.ts.map +1 -0
  80. package/dist/src/python/components/enum-declaration/enum-declaration.js +80 -0
  81. package/dist/src/python/components/enum-declaration/enum-declaration.js.map +1 -0
  82. package/dist/src/python/components/enum-declaration/enum-declaration.test.d.ts +2 -0
  83. package/dist/src/python/components/enum-declaration/enum-declaration.test.d.ts.map +1 -0
  84. package/dist/src/python/components/enum-declaration/enum-declaration.test.js +344 -0
  85. package/dist/src/python/components/enum-declaration/enum-declaration.test.js.map +1 -0
  86. package/dist/src/python/components/enum-declaration/enum-member.d.ts +9 -0
  87. package/dist/src/python/components/enum-declaration/enum-member.d.ts.map +1 -0
  88. package/dist/src/python/components/enum-declaration/enum-member.js +22 -0
  89. package/dist/src/python/components/enum-declaration/enum-member.js.map +1 -0
  90. package/dist/src/python/components/enum-declaration/index.d.ts +3 -0
  91. package/dist/src/python/components/enum-declaration/index.d.ts.map +1 -0
  92. package/dist/src/python/components/enum-declaration/index.js +3 -0
  93. package/dist/src/python/components/enum-declaration/index.js.map +1 -0
  94. package/dist/src/python/components/function-declaration/function-declaration.d.ts +24 -0
  95. package/dist/src/python/components/function-declaration/function-declaration.d.ts.map +1 -0
  96. package/dist/src/python/components/function-declaration/function-declaration.js +68 -0
  97. package/dist/src/python/components/function-declaration/function-declaration.js.map +1 -0
  98. package/dist/src/python/components/function-declaration/function-declaration.test.d.ts +2 -0
  99. package/dist/src/python/components/function-declaration/function-declaration.test.d.ts.map +1 -0
  100. package/dist/src/python/components/function-declaration/function-declaration.test.js +682 -0
  101. package/dist/src/python/components/function-declaration/function-declaration.test.js.map +1 -0
  102. package/dist/src/python/components/function-declaration/index.d.ts +2 -0
  103. package/dist/src/python/components/function-declaration/index.d.ts.map +1 -0
  104. package/dist/src/python/components/function-declaration/index.js +2 -0
  105. package/dist/src/python/components/function-declaration/index.js.map +1 -0
  106. package/dist/src/python/components/index.d.ts +12 -0
  107. package/dist/src/python/components/index.d.ts.map +1 -0
  108. package/dist/src/python/components/index.js +12 -0
  109. package/dist/src/python/components/index.js.map +1 -0
  110. package/dist/src/python/components/protocol-declaration/callable-parameters.d.ts +25 -0
  111. package/dist/src/python/components/protocol-declaration/callable-parameters.d.ts.map +1 -0
  112. package/dist/src/python/components/protocol-declaration/callable-parameters.js +33 -0
  113. package/dist/src/python/components/protocol-declaration/callable-parameters.js.map +1 -0
  114. package/dist/src/python/components/protocol-declaration/index.d.ts +3 -0
  115. package/dist/src/python/components/protocol-declaration/index.d.ts.map +1 -0
  116. package/dist/src/python/components/protocol-declaration/index.js +3 -0
  117. package/dist/src/python/components/protocol-declaration/index.js.map +1 -0
  118. package/dist/src/python/components/protocol-declaration/protocol-declaration.d.ts +8 -0
  119. package/dist/src/python/components/protocol-declaration/protocol-declaration.d.ts.map +1 -0
  120. package/dist/src/python/components/protocol-declaration/protocol-declaration.js +86 -0
  121. package/dist/src/python/components/protocol-declaration/protocol-declaration.js.map +1 -0
  122. package/dist/src/python/components/protocol-declaration/protocol-declaration.test.d.ts +2 -0
  123. package/dist/src/python/components/protocol-declaration/protocol-declaration.test.d.ts.map +1 -0
  124. package/dist/src/python/components/protocol-declaration/protocol-declaration.test.js +117 -0
  125. package/dist/src/python/components/protocol-declaration/protocol-declaration.test.js.map +1 -0
  126. package/dist/src/python/components/record-expression/index.d.ts +2 -0
  127. package/dist/src/python/components/record-expression/index.d.ts.map +1 -0
  128. package/dist/src/python/components/record-expression/index.js +2 -0
  129. package/dist/src/python/components/record-expression/index.js.map +1 -0
  130. package/dist/src/python/components/record-expression/record-expression.d.ts +6 -0
  131. package/dist/src/python/components/record-expression/record-expression.d.ts.map +1 -0
  132. package/dist/src/python/components/record-expression/record-expression.js +13 -0
  133. package/dist/src/python/components/record-expression/record-expression.js.map +1 -0
  134. package/dist/src/python/components/record-expression/record-expression.test.d.ts +2 -0
  135. package/dist/src/python/components/record-expression/record-expression.test.d.ts.map +1 -0
  136. package/dist/src/python/components/record-expression/record-expression.test.js +19 -0
  137. package/dist/src/python/components/record-expression/record-expression.test.js.map +1 -0
  138. package/dist/src/python/components/type-alias-declaration/index.d.ts +2 -0
  139. package/dist/src/python/components/type-alias-declaration/index.d.ts.map +1 -0
  140. package/dist/src/python/components/type-alias-declaration/index.js +2 -0
  141. package/dist/src/python/components/type-alias-declaration/index.js.map +1 -0
  142. package/dist/src/python/components/type-alias-declaration/type-alias-declaration.d.ts +16 -0
  143. package/dist/src/python/components/type-alias-declaration/type-alias-declaration.d.ts.map +1 -0
  144. package/dist/src/python/components/type-alias-declaration/type-alias-declaration.js +75 -0
  145. package/dist/src/python/components/type-alias-declaration/type-alias-declaration.js.map +1 -0
  146. package/dist/src/python/components/type-alias-declaration/type-alias-declaration.test.d.ts +2 -0
  147. package/dist/src/python/components/type-alias-declaration/type-alias-declaration.test.d.ts.map +1 -0
  148. package/dist/src/python/components/type-alias-declaration/type-alias-declaration.test.js +140 -0
  149. package/dist/src/python/components/type-alias-declaration/type-alias-declaration.test.js.map +1 -0
  150. package/dist/src/python/components/type-declaration/index.d.ts +2 -0
  151. package/dist/src/python/components/type-declaration/index.d.ts.map +1 -0
  152. package/dist/src/python/components/type-declaration/index.js +2 -0
  153. package/dist/src/python/components/type-declaration/index.js.map +1 -0
  154. package/dist/src/python/components/type-declaration/type-declaration.d.ts +11 -0
  155. package/dist/src/python/components/type-declaration/type-declaration.d.ts.map +1 -0
  156. package/dist/src/python/components/type-declaration/type-declaration.js +31 -0
  157. package/dist/src/python/components/type-declaration/type-declaration.js.map +1 -0
  158. package/dist/src/python/components/type-declaration/type-declaration.test.d.ts +2 -0
  159. package/dist/src/python/components/type-declaration/type-declaration.test.d.ts.map +1 -0
  160. package/dist/src/python/components/type-declaration/type-declaration.test.js +69 -0
  161. package/dist/src/python/components/type-declaration/type-declaration.test.js.map +1 -0
  162. package/dist/src/python/components/type-expression/index.d.ts +2 -0
  163. package/dist/src/python/components/type-expression/index.d.ts.map +1 -0
  164. package/dist/src/python/components/type-expression/index.js +2 -0
  165. package/dist/src/python/components/type-expression/index.js.map +1 -0
  166. package/dist/src/python/components/type-expression/type-expression.d.ts +12 -0
  167. package/dist/src/python/components/type-expression/type-expression.d.ts.map +1 -0
  168. package/dist/src/python/components/type-expression/type-expression.js +348 -0
  169. package/dist/src/python/components/type-expression/type-expression.js.map +1 -0
  170. package/dist/src/python/components/type-expression/type-expression.test.d.ts +2 -0
  171. package/dist/src/python/components/type-expression/type-expression.test.d.ts.map +1 -0
  172. package/dist/src/python/components/type-expression/type-expression.test.js +503 -0
  173. package/dist/src/python/components/type-expression/type-expression.test.js.map +1 -0
  174. package/dist/src/python/index.d.ts +4 -0
  175. package/dist/src/python/index.d.ts.map +1 -0
  176. package/dist/src/python/index.js +4 -0
  177. package/dist/src/python/index.js.map +1 -0
  178. package/dist/src/python/lib.d.ts +68 -0
  179. package/dist/src/python/lib.d.ts.map +1 -0
  180. package/dist/src/python/lib.js +38 -0
  181. package/dist/src/python/lib.js.map +1 -0
  182. package/dist/src/python/test-utils.d.ts +8 -0
  183. package/dist/src/python/test-utils.d.ts.map +1 -0
  184. package/dist/src/python/test-utils.js +25 -0
  185. package/dist/src/python/test-utils.js.map +1 -0
  186. package/dist/src/python/utils/index.d.ts +4 -0
  187. package/dist/src/python/utils/index.d.ts.map +1 -0
  188. package/dist/src/python/utils/index.js +4 -0
  189. package/dist/src/python/utils/index.js.map +1 -0
  190. package/dist/src/python/utils/operation.d.ts +27 -0
  191. package/dist/src/python/utils/operation.d.ts.map +1 -0
  192. package/dist/src/python/utils/operation.js +139 -0
  193. package/dist/src/python/utils/operation.js.map +1 -0
  194. package/dist/src/python/utils/refkey.d.ts +23 -0
  195. package/dist/src/python/utils/refkey.d.ts.map +1 -0
  196. package/dist/src/python/utils/refkey.js +36 -0
  197. package/dist/src/python/utils/refkey.js.map +1 -0
  198. package/dist/src/python/utils/type.d.ts +19 -0
  199. package/dist/src/python/utils/type.d.ts.map +1 -0
  200. package/dist/src/python/utils/type.js +24 -0
  201. package/dist/src/python/utils/type.js.map +1 -0
  202. package/package.json +9 -1
  203. package/package.json.bak +10 -1
  204. package/src/python/builtins.ts +43 -0
  205. package/src/python/components/array-expression/array-expression.test.tsx +14 -0
  206. package/src/python/components/array-expression/array-expression.tsx +11 -0
  207. package/src/python/components/array-expression/index.ts +1 -0
  208. package/src/python/components/atom/atom.test.tsx +244 -0
  209. package/src/python/components/atom/atom.tsx +95 -0
  210. package/src/python/components/atom/index.ts +1 -0
  211. package/src/python/components/class-declaration/class-bases.tsx +92 -0
  212. package/src/python/components/class-declaration/class-body.tsx +56 -0
  213. package/src/python/components/class-declaration/class-declaration.test.tsx +1414 -0
  214. package/src/python/components/class-declaration/class-declaration.tsx +116 -0
  215. package/src/python/components/class-declaration/class-member.test.tsx +194 -0
  216. package/src/python/components/class-declaration/class-member.tsx +67 -0
  217. package/src/python/components/class-declaration/class-method.test.tsx +250 -0
  218. package/src/python/components/class-declaration/class-method.tsx +97 -0
  219. package/src/python/components/class-declaration/index.ts +6 -0
  220. package/src/python/components/class-declaration/primitive-initializer.tsx +62 -0
  221. package/src/python/components/doc-element/doc-element.tsx +83 -0
  222. package/src/python/components/doc-element/index.ts +1 -0
  223. package/src/python/components/enum-declaration/enum-declaration.test.tsx +319 -0
  224. package/src/python/components/enum-declaration/enum-declaration.tsx +77 -0
  225. package/src/python/components/enum-declaration/enum-member.tsx +21 -0
  226. package/src/python/components/enum-declaration/index.ts +2 -0
  227. package/src/python/components/function-declaration/function-declaration.test.tsx +582 -0
  228. package/src/python/components/function-declaration/function-declaration.tsx +90 -0
  229. package/src/python/components/function-declaration/index.ts +1 -0
  230. package/src/python/components/index.ts +11 -0
  231. package/src/python/components/protocol-declaration/callable-parameters.tsx +44 -0
  232. package/src/python/components/protocol-declaration/index.ts +2 -0
  233. package/src/python/components/protocol-declaration/protocol-declaration.test.tsx +106 -0
  234. package/src/python/components/protocol-declaration/protocol-declaration.tsx +73 -0
  235. package/src/python/components/record-expression/index.ts +1 -0
  236. package/src/python/components/record-expression/record-expression.test.tsx +14 -0
  237. package/src/python/components/record-expression/record-expression.tsx +13 -0
  238. package/src/python/components/type-alias-declaration/index.ts +1 -0
  239. package/src/python/components/type-alias-declaration/type-alias-declaration.test.tsx +117 -0
  240. package/src/python/components/type-alias-declaration/type-alias-declaration.tsx +67 -0
  241. package/src/python/components/type-declaration/index.ts +1 -0
  242. package/src/python/components/type-declaration/type-declaration.test.tsx +58 -0
  243. package/src/python/components/type-declaration/type-declaration.tsx +26 -0
  244. package/src/python/components/type-expression/index.ts +1 -0
  245. package/src/python/components/type-expression/type-expression.test.tsx +463 -0
  246. package/src/python/components/type-expression/type-expression.tsx +333 -0
  247. package/src/python/index.ts +3 -0
  248. package/src/python/lib.ts +40 -0
  249. package/src/python/test-utils.tsx +31 -0
  250. package/src/python/utils/index.ts +3 -0
  251. package/src/python/utils/operation.ts +161 -0
  252. package/src/python/utils/refkey.ts +36 -0
  253. package/src/python/utils/type.ts +31 -0
@@ -0,0 +1,44 @@
1
+ import { refkey } from "@alloy-js/core";
2
+ import * as py from "@alloy-js/python";
3
+ import type { Operation } from "@typespec/compiler";
4
+ import { useTsp } from "../../../core/context/tsp-context.js";
5
+ import { buildParameterDescriptor } from "../../utils/operation.js";
6
+
7
+ export interface CallableParametersProps {
8
+ /**
9
+ * The operation to extract parameters from.
10
+ */
11
+ type: Operation;
12
+ }
13
+
14
+ /**
15
+ * Builds parameter descriptors for a callable (method/function) from an Operation's parameters.
16
+ *
17
+ * Iterates over the operation's parameters model and creates ParameterDescriptor objects
18
+ * with name, type expression, and default value (handles both explicit defaults and
19
+ * optional parameters without defaults which get `= None`).
20
+ *
21
+ * @returns Array of ParameterDescriptor objects for use with py.MethodDeclaration or similar.
22
+ *
23
+ * @example
24
+ * ```tsx
25
+ * const params = CallableParameters({ type: operation });
26
+ * <py.MethodDeclaration name="foo" parameters={params} />
27
+ * ```
28
+ */
29
+ export function CallableParameters(props: CallableParametersProps): py.ParameterDescriptor[] {
30
+ const { $ } = useTsp();
31
+ const paramsModel = props.type.parameters;
32
+
33
+ if (!paramsModel) {
34
+ return [];
35
+ }
36
+
37
+ const parameters: py.ParameterDescriptor[] = [];
38
+
39
+ for (const prop of $.model.getProperties(paramsModel).values()) {
40
+ parameters.push(buildParameterDescriptor(prop, refkey()));
41
+ }
42
+
43
+ return parameters;
44
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./callable-parameters.js";
2
+ export * from "./protocol-declaration.js";
@@ -0,0 +1,106 @@
1
+ import { TypeExpression } from "#python/components/type-expression/type-expression.js";
2
+ import { Tester } from "#test/test-host.js";
3
+ import { t } from "@typespec/compiler/testing";
4
+ import { describe, expect, it } from "vitest";
5
+ import { getOutput } from "../../test-utils.js";
6
+ import { ProtocolDeclaration } from "./protocol-declaration.js";
7
+
8
+ describe("Python ProtocolDeclaration", () => {
9
+ it("emits a callback Protocol for an operation", async () => {
10
+ const { program, getName, getOtherName } = await Tester.compile(t.code`
11
+ op ${t.op("getName")}(id: string): string;
12
+ op ${t.op("getOtherName")}(id: string): string;
13
+ `);
14
+
15
+ expect(
16
+ getOutput(program, [
17
+ <ProtocolDeclaration type={getName} />,
18
+ <ProtocolDeclaration type={getOtherName} />,
19
+ ]),
20
+ ).toRenderTo(`
21
+ from typing import Protocol
22
+
23
+
24
+ class GetName(Protocol):
25
+ def __call__(self, id: str) -> str:
26
+ ...
27
+
28
+
29
+
30
+ class GetOtherName(Protocol):
31
+ def __call__(self, id: str) -> str:
32
+ ...
33
+
34
+
35
+ `);
36
+ });
37
+
38
+ it("emits no return annotation when return type omitted", async () => {
39
+ const { program, getName } = await Tester.compile(t.code`
40
+ op ${t.op("getName")}(id: string): string;
41
+ `);
42
+
43
+ // Create a shallow clone without returnType to simulate missing return info
44
+ const getNameNoReturn: any = { ...(getName as any) };
45
+ delete getNameNoReturn.returnType;
46
+
47
+ expect(getOutput(program, [<ProtocolDeclaration type={getNameNoReturn} />])).toRenderTo(`
48
+ from typing import Protocol
49
+
50
+
51
+ class GetName(Protocol):
52
+ def __call__(self, id: str):
53
+ ...
54
+
55
+
56
+ `);
57
+ });
58
+
59
+ it("emits a Protocol for a TypeSpec interface (methods only)", async () => {
60
+ const { program, Greeter } = await Tester.compile(t.code`
61
+ interface ${t.interface("Greeter")} {
62
+ op getName(id: string): string;
63
+ op getOtherName(id: string): string;
64
+ }
65
+ `);
66
+
67
+ expect(getOutput(program, [<ProtocolDeclaration type={Greeter} />])).toRenderTo(`
68
+ from typing import Protocol
69
+
70
+
71
+ class Greeter(Protocol):
72
+ def get_name(self, id: str) -> str:
73
+ ...
74
+
75
+ def get_other_name(self, id: str) -> str:
76
+ ...
77
+
78
+
79
+ `);
80
+ });
81
+
82
+ it("emits both a Protocol and a Callable for the same operation", async () => {
83
+ const { program, getName } = await Tester.compile(t.code`
84
+ op ${t.op("getName")}(id: string): string;
85
+ `);
86
+
87
+ expect(
88
+ getOutput(program, [
89
+ <ProtocolDeclaration type={getName} />,
90
+ <TypeExpression type={getName} />,
91
+ ]),
92
+ ).toRenderTo(`
93
+ from typing import Callable
94
+ from typing import Protocol
95
+
96
+
97
+ class GetName(Protocol):
98
+ def __call__(self, id: str) -> str:
99
+ ...
100
+
101
+
102
+
103
+ Callable[[str], str]
104
+ `);
105
+ });
106
+ });
@@ -0,0 +1,73 @@
1
+ import { useTsp } from "#core/context/tsp-context.js";
2
+ import { typingModule } from "#python/builtins.js";
3
+ import { TypeExpression } from "#python/components/type-expression/type-expression.js";
4
+ import { reportPythonDiagnostic } from "#python/lib.js";
5
+ import { declarationRefkeys } from "#python/utils/refkey.js";
6
+ import { mapJoin } from "@alloy-js/core";
7
+ import * as py from "@alloy-js/python";
8
+ import type { Interface, Operation, Type } from "@typespec/compiler";
9
+ import { CallableParameters } from "./callable-parameters.js";
10
+
11
+ export interface ProtocolDeclarationProps extends Omit<py.ClassDeclarationProps, "name"> {
12
+ type: Interface | Operation;
13
+ name?: string;
14
+ }
15
+
16
+ export function ProtocolDeclaration(props: ProtocolDeclarationProps) {
17
+ const { $ } = useTsp();
18
+
19
+ const refkeys = declarationRefkeys(props.refkey, props.type);
20
+ const protocolBase = typingModule["."]["Protocol"];
21
+
22
+ const namePolicy = py.usePythonNamePolicy();
23
+ const originalName = props.name ?? (props.type as any)?.name ?? "";
24
+ const name = namePolicy.getName(originalName, "class");
25
+
26
+ // Interfaces will be converted to Protocols with method stubs for operations
27
+ if ((props.type as any)?.kind === "Interface") {
28
+ const iface = props.type as Interface;
29
+ const operations = ((iface as any).operations ?? new Map()) as Map<string, any>;
30
+ const methods = mapJoin(
31
+ () => Array.from(operations.values()) as any[],
32
+ (op: any) => {
33
+ const methodName = namePolicy.getName(op.name, "function");
34
+ const prm = CallableParameters({ type: op as Operation }); // self injected by MethodDeclaration
35
+ const ret = (op as any)?.returnType ? (
36
+ <TypeExpression type={(op as Operation).returnType as Type} />
37
+ ) : undefined;
38
+ return (
39
+ <py.MethodDeclaration name={methodName} parameters={prm} returnType={ret}>
40
+ ...
41
+ </py.MethodDeclaration>
42
+ );
43
+ },
44
+ );
45
+ return (
46
+ <py.ClassDeclaration name={name} bases={[protocolBase]} refkey={refkeys} doc={props.doc}>
47
+ {methods}
48
+ </py.ClassDeclaration>
49
+ );
50
+ }
51
+
52
+ if ((props.type as any)?.kind !== "Operation") {
53
+ reportPythonDiagnostic($.program, {
54
+ code: "python-unsupported-type",
55
+ target: props.type as any,
56
+ });
57
+ return <></>;
58
+ }
59
+
60
+ // Operations will be converted to Callback protocol using a dunder __call__ method
61
+ const op = props.type as Operation;
62
+ const cbParams = CallableParameters({ type: op });
63
+ const cbReturn = (op as any)?.returnType ? (
64
+ <TypeExpression type={op.returnType as Type} />
65
+ ) : undefined;
66
+ return (
67
+ <py.ClassDeclaration name={name} bases={[protocolBase]} refkey={refkeys} doc={props.doc}>
68
+ <py.DunderMethodDeclaration name="__call__" returnType={cbReturn} parameters={cbParams}>
69
+ ...
70
+ </py.DunderMethodDeclaration>
71
+ </py.ClassDeclaration>
72
+ );
73
+ }
@@ -0,0 +1 @@
1
+ export * from "./record-expression.js";
@@ -0,0 +1,14 @@
1
+ import { Tester } from "#test/test-host.js";
2
+ import { d } from "@alloy-js/core/testing";
3
+ import { t } from "@typespec/compiler/testing";
4
+ import { expect, it } from "vitest";
5
+ import { getOutput } from "../../test-utils.js";
6
+ import { TypeExpression } from "../type-expression/type-expression.js";
7
+
8
+ it("maps Record to Python dict", async () => {
9
+ const { program, TestRecord } = await Tester.compile(t.code`
10
+ alias ${t.type("TestRecord")} = Record<boolean>;
11
+ `);
12
+
13
+ expect(getOutput(program, [<TypeExpression type={TestRecord} />])).toRenderTo(d`dict[str, bool]`);
14
+ });
@@ -0,0 +1,13 @@
1
+ import { code } from "@alloy-js/core";
2
+ import type { Type } from "@typespec/compiler";
3
+ import { TypeExpression } from "../type-expression/type-expression.js";
4
+
5
+ export interface RecordExpressionProps {
6
+ elementType: Type;
7
+ }
8
+
9
+ export function RecordExpression({ elementType }: RecordExpressionProps) {
10
+ return code`
11
+ dict[str, ${(<TypeExpression type={elementType} />)}]
12
+ `;
13
+ }
@@ -0,0 +1 @@
1
+ export * from "./type-alias-declaration.js";
@@ -0,0 +1,117 @@
1
+ import { Tester } from "#test/test-host.js";
2
+ import { t } from "@typespec/compiler/testing";
3
+ import { describe, expect, it } from "vitest";
4
+ import { getOutput } from "../../test-utils.js";
5
+ import { TypeAliasDeclaration } from "./type-alias-declaration.js";
6
+
7
+ describe("Python Declaration equivalency to Type Alias", () => {
8
+ describe("Type Alias Declaration bound to Typespec Scalar", () => {
9
+ describe("Scalar extends utcDateTime", () => {
10
+ it("creates a type alias declaration for a utcDateTime without encoding", async () => {
11
+ const { program, MyDate } = await Tester.compile(t.code`
12
+ scalar ${t.scalar("MyDate")} extends utcDateTime;
13
+ `);
14
+
15
+ expect(getOutput(program, [<TypeAliasDeclaration type={MyDate} />])).toRenderTo(`
16
+ from datetime import datetime
17
+ from typing import TypeAlias
18
+
19
+
20
+ my_date: TypeAlias = datetime`);
21
+ });
22
+
23
+ it("creates a type alias declaration with doc", async () => {
24
+ const { program, MyDate } = await Tester.compile(t.code`
25
+ /**
26
+ * Type to represent a date
27
+ */
28
+ scalar ${t.scalar("MyDate")} extends utcDateTime;
29
+ `);
30
+
31
+ expect(getOutput(program, [<TypeAliasDeclaration type={MyDate} />])).toRenderTo(`
32
+ from datetime import datetime
33
+ from typing import TypeAlias
34
+
35
+
36
+ # Type to represent a date
37
+ my_date: TypeAlias = datetime`);
38
+ });
39
+
40
+ it("can override JSDoc", async () => {
41
+ const { program, MyDate } = await Tester.compile(t.code`
42
+ /**
43
+ * Type to represent a date
44
+ */
45
+ scalar ${t.scalar("MyDate")} extends utcDateTime;
46
+ `);
47
+
48
+ expect(getOutput(program, [<TypeAliasDeclaration doc={"Overridden Doc"} type={MyDate} />]))
49
+ .toRenderTo(`
50
+ from datetime import datetime
51
+ from typing import TypeAlias
52
+
53
+
54
+ # Overridden Doc
55
+ my_date: TypeAlias = datetime`);
56
+ });
57
+
58
+ it("creates a type alias declaration for a utcDateTime with unixTimeStamp encoding", async () => {
59
+ const { program, MyDate } = await Tester.compile(t.code`
60
+ @encode("unixTimestamp", int32)
61
+ scalar ${t.scalar("MyDate")} extends utcDateTime;
62
+ `);
63
+
64
+ expect(getOutput(program, [<TypeAliasDeclaration type={MyDate} />])).toRenderTo(`
65
+ from datetime import datetime
66
+ from typing import TypeAlias
67
+
68
+
69
+ my_date: TypeAlias = datetime`);
70
+ });
71
+
72
+ it("creates a type alias declaration for a utcDateTime with rfc7231 encoding", async () => {
73
+ const { program, MyDate } = await Tester.compile(t.code`
74
+ @encode("rfc7231")
75
+ scalar ${t.scalar("MyDate")} extends utcDateTime;
76
+ `);
77
+
78
+ expect(getOutput(program, [<TypeAliasDeclaration type={MyDate} />])).toRenderTo(`
79
+ from datetime import datetime
80
+ from typing import TypeAlias
81
+
82
+
83
+ my_date: TypeAlias = datetime`);
84
+ });
85
+
86
+ it("creates a type alias declaration for a utcDateTime with rfc3339 encoding", async () => {
87
+ const { program, MyDate } = await Tester.compile(t.code`
88
+ @encode("rfc3339")
89
+ scalar ${t.scalar("MyDate")} extends utcDateTime;
90
+ `);
91
+
92
+ expect(getOutput(program, [<TypeAliasDeclaration type={MyDate} />])).toRenderTo(`
93
+ from datetime import datetime
94
+ from typing import TypeAlias
95
+
96
+
97
+ my_date: TypeAlias = datetime`);
98
+ });
99
+ });
100
+ });
101
+
102
+ describe("Type Alias Declaration for Operation (Callable)", () => {
103
+ it("creates a type alias for an operation type reference", async () => {
104
+ const { program, Handler } = await Tester.compile(t.code`
105
+ op handleRequest(id: string): string;
106
+ alias ${t.type("Handler")} = handleRequest;
107
+ `);
108
+
109
+ expect(getOutput(program, [<TypeAliasDeclaration type={Handler} />])).toRenderTo(`
110
+ from typing import Callable
111
+ from typing import TypeAlias
112
+
113
+
114
+ handle_request: TypeAlias = Callable[[str], str]`);
115
+ });
116
+ });
117
+ });
@@ -0,0 +1,67 @@
1
+ import { useTsp } from "#core/context/index.js";
2
+ import * as py from "@alloy-js/python";
3
+ import { isTemplateInstance, type Model, type Type } from "@typespec/compiler";
4
+ import { reportDiagnostic } from "../../../lib.js";
5
+ import { typingModule } from "../../builtins.js";
6
+ import { declarationRefkeys } from "../../utils/refkey.js";
7
+ import { ClassDeclaration } from "../class-declaration/class-declaration.js";
8
+ import { TypeExpression } from "../type-expression/type-expression.js";
9
+
10
+ export interface TypedAliasDeclarationProps extends Omit<py.BaseDeclarationProps, "name"> {
11
+ type: Type;
12
+ name?: string;
13
+ }
14
+
15
+ /**
16
+ * Create a Python type alias declaration. Pass the `type` prop to emit the
17
+ * type alias as the provided TypeSpec type.
18
+ *
19
+ * For template instances (e.g., `alias StringResponse = Response<string>`),
20
+ * this emits a dataclass instead of a type alias, since Python doesn't support
21
+ * parameterized type aliases the way TypeScript does.
22
+ */
23
+ export function TypeAliasDeclaration(props: TypedAliasDeclarationProps) {
24
+ const { $ } = useTsp();
25
+
26
+ const originalName =
27
+ props.name ??
28
+ ("name" in props.type && typeof props.type.name === "string" ? props.type.name : "");
29
+
30
+ if (!originalName || originalName === "") {
31
+ reportDiagnostic($.program, { code: "type-declaration-missing-name", target: props.type });
32
+ }
33
+
34
+ const doc = props.doc ?? $.type.getDoc(props.type);
35
+ const refkeys = declarationRefkeys(props.refkey, props.type);
36
+
37
+ // For Model template instances (e.g., alias StringResponse = Response<string>),
38
+ // emit as a dataclass since Python doesn't support parameterized type aliases.
39
+ // TypeSpec templates are macros that expand to concrete types.
40
+ if ($.model.is(props.type) && isTemplateInstance(props.type)) {
41
+ const namePolicy = py.usePythonNamePolicy();
42
+ const plausibleName = $.type.getPlausibleName(props.type as Model);
43
+ const name = props.name ?? namePolicy.getName(plausibleName, "class");
44
+
45
+ return (
46
+ <ClassDeclaration doc={doc} type={props.type} name={name} refkey={refkeys}>
47
+ {props.children}
48
+ </ClassDeclaration>
49
+ );
50
+ }
51
+
52
+ // For other types (scalars, unions, operations), emit as a type alias
53
+ const name = py.usePythonNamePolicy().getName(originalName, "variable");
54
+
55
+ return (
56
+ <py.VariableDeclaration
57
+ doc={doc}
58
+ name={name}
59
+ refkey={refkeys}
60
+ omitNone={true}
61
+ type={typingModule["."]["TypeAlias"]}
62
+ initializer={<TypeExpression type={props.type} noReference />}
63
+ >
64
+ {props.children}
65
+ </py.VariableDeclaration>
66
+ );
67
+ }
@@ -0,0 +1 @@
1
+ export * from "./type-declaration.js";
@@ -0,0 +1,58 @@
1
+ import { Tester } from "#test/test-host.js";
2
+ import { d } from "@alloy-js/core/testing";
3
+ import { t } from "@typespec/compiler/testing";
4
+ import { describe, expect, it } from "vitest";
5
+ import { getOutput } from "../../test-utils.js";
6
+ import { TypeDeclaration } from "./type-declaration.js";
7
+
8
+ describe("Python TypeDeclaration dispatcher", () => {
9
+ it("dispatches to EnumDeclaration for enums", async () => {
10
+ const { program, Foo } = await Tester.compile(t.code`
11
+ enum ${t.enum("Foo")} {
12
+ one: 1,
13
+ two: 2,
14
+ three: 3
15
+ }
16
+ `);
17
+
18
+ const output = getOutput(program, [<TypeDeclaration type={Foo} />]);
19
+ expect(output).toRenderTo(d`
20
+ from enum import IntEnum
21
+
22
+
23
+ class Foo(IntEnum):
24
+ ONE = 1
25
+ TWO = 2
26
+ THREE = 3
27
+
28
+
29
+ `);
30
+ });
31
+
32
+ it("dispatches scalars to TypeAliasDeclaration", async () => {
33
+ const { program, MyDate } = await Tester.compile(t.code`
34
+ scalar ${t.scalar("MyDate")} extends utcDateTime;
35
+ `);
36
+
37
+ const output = getOutput(program, [<TypeDeclaration type={MyDate} />]);
38
+ expect(output).toRenderTo(d`
39
+ from datetime import datetime
40
+ from typing import TypeAlias
41
+
42
+
43
+ my_date: TypeAlias = datetime`);
44
+ });
45
+
46
+ it("dispatches arrays (model is Array<T>) to type alias with list[T]", async () => {
47
+ const { program, Items } = await Tester.compile(t.code`
48
+ model ${t.model("Items")} is Array<int32>;
49
+ `);
50
+
51
+ const output = getOutput(program, [<TypeDeclaration type={Items} />]);
52
+ expect(output).toRenderTo(d`
53
+ from typing import TypeAlias
54
+
55
+
56
+ items: TypeAlias = list[int]`);
57
+ });
58
+ });
@@ -0,0 +1,26 @@
1
+ import { useTsp } from "#core/context/index.js";
2
+ import * as py from "@alloy-js/python";
3
+ import type { Type } from "@typespec/compiler";
4
+ import { EnumDeclaration } from "../enum-declaration/enum-declaration.js";
5
+ import { TypeAliasDeclaration } from "../type-alias-declaration/type-alias-declaration.js";
6
+
7
+ export interface TypeDeclarationProps extends Omit<py.BaseDeclarationProps, "name"> {
8
+ name?: string;
9
+ type: Type;
10
+ }
11
+
12
+ /**
13
+ * Single entry point to declare a Python symbol for any TypeSpec `Type`.
14
+ */
15
+ export function TypeDeclaration(props: TypeDeclarationProps) {
16
+ const { $ } = useTsp();
17
+ const { type, ...restProps } = props;
18
+ const doc = props.doc ?? $.type.getDoc(type);
19
+ switch (type.kind) {
20
+ case "Enum":
21
+ return <EnumDeclaration doc={doc} type={type} {...restProps} />;
22
+ default:
23
+ // All other kinds map to a Python type alias using TypeExpression
24
+ return <TypeAliasDeclaration doc={doc} type={type} {...restProps} />;
25
+ }
26
+ }
@@ -0,0 +1 @@
1
+ export * from "./type-expression.js";