@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,582 @@
1
+ import { getOutput } from "#python/test-utils.js";
2
+ import { Tester } from "#test/test-host.js";
3
+ import * as py from "@alloy-js/python";
4
+ import { t } from "@typespec/compiler/testing";
5
+ import { describe, expect, it } from "vitest";
6
+ import { FunctionDeclaration } from "./function-declaration.js";
7
+
8
+ describe("Python Function Declaration", () => {
9
+ it("creates a function with single positional param", async () => {
10
+ const { program, getName } = await Tester.compile(t.code`
11
+ op ${t.op("getName")}(id: string): string;
12
+ `);
13
+
14
+ expect(getOutput(program, [<FunctionDeclaration type={getName} />])).toRenderTo(`
15
+ def get_name(id: str) -> str:
16
+ pass
17
+
18
+ `);
19
+ });
20
+
21
+ it("creates an async function", async () => {
22
+ const { program, getName } = await Tester.compile(t.code`
23
+ op ${t.op("getName")}(id: string): string;
24
+ `);
25
+
26
+ expect(getOutput(program, [<FunctionDeclaration async type={getName} />])).toRenderTo(`
27
+ async def get_name(id: str) -> str:
28
+ pass
29
+
30
+ `);
31
+ });
32
+
33
+ it("creates a function with a custom name", async () => {
34
+ const { program, getName } = await Tester.compile(t.code`
35
+ op ${t.op("getName")}(id: string): string;
36
+ `);
37
+
38
+ expect(getOutput(program, [<FunctionDeclaration name="new_name" type={getName} />]))
39
+ .toRenderTo(`
40
+ def new_name(id: str) -> str:
41
+ pass
42
+
43
+ `);
44
+ });
45
+
46
+ it("creates a function with additional keyword-only parameters", async () => {
47
+ const { program, createPerson } = await Tester.compile(t.code`
48
+ op ${t.op("createPerson")}(id: string): string;
49
+ `);
50
+
51
+ expect(
52
+ getOutput(program, [
53
+ <FunctionDeclaration
54
+ type={createPerson}
55
+ parameters={[
56
+ { name: "name", type: "str" },
57
+ { name: "age", type: "float" },
58
+ ]}
59
+ />,
60
+ ]),
61
+ ).toRenderTo(`
62
+ def create_person(id: str, *, name: str, age: float) -> str:
63
+ pass
64
+
65
+ `);
66
+ });
67
+
68
+ it("creates a function with additional keyword-only parameters (string shorthand)", async () => {
69
+ const { program, createPerson } = await Tester.compile(t.code`
70
+ op ${t.op("createPerson")}(id: string): string;
71
+ `);
72
+
73
+ expect(
74
+ getOutput(program, [
75
+ <FunctionDeclaration type={createPerson} parameters={["name", "age"]} />,
76
+ ]),
77
+ ).toRenderTo(`
78
+ def create_person(id: str, *, name, age) -> str:
79
+ pass
80
+
81
+ `);
82
+ });
83
+
84
+ it("creates a function replacing parameters with raw params provided", async () => {
85
+ const { program, createPerson } = await Tester.compile(t.code`
86
+ op ${t.op("createPerson")}(id: string): string;
87
+ `);
88
+
89
+ expect(
90
+ getOutput(program, [
91
+ <FunctionDeclaration
92
+ type={createPerson}
93
+ parameters={["name", "age"]}
94
+ replaceParameters={true}
95
+ />,
96
+ ]),
97
+ ).toRenderTo(`
98
+ def create_person(*, name, age) -> str:
99
+ pass
100
+
101
+ `);
102
+ });
103
+
104
+ it("creates a function replacing parameters with params having defaults (requires * marker)", async () => {
105
+ const { program, createPerson } = await Tester.compile(t.code`
106
+ op ${t.op("createPerson")}(id: string): string;
107
+ `);
108
+
109
+ expect(
110
+ getOutput(program, [
111
+ <FunctionDeclaration
112
+ type={createPerson}
113
+ parameters={[
114
+ { name: "name", type: "str", default: <py.Atom jsValue={"alice"} /> },
115
+ { name: "age", type: "int", default: <py.Atom jsValue={30} /> },
116
+ ]}
117
+ replaceParameters={true}
118
+ />,
119
+ ]),
120
+ ).toRenderTo(`
121
+ def create_person(*, name: str = "alice", age: int = 30) -> str:
122
+ pass
123
+
124
+ `);
125
+ });
126
+
127
+ it("creates a function with defaults in raw parameter descriptors", async () => {
128
+ const { program, createPerson } = await Tester.compile(t.code`
129
+ op ${t.op("createPerson")}(id: string, locale: string = "en-US"): string;
130
+ `);
131
+
132
+ expect(
133
+ getOutput(program, [
134
+ <FunctionDeclaration
135
+ type={createPerson}
136
+ parameters={[
137
+ { name: "limit", type: "int", default: <py.Atom jsValue={10} /> },
138
+ { name: "verbose", type: "bool", default: <py.Atom jsValue={true} /> },
139
+ ]}
140
+ />,
141
+ ]),
142
+ ).toRenderTo(`
143
+ def create_person(id: str, *, locale: str = "en-US", limit: int = 10, verbose: bool = True) -> str:
144
+ pass
145
+
146
+ `);
147
+ });
148
+
149
+ it("creates a function building parameters from a model via parametersModel (will replace parameters)", async () => {
150
+ const { program, createPerson, Foo } = await Tester.compile(t.code`
151
+ op ${t.op("createPerson")}(id: string): string;
152
+
153
+ model ${t.model("Foo")} {
154
+ name: string;
155
+ age: int32;
156
+ }
157
+ `);
158
+
159
+ expect(getOutput(program, [<FunctionDeclaration type={createPerson} parametersModel={Foo} />]))
160
+ .toRenderTo(`
161
+ def create_person(name: str, age: int) -> str:
162
+ pass
163
+
164
+ `);
165
+ });
166
+
167
+ it("creates a function with parametersModel applying defaults and optionals", async () => {
168
+ const { program, createPerson, Foo } = await Tester.compile(t.code`
169
+ op ${t.op("createPerson")}(id: string): string;
170
+
171
+ model ${t.model("Foo")} {
172
+ requiredName?: string = "alice";
173
+ optionalAge?: int32;
174
+ }
175
+ `);
176
+
177
+ expect(getOutput(program, [<FunctionDeclaration type={createPerson} parametersModel={Foo} />]))
178
+ .toRenderTo(`
179
+ def create_person(*, required_name: str = "alice", optional_age: int = None) -> str:
180
+ pass
181
+
182
+ `);
183
+ });
184
+
185
+ it("creates a function that replaces parameters with parametersModel even when extras are provided", async () => {
186
+ const { program, createPerson, Foo } = await Tester.compile(t.code`
187
+ op ${t.op("createPerson")}(id: string): string;
188
+
189
+ model ${t.model("Foo")} {
190
+ name: string;
191
+ age: int32;
192
+ }
193
+ `);
194
+
195
+ expect(
196
+ getOutput(program, [
197
+ <FunctionDeclaration type={createPerson} parametersModel={Foo} parameters={["extra"]} />,
198
+ ]),
199
+ ).toRenderTo(`
200
+ def create_person(name: str, age: int) -> str:
201
+ pass
202
+
203
+ `);
204
+ });
205
+
206
+ it("creates a function overriding the return type", async () => {
207
+ const { program, getName } = await Tester.compile(t.code`
208
+ op ${t.op("getName")}(id: string): string;
209
+ `);
210
+
211
+ expect(getOutput(program, [<FunctionDeclaration type={getName} returnType="ASpecialString" />]))
212
+ .toRenderTo(`
213
+ def get_name(id: str) -> ASpecialString:
214
+ pass
215
+
216
+ `);
217
+ });
218
+ it("creates a function with body", async () => {
219
+ const { program, createPerson } = await Tester.compile(t.code`
220
+ op ${t.op("createPerson")}(id: string): string;
221
+ `);
222
+
223
+ expect(
224
+ getOutput(program, [
225
+ <FunctionDeclaration type={createPerson}>
226
+ <>print("Hello World!")</>
227
+ </FunctionDeclaration>,
228
+ ]),
229
+ ).toRenderTo(`
230
+ def create_person(id: str) -> str:
231
+ print("Hello World!")
232
+
233
+ `);
234
+ });
235
+
236
+ it("creates a function with a doc", async () => {
237
+ const { program, getName } = await Tester.compile(t.code`
238
+ op ${t.op("getName")}(id: string): string;
239
+ `);
240
+
241
+ expect(getOutput(program, [<FunctionDeclaration type={getName} doc={"This is a test doc"} />]))
242
+ .toRenderTo(`
243
+ def get_name(id: str) -> str:
244
+ """
245
+ This is a test doc
246
+ """
247
+
248
+ pass
249
+
250
+ `);
251
+ });
252
+
253
+ it("creates a function with a multi-paragraph FunctionDoc", async () => {
254
+ const { program, getName } = await Tester.compile(t.code`
255
+ op ${t.op("getName")}(id: string): string;
256
+ `);
257
+
258
+ expect(
259
+ getOutput(program, [
260
+ <FunctionDeclaration
261
+ type={getName}
262
+ doc={<py.FunctionDoc description={[<>First paragraph</>, <>Second paragraph</>]} />}
263
+ />,
264
+ ]),
265
+ ).toRenderTo(`
266
+ def get_name(id: str) -> str:
267
+ """
268
+ First paragraph
269
+
270
+ Second paragraph
271
+ """
272
+
273
+ pass
274
+
275
+ `);
276
+ });
277
+
278
+ it("creates a function with doc as string[]", async () => {
279
+ const { program, getName } = await Tester.compile(t.code`
280
+ op ${t.op("getName")}(id: string): string;
281
+ `);
282
+
283
+ expect(
284
+ getOutput(program, [
285
+ <FunctionDeclaration type={getName} doc={["First paragraph", "Second paragraph"]} />,
286
+ ]),
287
+ ).toRenderTo(`
288
+ def get_name(id: str) -> str:
289
+ """
290
+ First paragraph
291
+
292
+ Second paragraph
293
+ """
294
+
295
+ pass
296
+
297
+ `);
298
+ });
299
+
300
+ it("creates a function with doc as Children[]", async () => {
301
+ const { program, getName } = await Tester.compile(t.code`
302
+ op ${t.op("getName")}(id: string): string;
303
+ `);
304
+
305
+ expect(
306
+ getOutput(program, [
307
+ <FunctionDeclaration type={getName} doc={[<>First paragraph</>, <>Second paragraph</>]} />,
308
+ ]),
309
+ ).toRenderTo(`
310
+ def get_name(id: str) -> str:
311
+ """
312
+ First paragraph
313
+
314
+ Second paragraph
315
+ """
316
+
317
+ pass
318
+
319
+ `);
320
+ });
321
+
322
+ it("creates a function with doc lines (string with newlines)", async () => {
323
+ const { program, getName } = await Tester.compile(t.code`
324
+ op ${t.op("getName")}(id: string): string;
325
+ `);
326
+
327
+ expect(getOutput(program, [<FunctionDeclaration type={getName} doc={"Line 1\nLine 2"} />]))
328
+ .toRenderTo(`
329
+ def get_name(id: str) -> str:
330
+ """
331
+ Line 1
332
+ Line 2
333
+ """
334
+
335
+ pass
336
+
337
+ `);
338
+ });
339
+
340
+ it("creates a function with no parameters", async () => {
341
+ const { program, ping } = await Tester.compile(t.code`
342
+ op ${t.op("ping")}(): string;
343
+ `);
344
+
345
+ expect(getOutput(program, [<FunctionDeclaration type={ping} />])).toRenderTo(`
346
+ def ping() -> str:
347
+ pass
348
+
349
+ `);
350
+ });
351
+
352
+ it("creates a function that returns None for void", async () => {
353
+ const { program, ping } = await Tester.compile(t.code`
354
+ op ${t.op("ping")}(): void;
355
+ `);
356
+
357
+ expect(getOutput(program, [<FunctionDeclaration type={ping} />])).toRenderTo(`
358
+ def ping() -> None:
359
+ pass
360
+
361
+ `);
362
+ });
363
+
364
+ it("creates a function that returns Never for never", async () => {
365
+ const { program, abort } = await Tester.compile(t.code`
366
+ op ${t.op("abort")}(): never;
367
+ `);
368
+
369
+ expect(getOutput(program, [<FunctionDeclaration type={abort} />])).toRenderTo(`
370
+ from typing import Never
371
+
372
+
373
+ def abort() -> Never:
374
+ pass
375
+
376
+ `);
377
+ });
378
+
379
+ it("creates a function that correctly handles simple unions", async () => {
380
+ const { program, get } = await Tester.compile(t.code`
381
+ op ${t.op("get")}(): int32 | string;
382
+ `);
383
+
384
+ expect(getOutput(program, [<FunctionDeclaration type={get} />])).toRenderTo(`
385
+ def get() -> int | str:
386
+ pass
387
+
388
+ `);
389
+ });
390
+
391
+ it("creates a function with only keyword-only parameters (requires * marker for params with defaults)", async () => {
392
+ const { program, createPerson } = await Tester.compile(t.code`
393
+ op ${t.op("createPerson")}(name: string = "alice", age: int32 = 30): string;
394
+ `);
395
+
396
+ expect(getOutput(program, [<FunctionDeclaration type={createPerson} />])).toRenderTo(`
397
+ def create_person(*, name: str = "alice", age: int = 30) -> str:
398
+ pass
399
+
400
+ `);
401
+ });
402
+
403
+ it("creates a function with operation params positional and additional params keyword-only", async () => {
404
+ const { program, createPerson } = await Tester.compile(t.code`
405
+ op ${t.op("createPerson")}(id: string, locale: string = "en-US"): string;
406
+ `);
407
+
408
+ expect(
409
+ getOutput(program, [
410
+ <FunctionDeclaration
411
+ type={createPerson}
412
+ parameters={[
413
+ { name: "version", type: "int" },
414
+ { name: "debug", type: "bool", default: <py.Atom jsValue={false} /> },
415
+ ]}
416
+ />,
417
+ ]),
418
+ ).toRenderTo(`
419
+ def create_person(id: str, *, version: int, locale: str = "en-US", debug: bool = False) -> str:
420
+ pass
421
+
422
+ `);
423
+ });
424
+
425
+ it("creates a function with TSP params in wrong order (default before required) - reorders correctly", async () => {
426
+ const { program, createPerson } = await Tester.compile(t.code`
427
+ op ${t.op("createPerson")}(locale: string = "en-US", id: string): string;
428
+ `);
429
+
430
+ expect(getOutput(program, [<FunctionDeclaration type={createPerson} />])).toRenderTo(`
431
+ def create_person(id: str, *, locale: str = "en-US") -> str:
432
+ pass
433
+
434
+ `);
435
+ });
436
+
437
+ it("creates a function with only positional params when adding params to empty operation", async () => {
438
+ const { program, ping } = await Tester.compile(t.code`
439
+ op ${t.op("ping")}(): string;
440
+ `);
441
+
442
+ expect(getOutput(program, [<FunctionDeclaration type={ping} parameters={["name", "age"]} />]))
443
+ .toRenderTo(`
444
+ def ping(name, age) -> str:
445
+ pass
446
+
447
+ `);
448
+ });
449
+
450
+ it("creates a function with multiple positional params", async () => {
451
+ const { program, createPerson } = await Tester.compile(t.code`
452
+ op ${t.op("createPerson")}(id: string, name: string, age: int32): string;
453
+ `);
454
+
455
+ expect(getOutput(program, [<FunctionDeclaration type={createPerson} />])).toRenderTo(`
456
+ def create_person(id: str, name: str, age: int) -> str:
457
+ pass
458
+
459
+ `);
460
+ });
461
+
462
+ it("creates a function adding keyword-only params to operation with only positional params", async () => {
463
+ const { program, createPerson } = await Tester.compile(t.code`
464
+ op ${t.op("createPerson")}(id: string, name: string): string;
465
+ `);
466
+
467
+ expect(
468
+ getOutput(program, [
469
+ <FunctionDeclaration
470
+ type={createPerson}
471
+ parameters={[
472
+ "email",
473
+ { name: "notify", type: "bool", default: <py.Atom jsValue={false} /> },
474
+ ]}
475
+ />,
476
+ ]),
477
+ ).toRenderTo(`
478
+ def create_person(id: str, name: str, *, email, notify: bool = False) -> str:
479
+ pass
480
+
481
+ `);
482
+ });
483
+
484
+ it("creates a function with multiple params with defaults (all keyword-only)", async () => {
485
+ const { program, search } = await Tester.compile(t.code`
486
+ op ${t.op("search")}(
487
+ limit: int32 = 10,
488
+ offset: int32 = 0,
489
+ sortBy: string = "name"
490
+ ): string;
491
+ `);
492
+
493
+ expect(getOutput(program, [<FunctionDeclaration type={search} />])).toRenderTo(`
494
+ def search(*, limit: int = 10, offset: int = 0, sort_by: str = "name") -> str:
495
+ pass
496
+
497
+ `);
498
+ });
499
+
500
+ it("creates a function adding params without defaults to operation with only defaults", async () => {
501
+ const { program, search } = await Tester.compile(t.code`
502
+ op ${t.op("search")}(limit: int32 = 10, offset: int32 = 0): string;
503
+ `);
504
+
505
+ expect(getOutput(program, [<FunctionDeclaration type={search} parameters={["query"]} />]))
506
+ .toRenderTo(`
507
+ def search(*, query, limit: int = 10, offset: int = 0) -> str:
508
+ pass
509
+
510
+ `);
511
+ });
512
+
513
+ it("creates a function with complex parameter mix", async () => {
514
+ const { program, complexOp } = await Tester.compile(t.code`
515
+ op ${t.op("complexOp")}(
516
+ required1: string,
517
+ required2: int32,
518
+ optional1: string = "default",
519
+ optional2: int32 = 42
520
+ ): string;
521
+ `);
522
+
523
+ expect(
524
+ getOutput(program, [
525
+ <FunctionDeclaration
526
+ type={complexOp}
527
+ parameters={[
528
+ "additionalRequired",
529
+ { name: "additionalOptional", type: "bool", default: <py.Atom jsValue={true} /> },
530
+ ]}
531
+ />,
532
+ ]),
533
+ ).toRenderTo(`
534
+ def complex_op(required1: str, required2: int, *, additional_required, optional1: str = "default", optional2: int = 42, additional_optional: bool = True) -> str:
535
+ pass
536
+
537
+ `);
538
+ });
539
+
540
+ it("creates a function with single positional param and additional keyword-only", async () => {
541
+ const { program, getUser } = await Tester.compile(t.code`
542
+ op ${t.op("getUser")}(id: string): string;
543
+ `);
544
+
545
+ expect(
546
+ getOutput(program, [
547
+ <FunctionDeclaration
548
+ type={getUser}
549
+ parameters={[
550
+ { name: "includeDeleted", type: "bool", default: <py.Atom jsValue={false} /> },
551
+ ]}
552
+ />,
553
+ ]),
554
+ ).toRenderTo(`
555
+ def get_user(id: str, *, include_deleted: bool = False) -> str:
556
+ pass
557
+
558
+ `);
559
+ });
560
+
561
+ it("creates a function adding only params with defaults to empty operation", async () => {
562
+ const { program, ping } = await Tester.compile(t.code`
563
+ op ${t.op("ping")}(): string;
564
+ `);
565
+
566
+ expect(
567
+ getOutput(program, [
568
+ <FunctionDeclaration
569
+ type={ping}
570
+ parameters={[
571
+ { name: "timeout", type: "int", default: <py.Atom jsValue={30} /> },
572
+ { name: "retries", type: "int", default: <py.Atom jsValue={3} /> },
573
+ ]}
574
+ />,
575
+ ]),
576
+ ).toRenderTo(`
577
+ def ping(*, timeout: int = 30, retries: int = 3) -> str:
578
+ pass
579
+
580
+ `);
581
+ });
582
+ });
@@ -0,0 +1,90 @@
1
+ import { useTsp } from "#core/index.js";
2
+ import { buildParameterDescriptors } from "#python/utils/operation.js";
3
+ import { declarationRefkeys } from "#python/utils/refkey.js";
4
+ import * as py from "@alloy-js/python";
5
+ import type { Model, Operation } from "@typespec/compiler";
6
+ import { DocElement } from "../doc-element/doc-element.js";
7
+ import { TypeExpression } from "../type-expression/type-expression.js";
8
+
9
+ export interface FunctionDeclarationPropsWithType extends Omit<
10
+ py.FunctionDeclarationProps,
11
+ "name"
12
+ > {
13
+ type: Operation;
14
+ name?: string;
15
+ parametersModel?: Model;
16
+ /** If true, parameters replaces operation parameters instead of adding to them as keyword-only */
17
+ replaceParameters?: boolean;
18
+ }
19
+
20
+ export type FunctionDeclarationProps =
21
+ | FunctionDeclarationPropsWithType
22
+ | py.FunctionDeclarationProps;
23
+
24
+ /**
25
+ * A Python function declaration. Pass the `type` prop to create the
26
+ * function declaration by converting from a TypeSpec Operation. Any other props
27
+ * provided will take precedence.
28
+ *
29
+ * @remarks
30
+ * - `parametersModel`: When provided, it replaces the function parameters, ignoring
31
+ * the `parameters` option.
32
+ * - Model-derived parameters include default values when present on the model, and
33
+ * emit `= None` for optional parameters without an explicit default.
34
+ * - Additional parameters (from `parameters` prop) are always keyword-only.
35
+ */
36
+ export function FunctionDeclaration(props: FunctionDeclarationProps) {
37
+ const { $ } = useTsp();
38
+
39
+ if (!isTypedFunctionDeclarationProps(props)) {
40
+ return <py.FunctionDeclaration {...props} />;
41
+ }
42
+
43
+ const refkeys = declarationRefkeys(props.refkey, props.type);
44
+
45
+ const name = props.name
46
+ ? props.name
47
+ : py.usePythonNamePolicy().getName(props.type.name, "function");
48
+
49
+ const returnType = props.returnType ?? <TypeExpression type={props.type.returnType} />;
50
+ let allParameters: (py.ParameterDescriptor | string)[] | undefined;
51
+ if (props.parametersModel) {
52
+ // When a parametersModel is provided, it always replaces parameters,
53
+ // ignoring extra parameters.
54
+ allParameters = buildParameterDescriptors(props.parametersModel) ?? [];
55
+ } else {
56
+ allParameters = buildParameterDescriptors(props.type.parameters, {
57
+ params: props.parameters,
58
+ replaceParameters: props.replaceParameters,
59
+ });
60
+ }
61
+ const docSource = props.doc ?? $.type.getDoc(props.type);
62
+ const docElement = docSource ? (
63
+ <DocElement doc={docSource} component={py.FunctionDoc} />
64
+ ) : undefined;
65
+ const doc = docElement ? (
66
+ <>
67
+ {docElement}
68
+ <hbr />
69
+ </>
70
+ ) : undefined;
71
+
72
+ return (
73
+ <py.FunctionDeclaration
74
+ doc={doc}
75
+ refkey={refkeys}
76
+ name={name}
77
+ async={props.async}
78
+ returnType={returnType}
79
+ parameters={allParameters}
80
+ >
81
+ {props.children}
82
+ </py.FunctionDeclaration>
83
+ );
84
+ }
85
+
86
+ function isTypedFunctionDeclarationProps(
87
+ props: FunctionDeclarationProps,
88
+ ): props is FunctionDeclarationPropsWithType {
89
+ return "type" in props;
90
+ }
@@ -0,0 +1 @@
1
+ export * from "./function-declaration.js";
@@ -0,0 +1,11 @@
1
+ export * from "./array-expression/index.js";
2
+ export * from "./atom/index.js";
3
+ export * from "./class-declaration/index.js";
4
+ export * from "./doc-element/index.js";
5
+ export * from "./enum-declaration/index.js";
6
+ export * from "./function-declaration/index.js";
7
+ export * from "./protocol-declaration/index.js";
8
+ export * from "./record-expression/index.js";
9
+ export * from "./type-alias-declaration/index.js";
10
+ export * from "./type-declaration/index.js";
11
+ export * from "./type-expression/index.js";