@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,97 @@
1
+ import { type Children, createContext, splitProps, useContext } from "@alloy-js/core";
2
+ import * as py from "@alloy-js/python";
3
+ import type { Operation } from "@typespec/compiler";
4
+ import { useTsp } from "../../../core/index.js";
5
+ import { buildParameterDescriptors, getReturnType } from "../../utils/operation.js";
6
+ import { DocElement } from "../doc-element/doc-element.js";
7
+ import { TypeExpression } from "../type-expression/type-expression.js";
8
+
9
+ export const MethodContext = createContext<"method" | "static" | "class" | undefined>(undefined);
10
+ export const MethodProvider = MethodContext.Provider;
11
+
12
+ export interface MethodPropsWithType extends Omit<py.MethodDeclarationBaseProps, "name"> {
13
+ type: Operation;
14
+ name?: string;
15
+ doc?: Children;
16
+ methodType?: "method" | "class" | "static";
17
+ abstract?: boolean;
18
+ /** If true, parameters replaces operation parameters instead of adding to them as keyword-only */
19
+ replaceParameters?: boolean;
20
+ }
21
+
22
+ export type MethodProps = MethodPropsWithType | py.MethodDeclarationBaseProps;
23
+
24
+ /**
25
+ * Get the method component based on the resolved method type.
26
+ * We prioritize the methodType prop provided in the Method component,
27
+ * and then the one provided in the context, and then we default to "method".
28
+ */
29
+ function getResolvedMethodType(props: MethodProps): "method" | "class" | "static" {
30
+ const ctxMethodType = useContext(MethodContext);
31
+ const propMethodType = "methodType" in props ? (props as any).methodType : undefined;
32
+ return (propMethodType ?? ctxMethodType ?? "method") as "method" | "class" | "static";
33
+ }
34
+
35
+ /**
36
+ * A Python class method. Pass the `type` prop to create the
37
+ * method by converting from a TypeSpec Operation. Any other props
38
+ * provided will take precedence.
39
+ */
40
+ export function Method(props: Readonly<MethodProps>) {
41
+ const { $ } = useTsp();
42
+ const isTypeSpecTyped = "type" in props;
43
+ const type = isTypeSpecTyped ? props.type : undefined;
44
+ const docSource = props.doc ?? (type ? $.type.getDoc(type) : undefined);
45
+ const docElement = docSource ? (
46
+ <DocElement doc={docSource} component={py.MethodDoc} />
47
+ ) : undefined;
48
+ const resolvedMethodType = getResolvedMethodType(props);
49
+ const MethodComponent =
50
+ resolvedMethodType === "static"
51
+ ? py.StaticMethodDeclaration
52
+ : resolvedMethodType === "class"
53
+ ? py.ClassMethodDeclaration
54
+ : py.MethodDeclaration;
55
+
56
+ // Default to abstract when deriving from a TypeSpec operation (`type` prop present),
57
+ // unless explicitly overridden by props.abstract === false
58
+ const abstractFlag = (() => {
59
+ const explicit = (props as any).abstract as boolean | undefined;
60
+ return explicit ?? (!isTypeSpecTyped ? false : undefined);
61
+ })();
62
+
63
+ /**
64
+ * If the method does not come from the Typespec class declaration, return a standard Python method declaration.
65
+ * Have in mind that, with that, we lose some of the TypeSpec class declaration overrides.
66
+ */
67
+ if (!isTypeSpecTyped) {
68
+ return <MethodComponent {...props} doc={docElement} abstract={abstractFlag} />;
69
+ }
70
+
71
+ const [efProps, updateProps, forwardProps] = splitProps(
72
+ props,
73
+ ["type"],
74
+ ["returnType", "parameters"],
75
+ );
76
+
77
+ const name = props.name ?? py.usePythonNamePolicy().getName(efProps.type.name, "function");
78
+ const returnType = props.returnType ?? <TypeExpression type={getReturnType(efProps.type)} />;
79
+ const allParameters = buildParameterDescriptors(efProps.type.parameters, {
80
+ params: props.parameters,
81
+ replaceParameters: props.replaceParameters,
82
+ });
83
+
84
+ return (
85
+ <>
86
+ <MethodComponent
87
+ {...forwardProps}
88
+ {...updateProps}
89
+ name={name}
90
+ returnType={returnType}
91
+ parameters={allParameters}
92
+ doc={docElement}
93
+ abstract={abstractFlag}
94
+ />
95
+ </>
96
+ );
97
+ }
@@ -0,0 +1,6 @@
1
+ export * from "./class-bases.js";
2
+ export * from "./class-body.js";
3
+ export * from "./class-declaration.js";
4
+ export * from "./class-member.js";
5
+ export * from "./class-method.js";
6
+ export * from "./primitive-initializer.js";
@@ -0,0 +1,62 @@
1
+ import { type Children } from "@alloy-js/core";
2
+ import * as py from "@alloy-js/python";
3
+ import type { Type, Value } from "@typespec/compiler";
4
+ import { useTsp } from "../../../core/context/tsp-context.js";
5
+ import { Atom } from "../atom/atom.js";
6
+
7
+ export interface PrimitiveInitializerProps {
8
+ /**
9
+ * The default value to convert to a Python initializer expression.
10
+ */
11
+ defaultValue: Value;
12
+ /**
13
+ * The property type, used to determine float vs int formatting.
14
+ */
15
+ propertyType: Type;
16
+ }
17
+
18
+ /**
19
+ * Renders a Python primitive initializer from a TypeSpec default value.
20
+ *
21
+ * Handles StringValue, BooleanValue, NullValue, NumericValue, and ArrayValue.
22
+ * For numeric values, uses the propertyType to determine whether to render as float.
23
+ *
24
+ * @returns The Python initializer expression, or undefined if not supported.
25
+ */
26
+ export function PrimitiveInitializer(props: PrimitiveInitializerProps): Children | undefined {
27
+ const { $ } = useTsp();
28
+ const { defaultValue, propertyType } = props;
29
+
30
+ if (!defaultValue) return undefined;
31
+
32
+ const valueKind = (defaultValue as any).valueKind ?? (defaultValue as any).kind;
33
+ switch (valueKind) {
34
+ case "StringValue":
35
+ case "BooleanValue":
36
+ case "NullValue":
37
+ return <py.Atom jsValue={(defaultValue as any).value} />;
38
+ case "NumericValue": {
39
+ // The Atom component converts NumericValue via asNumber(), which normalizes 100.0 to 100.
40
+ // Atom also has no access to the field type (float vs int), so it can't decide when to keep a trailing .0.
41
+ // Here we do have the propertyType so, for float/decimal fields, we render a raw value and append ".0"
42
+ // when needed. For non-float fields, default to a plain numeric Atom.
43
+
44
+ // Unwrap potential numeric wrapper shape and preserve float formatting
45
+ let raw: any = (defaultValue as any).value;
46
+ // Example: value is { value: "100", isInteger: true }
47
+ if (raw && typeof raw === "object" && "value" in raw) raw = raw.value;
48
+
49
+ // Float-like property types (including custom subtypes) should render with float hint
50
+ if ($.scalar.extendsFloat(propertyType) || $.scalar.extendsDecimal(propertyType)) {
51
+ return <Atom value={defaultValue} float />;
52
+ }
53
+
54
+ // Otherwise output as a number atom
55
+ return <py.Atom jsValue={Number(raw)} />;
56
+ }
57
+ case "ArrayValue":
58
+ return <Atom value={defaultValue} />;
59
+ default:
60
+ return undefined;
61
+ }
62
+ }
@@ -0,0 +1,83 @@
1
+ import { type Children, type Component, List } from "@alloy-js/core";
2
+ import type { Type } from "@typespec/compiler";
3
+ import { useTsp } from "../../../core/context/tsp-context.js";
4
+
5
+ export interface DocElementProps {
6
+ /**
7
+ * The TypeSpec type to get documentation from.
8
+ * If provided and no `doc` override is given, documentation will be
9
+ * fetched via `$.type.getDoc(type)`.
10
+ */
11
+ type?: Type;
12
+
13
+ /**
14
+ * Optional documentation override. If provided, this takes precedence
15
+ * over documentation from the `type` prop.
16
+ *
17
+ * Accepts:
18
+ * - string - split into lines and render as a multi-line docstring
19
+ * - string[] | Children[] - rendered as separate paragraphs
20
+ * - Children (e.g., an explicit Doc component) - returned as-is
21
+ */
22
+ doc?: string | string[] | Children | Children[];
23
+
24
+ /**
25
+ * The Python doc component to use for rendering (ClassDoc, FunctionDoc, MethodDoc, etc.)
26
+ */
27
+ component: Component<{ description: Children[] }>;
28
+ }
29
+
30
+ /**
31
+ * Renders documentation for a Python declaration.
32
+ *
33
+ * This component handles fetching documentation from TypeSpec types and
34
+ * normalizing various doc formats into the appropriate Python doc component.
35
+ *
36
+ * @example
37
+ * ```tsx
38
+ * // With a TypeSpec type (fetches doc automatically)
39
+ * <DocElement type={model} component={py.ClassDoc} />
40
+ *
41
+ * // With an explicit doc override
42
+ * <DocElement doc="My custom documentation" component={py.FunctionDoc} />
43
+ *
44
+ * // With both (doc takes precedence)
45
+ * <DocElement type={model} doc={props.doc} component={py.ClassDoc} />
46
+ * ```
47
+ */
48
+ export function DocElement(props: DocElementProps): Children {
49
+ const { $ } = useTsp();
50
+
51
+ // Resolve the documentation source: explicit doc takes precedence over type-derived doc
52
+ const source = props.doc ?? (props.type ? $.type.getDoc(props.type) : undefined);
53
+
54
+ if (!source) {
55
+ return undefined;
56
+ }
57
+
58
+ const DocComponent = props.component;
59
+
60
+ // Doc provided as an array (paragraphs/nodes) - preserve structure
61
+ if (Array.isArray(source)) {
62
+ return <DocComponent description={source as Children[]} />;
63
+ }
64
+
65
+ // Doc provided as a string - preserve line breaks
66
+ if (typeof source === "string") {
67
+ const lines = source.split(/\r?\n/);
68
+ return (
69
+ <DocComponent
70
+ description={[
71
+ <List hardline>
72
+ {lines.map((line) => (
73
+ <>{line}</>
74
+ ))}
75
+ </List>,
76
+ ]}
77
+ />
78
+ );
79
+ }
80
+
81
+ // Doc provided as JSX - pass through unchanged
82
+ return source as Children;
83
+ }
@@ -0,0 +1 @@
1
+ export * from "./doc-element.js";
@@ -0,0 +1,319 @@
1
+ import { efRefkey } from "#python/utils/refkey.js";
2
+ import { Tester } from "#test/test-host.js";
3
+ import { d } from "@alloy-js/core/testing";
4
+ import * as py from "@alloy-js/python";
5
+ import { t } from "@typespec/compiler/testing";
6
+ import { describe, expect, it } from "vitest";
7
+ import { getOutput } from "../../test-utils.js";
8
+ import { EnumDeclaration } from "./enum-declaration.js";
9
+
10
+ describe("Python Enum Declaration", () => {
11
+ it("takes an enum type parameter", async () => {
12
+ const { program, Foo } = await Tester.compile(t.code`
13
+ enum ${t.enum("Foo")} {
14
+ one: 1,
15
+ two: 2,
16
+ three: 3
17
+ }
18
+ `);
19
+
20
+ expect(getOutput(program, [<EnumDeclaration type={Foo} />])).toRenderTo(d`
21
+ from enum import IntEnum
22
+
23
+
24
+ class Foo(IntEnum):
25
+ ONE = 1
26
+ TWO = 2
27
+ THREE = 3
28
+
29
+
30
+ `);
31
+ });
32
+
33
+ it("adds Python doc from TypeSpec", async () => {
34
+ const { program, Foo } = await Tester.compile(t.code`
35
+ /**
36
+ * This is a test enum
37
+ */
38
+ enum ${t.enum("Foo")} {
39
+ @doc("This is one")
40
+ one: 1,
41
+ two: 2,
42
+ three: 3
43
+ }
44
+ `);
45
+ const output = getOutput(program, [<EnumDeclaration type={Foo} />]);
46
+
47
+ expect(output).toRenderTo(d`
48
+ from enum import IntEnum
49
+
50
+
51
+ class Foo(IntEnum):
52
+ """
53
+ This is a test enum
54
+ """
55
+
56
+ ONE = 1
57
+ """
58
+ This is one
59
+ """
60
+ TWO = 2
61
+ THREE = 3
62
+
63
+
64
+ `);
65
+ });
66
+
67
+ it("explicit doc take precedence", async () => {
68
+ const { program, Foo } = await Tester.compile(t.code`
69
+ /**
70
+ * This is a test enum
71
+ */
72
+ enum ${t.enum("Foo")} {
73
+ @doc("This is one")
74
+ one: 1,
75
+ two: 2,
76
+ three: 3
77
+ }
78
+ `);
79
+ const output = getOutput(program, [
80
+ <EnumDeclaration type={Foo} doc={["This is an explicit doc"]} />,
81
+ ]);
82
+
83
+ expect(output).toRenderTo(d`
84
+ from enum import IntEnum
85
+
86
+
87
+ class Foo(IntEnum):
88
+ """
89
+ This is an explicit doc
90
+ """
91
+
92
+ ONE = 1
93
+ """
94
+ This is one
95
+ """
96
+ TWO = 2
97
+ THREE = 3
98
+
99
+
100
+ `);
101
+ });
102
+
103
+ it("takes a union type parameter", async () => {
104
+ const { program, Foo } = await Tester.compile(t.code`
105
+ union ${t.union("Foo")} {
106
+ one: 1,
107
+ two: 2,
108
+ three: 3
109
+ }
110
+ `);
111
+ const output = getOutput(program, [<EnumDeclaration type={Foo} />]);
112
+
113
+ expect(output).toRenderTo(d`
114
+ from enum import IntEnum
115
+
116
+
117
+ class Foo(IntEnum):
118
+ ONE = 1
119
+ TWO = 2
120
+ THREE = 3
121
+
122
+
123
+ `);
124
+ });
125
+
126
+ it("can be referenced", async () => {
127
+ const { program, Foo } = await Tester.compile(t.code`
128
+ enum ${t.enum("Foo")} {
129
+ one: 1,
130
+ two: 2,
131
+ three: 3
132
+ }
133
+ `);
134
+
135
+ const output = getOutput(program, [
136
+ <EnumDeclaration type={Foo} />,
137
+ <py.StatementList>
138
+ {efRefkey(Foo)}
139
+ {efRefkey(Foo.members.get("one"))}
140
+ </py.StatementList>,
141
+ ]);
142
+
143
+ expect(output).toRenderTo(d`
144
+ from enum import IntEnum
145
+
146
+
147
+ class Foo(IntEnum):
148
+ ONE = 1
149
+ TWO = 2
150
+ THREE = 3
151
+
152
+
153
+ Foo
154
+ Foo.ONE
155
+ `);
156
+ });
157
+
158
+ it("can be referenced using union", async () => {
159
+ const { program, Foo } = await Tester.compile(t.code`
160
+ union ${t.union("Foo")} {
161
+ one: 1,
162
+ two: 2,
163
+ three: 3
164
+ }
165
+ `);
166
+
167
+ const output = getOutput(program, [
168
+ <EnumDeclaration type={Foo} />,
169
+ <py.StatementList>
170
+ {efRefkey(Foo)}
171
+ {efRefkey(Foo.variants.get("one"))}
172
+ </py.StatementList>,
173
+ ]);
174
+
175
+ expect(output).toRenderTo(d`
176
+ from enum import IntEnum
177
+
178
+
179
+ class Foo(IntEnum):
180
+ ONE = 1
181
+ TWO = 2
182
+ THREE = 3
183
+
184
+
185
+ Foo
186
+ Foo.ONE
187
+ `);
188
+ });
189
+
190
+ describe("Enum Type Detection", () => {
191
+ it("generates IntEnum if all values are integer values", async () => {
192
+ const { program, StatusCode } = await Tester.compile(t.code`
193
+ enum ${t.enum("StatusCode")} {
194
+ success: 200,
195
+ notFound: 404,
196
+ serverError: 500
197
+ }
198
+ `);
199
+ const output = getOutput(program, [<EnumDeclaration type={StatusCode} />]);
200
+
201
+ expect(output).toRenderTo(d`
202
+ from enum import IntEnum
203
+
204
+
205
+ class StatusCode(IntEnum):
206
+ SUCCESS = 200
207
+ NOT_FOUND = 404
208
+ SERVER_ERROR = 500
209
+
210
+
211
+ `);
212
+ });
213
+
214
+ it("generates StrEnum if all values are string values", async () => {
215
+ const { program, Color } = await Tester.compile(t.code`
216
+ enum ${t.enum("Color")} {
217
+ red: "red",
218
+ green: "green",
219
+ blue: "blue"
220
+ }
221
+ `);
222
+ const output = getOutput(program, [<EnumDeclaration type={Color} />]);
223
+
224
+ expect(output).toRenderTo(d`
225
+ from enum import StrEnum
226
+
227
+
228
+ class Color(StrEnum):
229
+ RED = "red"
230
+ GREEN = "green"
231
+ BLUE = "blue"
232
+
233
+
234
+ `);
235
+ });
236
+
237
+ it("generates StrEnum if all values are string values with custom values", async () => {
238
+ const { program, Color } = await Tester.compile(t.code`
239
+ enum ${t.enum("Color")} {
240
+ red: "This is red",
241
+ green: "This is green",
242
+ blue: "This is blue"
243
+ }
244
+ `);
245
+ const output = getOutput(program, [
246
+ <EnumDeclaration type={Color} />,
247
+ <py.StatementList>
248
+ {efRefkey(Color.members.get("red"))}
249
+ {efRefkey(Color.members.get("green"))}
250
+ {efRefkey(Color.members.get("blue"))}
251
+ </py.StatementList>,
252
+ ]);
253
+
254
+ expect(output).toRenderTo(d`
255
+ from enum import StrEnum
256
+
257
+
258
+ class Color(StrEnum):
259
+ RED = "This is red"
260
+ GREEN = "This is green"
261
+ BLUE = "This is blue"
262
+
263
+
264
+ Color.RED
265
+ Color.GREEN
266
+ Color.BLUE
267
+
268
+ `);
269
+ });
270
+
271
+ it("generates Enum for mixed value types", async () => {
272
+ const { program, Mixed } = await Tester.compile(t.code`
273
+ enum ${t.enum("Mixed")} {
274
+ stringValue: "hello",
275
+ numericValue: 42,
276
+ autoValue
277
+ }
278
+ `);
279
+ const output = getOutput(program, [<EnumDeclaration type={Mixed} />]);
280
+
281
+ expect(output).toRenderTo(d`
282
+ from enum import auto
283
+ from enum import Enum
284
+
285
+
286
+ class Mixed(Enum):
287
+ STRING_VALUE = "hello"
288
+ NUMERIC_VALUE = 42
289
+ AUTO_VALUE = auto()
290
+
291
+
292
+ `);
293
+ });
294
+
295
+ it("handles correctly enums without values", async () => {
296
+ const { program, EnumWithoutValues } = await Tester.compile(t.code`
297
+ enum ${t.enum("EnumWithoutValues")} {
298
+ someValue,
299
+ anotherValue,
300
+ yetAnotherValue
301
+ }
302
+ `);
303
+ const output = getOutput(program, [<EnumDeclaration type={EnumWithoutValues} />]);
304
+
305
+ expect(output).toRenderTo(d`
306
+ from enum import auto
307
+ from enum import Enum
308
+
309
+
310
+ class EnumWithoutValues(Enum):
311
+ SOME_VALUE = auto()
312
+ ANOTHER_VALUE = auto()
313
+ YET_ANOTHER_VALUE = auto()
314
+
315
+
316
+ `);
317
+ });
318
+ });
319
+ });
@@ -0,0 +1,77 @@
1
+ import { useTsp } from "#core/context/index.js";
2
+ import { For, Prose } from "@alloy-js/core";
3
+ import * as py from "@alloy-js/python";
4
+ import type { Enum, EnumMember as TspEnumMember, Union } from "@typespec/compiler";
5
+ import { reportDiagnostic } from "../../../lib.js";
6
+ import { declarationRefkeys, efRefkey } from "../../utils/refkey.js";
7
+ import { EnumMember } from "./enum-member.js";
8
+
9
+ export interface EnumDeclarationProps extends Omit<py.BaseDeclarationProps, "name"> {
10
+ name?: string;
11
+ type: Union | Enum;
12
+ }
13
+
14
+ // Determine the appropriate enum type based on the member values
15
+ function determineEnumType(
16
+ members: Array<[string, TspEnumMember]>,
17
+ ): "IntEnum" | "StrEnum" | "Enum" {
18
+ const allInteger = members.every(([, member]) => {
19
+ const value = member.value;
20
+ return typeof value === "number" && Number.isInteger(value);
21
+ });
22
+
23
+ const allString = members.every(([, member]) => {
24
+ const value = member.value;
25
+ return typeof value === "string";
26
+ });
27
+
28
+ if (allInteger) {
29
+ return "IntEnum";
30
+ } else if (allString) {
31
+ return "StrEnum";
32
+ } else {
33
+ return "Enum";
34
+ }
35
+ }
36
+
37
+ export function EnumDeclaration(props: EnumDeclarationProps) {
38
+ const { $ } = useTsp();
39
+ let type: Enum;
40
+ if ($.union.is(props.type)) {
41
+ if (!$.union.isValidEnum(props.type)) {
42
+ throw new Error("The provided union type cannot be represented as an enum");
43
+ }
44
+ type = $.enum.createFromUnion(props.type);
45
+ } else {
46
+ type = props.type;
47
+ }
48
+
49
+ if (!props.type.name) {
50
+ reportDiagnostic($.program, { code: "type-declaration-missing-name", target: props.type });
51
+ }
52
+ const refkeys = declarationRefkeys(props.refkey, props.type);
53
+ const name = props.name ?? py.usePythonNamePolicy().getName(props.type.name!, "enum");
54
+ const members = Array.from(type.members.entries());
55
+ const doc = props.doc ?? $.type.getDoc(type);
56
+ const docElement = doc ? <py.ClassDoc description={[<Prose>{doc}</Prose>]} /> : undefined;
57
+ const enumType = determineEnumType(members);
58
+
59
+ return (
60
+ <py.ClassEnumDeclaration doc={docElement} name={name} refkey={refkeys} baseType={enumType}>
61
+ <For each={members} hardline>
62
+ {([key, value]) => {
63
+ const memberDoc = $.type.getDoc(value);
64
+ return (
65
+ <EnumMember
66
+ doc={memberDoc}
67
+ type={value}
68
+ refkey={
69
+ $.union.is(props.type) ? efRefkey(props.type.variants.get(key)) : efRefkey(value)
70
+ }
71
+ />
72
+ );
73
+ }}
74
+ </For>
75
+ </py.ClassEnumDeclaration>
76
+ );
77
+ }
@@ -0,0 +1,21 @@
1
+ import { type Children, type Refkey } from "@alloy-js/core";
2
+ import * as py from "@alloy-js/python";
3
+ import type { EnumMember as TspEnumMember } from "@typespec/compiler";
4
+
5
+ export interface EnumMemberProps {
6
+ type: TspEnumMember;
7
+ doc?: Children;
8
+ refkey?: Refkey;
9
+ }
10
+
11
+ export function EnumMember(props: EnumMemberProps) {
12
+ return (
13
+ <py.EnumMember
14
+ doc={props.doc}
15
+ name={props.type.name}
16
+ jsValue={props.type.value}
17
+ refkey={props.refkey}
18
+ auto={props.type.value === undefined}
19
+ />
20
+ );
21
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./enum-declaration.js";
2
+ export * from "./enum-member.js";