@gtkx/codegen 1.0.0 → 1.2.0

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 (347) hide show
  1. package/README.md +1 -1
  2. package/dist/analysis/descriptor-render.d.ts +12 -15
  3. package/dist/analysis/descriptor-render.d.ts.map +1 -1
  4. package/dist/analysis/descriptor-render.js +59 -38
  5. package/dist/analysis/descriptor-render.js.map +1 -1
  6. package/dist/analysis/descriptor.d.ts +25 -10
  7. package/dist/analysis/descriptor.d.ts.map +1 -1
  8. package/dist/analysis/descriptor.js +37 -9
  9. package/dist/analysis/descriptor.js.map +1 -1
  10. package/dist/analysis/inheritance.d.ts +4 -2
  11. package/dist/analysis/inheritance.d.ts.map +1 -1
  12. package/dist/analysis/inheritance.js +80 -38
  13. package/dist/analysis/inheritance.js.map +1 -1
  14. package/dist/analysis/interface-conflicts.d.ts +25 -0
  15. package/dist/analysis/interface-conflicts.d.ts.map +1 -0
  16. package/dist/analysis/interface-conflicts.js +139 -0
  17. package/dist/analysis/interface-conflicts.js.map +1 -0
  18. package/dist/analysis/param-capability.d.ts.map +1 -1
  19. package/dist/analysis/param-capability.js +3 -4
  20. package/dist/analysis/param-capability.js.map +1 -1
  21. package/dist/analysis/param-structure.js +2 -2
  22. package/dist/analysis/param-structure.js.map +1 -1
  23. package/dist/analysis/ts-type.d.ts +3 -2
  24. package/dist/analysis/ts-type.d.ts.map +1 -1
  25. package/dist/analysis/ts-type.js +26 -26
  26. package/dist/analysis/ts-type.js.map +1 -1
  27. package/dist/analysis/type-key.d.ts +5 -0
  28. package/dist/analysis/type-key.d.ts.map +1 -0
  29. package/dist/analysis/type-key.js +9 -0
  30. package/dist/analysis/type-key.js.map +1 -0
  31. package/dist/analysis/type-shape.d.ts +3 -2
  32. package/dist/analysis/type-shape.d.ts.map +1 -1
  33. package/dist/analysis/type-shape.js +2 -1
  34. package/dist/analysis/type-shape.js.map +1 -1
  35. package/dist/compile.d.ts +14 -6
  36. package/dist/compile.d.ts.map +1 -1
  37. package/dist/compile.js +125 -24
  38. package/dist/compile.js.map +1 -1
  39. package/dist/docs/api-reference.d.ts +2 -0
  40. package/dist/docs/api-reference.d.ts.map +1 -1
  41. package/dist/docs/api-reference.js +11 -10
  42. package/dist/docs/api-reference.js.map +1 -1
  43. package/dist/docs/element-page.d.ts.map +1 -1
  44. package/dist/docs/element-page.js +5 -3
  45. package/dist/docs/element-page.js.map +1 -1
  46. package/dist/docs/pipeline.d.ts +1 -0
  47. package/dist/docs/pipeline.d.ts.map +1 -1
  48. package/dist/docs/pipeline.js +93 -19
  49. package/dist/docs/pipeline.js.map +1 -1
  50. package/dist/docs/render.d.ts +2 -1
  51. package/dist/docs/render.d.ts.map +1 -1
  52. package/dist/docs/render.js +5 -4
  53. package/dist/docs/render.js.map +1 -1
  54. package/dist/docs/symbol-page.d.ts.map +1 -1
  55. package/dist/docs/symbol-page.js +10 -9
  56. package/dist/docs/symbol-page.js.map +1 -1
  57. package/dist/fingerprint.d.ts +20 -3
  58. package/dist/fingerprint.d.ts.map +1 -1
  59. package/dist/fingerprint.js +56 -37
  60. package/dist/fingerprint.js.map +1 -1
  61. package/dist/gi.d.ts +1 -0
  62. package/dist/gi.d.ts.map +1 -1
  63. package/dist/gi.js +8 -2
  64. package/dist/gi.js.map +1 -1
  65. package/dist/gir/ancestry.d.ts +7 -1
  66. package/dist/gir/ancestry.d.ts.map +1 -1
  67. package/dist/gir/ancestry.js +9 -1
  68. package/dist/gir/ancestry.js.map +1 -1
  69. package/dist/gir/annotations.d.ts +1 -2
  70. package/dist/gir/annotations.d.ts.map +1 -1
  71. package/dist/gir/annotations.js +1 -1
  72. package/dist/gir/annotations.js.map +1 -1
  73. package/dist/gir/cursor-overrides.d.ts +8 -0
  74. package/dist/gir/cursor-overrides.d.ts.map +1 -0
  75. package/dist/gir/cursor-overrides.js +6 -0
  76. package/dist/gir/cursor-overrides.js.map +1 -0
  77. package/dist/gir/emittable.d.ts +7 -0
  78. package/dist/gir/emittable.d.ts.map +1 -0
  79. package/dist/gir/emittable.js +3 -0
  80. package/dist/gir/emittable.js.map +1 -0
  81. package/dist/gir/function.d.ts.map +1 -1
  82. package/dist/gir/function.js +28 -2
  83. package/dist/gir/function.js.map +1 -1
  84. package/dist/gir/gir-path.d.ts +1 -1
  85. package/dist/gir/gir-path.js +1 -1
  86. package/dist/gir/gir-path.js.map +1 -1
  87. package/dist/gir/library.d.ts +5 -1
  88. package/dist/gir/library.d.ts.map +1 -1
  89. package/dist/gir/library.js +9 -2
  90. package/dist/gir/library.js.map +1 -1
  91. package/dist/gir/namespace.d.ts +5 -1
  92. package/dist/gir/namespace.d.ts.map +1 -1
  93. package/dist/gir/namespace.js +4 -2
  94. package/dist/gir/namespace.js.map +1 -1
  95. package/dist/gir/parameter.d.ts +13 -1
  96. package/dist/gir/parameter.d.ts.map +1 -1
  97. package/dist/gir/parameter.js +1 -0
  98. package/dist/gir/parameter.js.map +1 -1
  99. package/dist/gir/parse.d.ts.map +1 -1
  100. package/dist/gir/parse.js +6 -6
  101. package/dist/gir/parse.js.map +1 -1
  102. package/dist/gir/primitives.js +1 -1
  103. package/dist/gir/primitives.js.map +1 -1
  104. package/dist/guards.d.ts +16 -0
  105. package/dist/guards.d.ts.map +1 -0
  106. package/dist/guards.js +11 -0
  107. package/dist/guards.js.map +1 -0
  108. package/dist/internal.d.ts +2 -0
  109. package/dist/internal.d.ts.map +1 -1
  110. package/dist/internal.js +2 -0
  111. package/dist/internal.js.map +1 -1
  112. package/dist/json.d.ts +3 -0
  113. package/dist/json.d.ts.map +1 -0
  114. package/dist/json.js +11 -0
  115. package/dist/json.js.map +1 -0
  116. package/dist/khronos/args.d.ts.map +1 -1
  117. package/dist/khronos/args.js +8 -6
  118. package/dist/khronos/args.js.map +1 -1
  119. package/dist/khronos/modules.d.ts.map +1 -1
  120. package/dist/khronos/modules.js +22 -7
  121. package/dist/khronos/modules.js.map +1 -1
  122. package/dist/khronos/parse.d.ts.map +1 -1
  123. package/dist/khronos/parse.js +3 -4
  124. package/dist/khronos/parse.js.map +1 -1
  125. package/dist/khronos/pipeline.d.ts +1 -1
  126. package/dist/khronos/pipeline.d.ts.map +1 -1
  127. package/dist/khronos/pipeline.js.map +1 -1
  128. package/dist/khronos/plan.d.ts +1 -7
  129. package/dist/khronos/plan.d.ts.map +1 -1
  130. package/dist/khronos/plan.js +1 -1
  131. package/dist/khronos/plan.js.map +1 -1
  132. package/dist/khronos/render.d.ts.map +1 -1
  133. package/dist/khronos/render.js +8 -4
  134. package/dist/khronos/render.js.map +1 -1
  135. package/dist/runner.d.ts +7 -1
  136. package/dist/runner.d.ts.map +1 -1
  137. package/dist/runner.js +21 -3
  138. package/dist/runner.js.map +1 -1
  139. package/dist/staging.d.ts +5 -0
  140. package/dist/staging.d.ts.map +1 -0
  141. package/dist/staging.js +57 -0
  142. package/dist/staging.js.map +1 -0
  143. package/dist/store/compile-store.d.ts +0 -1
  144. package/dist/store/compile-store.d.ts.map +1 -1
  145. package/dist/store/compile-store.js +7 -32
  146. package/dist/store/compile-store.js.map +1 -1
  147. package/dist/store/gi/callables.d.ts +6 -3
  148. package/dist/store/gi/callables.d.ts.map +1 -1
  149. package/dist/store/gi/callables.js +40 -30
  150. package/dist/store/gi/callables.js.map +1 -1
  151. package/dist/store/gi/callback.d.ts.map +1 -1
  152. package/dist/store/gi/callback.js +9 -5
  153. package/dist/store/gi/callback.js.map +1 -1
  154. package/dist/store/gi/class.d.ts.map +1 -1
  155. package/dist/store/gi/class.js +104 -44
  156. package/dist/store/gi/class.js.map +1 -1
  157. package/dist/store/gi/companion.d.ts.map +1 -1
  158. package/dist/store/gi/companion.js +6 -6
  159. package/dist/store/gi/companion.js.map +1 -1
  160. package/dist/store/gi/constant.d.ts.map +1 -1
  161. package/dist/store/gi/constant.js +11 -3
  162. package/dist/store/gi/constant.js.map +1 -1
  163. package/dist/store/gi/constructor-props.js +1 -1
  164. package/dist/store/gi/constructor-props.js.map +1 -1
  165. package/dist/store/gi/enum.d.ts.map +1 -1
  166. package/dist/store/gi/enum.js +29 -12
  167. package/dist/store/gi/enum.js.map +1 -1
  168. package/dist/store/gi/function.d.ts +1 -3
  169. package/dist/store/gi/function.d.ts.map +1 -1
  170. package/dist/store/gi/function.js +24 -18
  171. package/dist/store/gi/function.js.map +1 -1
  172. package/dist/store/gi/gtype-binding.d.ts.map +1 -1
  173. package/dist/store/gi/gtype-binding.js +4 -1
  174. package/dist/store/gi/gtype-binding.js.map +1 -1
  175. package/dist/store/gi/interface.d.ts.map +1 -1
  176. package/dist/store/gi/interface.js +34 -19
  177. package/dist/store/gi/interface.js.map +1 -1
  178. package/dist/store/gi/method.d.ts +7 -6
  179. package/dist/store/gi/method.d.ts.map +1 -1
  180. package/dist/store/gi/method.js +13 -24
  181. package/dist/store/gi/method.js.map +1 -1
  182. package/dist/store/gi/param-marshal.d.ts +3 -2
  183. package/dist/store/gi/param-marshal.d.ts.map +1 -1
  184. package/dist/store/gi/param-marshal.js +50 -5
  185. package/dist/store/gi/param-marshal.js.map +1 -1
  186. package/dist/store/gi/pipeline.d.ts.map +1 -1
  187. package/dist/store/gi/pipeline.js +21 -10
  188. package/dist/store/gi/pipeline.js.map +1 -1
  189. package/dist/store/gi/properties.d.ts +2 -1
  190. package/dist/store/gi/properties.d.ts.map +1 -1
  191. package/dist/store/gi/properties.js +6 -3
  192. package/dist/store/gi/properties.js.map +1 -1
  193. package/dist/store/gi/property-accessor.d.ts +10 -8
  194. package/dist/store/gi/property-accessor.d.ts.map +1 -1
  195. package/dist/store/gi/property-accessor.js +49 -91
  196. package/dist/store/gi/property-accessor.js.map +1 -1
  197. package/dist/store/gi/record-constructor.d.ts +8 -1
  198. package/dist/store/gi/record-constructor.d.ts.map +1 -1
  199. package/dist/store/gi/record-constructor.js +34 -13
  200. package/dist/store/gi/record-constructor.js.map +1 -1
  201. package/dist/store/gi/record-field-accessor.d.ts.map +1 -1
  202. package/dist/store/gi/record-field-accessor.js +20 -4
  203. package/dist/store/gi/record-field-accessor.js.map +1 -1
  204. package/dist/store/gi/record-layout.d.ts +6 -1
  205. package/dist/store/gi/record-layout.d.ts.map +1 -1
  206. package/dist/store/gi/record-layout.js +8 -1
  207. package/dist/store/gi/record-layout.js.map +1 -1
  208. package/dist/store/gi/record.d.ts.map +1 -1
  209. package/dist/store/gi/record.js +19 -8
  210. package/dist/store/gi/record.js.map +1 -1
  211. package/dist/store/gi/registration.js +2 -2
  212. package/dist/store/gi/registration.js.map +1 -1
  213. package/dist/store/gi/return-wrap.js +1 -1
  214. package/dist/store/gi/return-wrap.js.map +1 -1
  215. package/dist/store/gi/signal.d.ts +2 -1
  216. package/dist/store/gi/signal.d.ts.map +1 -1
  217. package/dist/store/gi/signal.js +55 -28
  218. package/dist/store/gi/signal.js.map +1 -1
  219. package/dist/store/gi/value-marshalable.d.ts.map +1 -1
  220. package/dist/store/gi/value-marshalable.js +2 -1
  221. package/dist/store/gi/value-marshalable.js.map +1 -1
  222. package/dist/store/gi/vtable.d.ts +4 -1
  223. package/dist/store/gi/vtable.d.ts.map +1 -1
  224. package/dist/store/gi/vtable.js +60 -17
  225. package/dist/store/gi/vtable.js.map +1 -1
  226. package/dist/store/gi-store.d.ts +1 -0
  227. package/dist/store/gi-store.d.ts.map +1 -1
  228. package/dist/store/gi-store.js +15 -20
  229. package/dist/store/gi-store.js.map +1 -1
  230. package/dist/store/jsx/generated-elements.d.ts +2 -1
  231. package/dist/store/jsx/generated-elements.d.ts.map +1 -1
  232. package/dist/store/jsx/generated-elements.js +13 -7
  233. package/dist/store/jsx/generated-elements.js.map +1 -1
  234. package/dist/store/jsx/jsx.js +3 -3
  235. package/dist/store/jsx/jsx.js.map +1 -1
  236. package/dist/store/jsx/metadata.d.ts.map +1 -1
  237. package/dist/store/jsx/metadata.js +3 -1
  238. package/dist/store/jsx/metadata.js.map +1 -1
  239. package/dist/store/jsx-store.d.ts.map +1 -1
  240. package/dist/store/jsx-store.js +3 -4
  241. package/dist/store/jsx-store.js.map +1 -1
  242. package/dist/store/resolve-store.d.ts +14 -3
  243. package/dist/store/resolve-store.d.ts.map +1 -1
  244. package/dist/store/resolve-store.js +98 -15
  245. package/dist/store/resolve-store.js.map +1 -1
  246. package/dist/store/store-fs.d.ts +9 -7
  247. package/dist/store/store-fs.d.ts.map +1 -1
  248. package/dist/store/store-fs.js +54 -25
  249. package/dist/store/store-fs.js.map +1 -1
  250. package/dist/store/store-links.d.ts +3 -0
  251. package/dist/store/store-links.d.ts.map +1 -0
  252. package/dist/store/store-links.js +39 -0
  253. package/dist/store/store-links.js.map +1 -0
  254. package/dist/writer/comparison-context.d.ts +4 -0
  255. package/dist/writer/comparison-context.d.ts.map +1 -0
  256. package/dist/writer/comparison-context.js +13 -0
  257. package/dist/writer/comparison-context.js.map +1 -0
  258. package/dist/writer/context.d.ts +3 -3
  259. package/dist/writer/context.d.ts.map +1 -1
  260. package/dist/writer/context.js +11 -6
  261. package/dist/writer/context.js.map +1 -1
  262. package/dist/writer/module.d.ts +13 -5
  263. package/dist/writer/module.d.ts.map +1 -1
  264. package/dist/writer/module.js +68 -11
  265. package/dist/writer/module.js.map +1 -1
  266. package/dist/xml.d.ts +8 -1
  267. package/dist/xml.d.ts.map +1 -1
  268. package/dist/xml.js +70 -1
  269. package/dist/xml.js.map +1 -1
  270. package/overrides/gobject/object.ts.ejs +2 -0
  271. package/package.json +14 -3
  272. package/src/analysis/descriptor-render.ts +106 -52
  273. package/src/analysis/descriptor.ts +76 -15
  274. package/src/analysis/inheritance.ts +134 -44
  275. package/src/analysis/interface-conflicts.ts +235 -0
  276. package/src/analysis/param-capability.ts +3 -6
  277. package/src/analysis/param-structure.ts +2 -2
  278. package/src/analysis/ts-type.ts +43 -28
  279. package/src/analysis/type-key.ts +14 -0
  280. package/src/analysis/type-shape.ts +5 -2
  281. package/src/compile.ts +192 -27
  282. package/src/docs/api-reference.ts +13 -10
  283. package/src/docs/element-page.ts +5 -2
  284. package/src/docs/pipeline.ts +140 -24
  285. package/src/docs/render.ts +7 -3
  286. package/src/docs/symbol-page.ts +12 -11
  287. package/src/fingerprint.ts +95 -47
  288. package/src/gi.ts +10 -2
  289. package/src/gir/ancestry.ts +17 -1
  290. package/src/gir/annotations.ts +1 -1
  291. package/src/gir/cursor-overrides.ts +12 -0
  292. package/src/gir/emittable.ts +8 -0
  293. package/src/gir/function.ts +45 -9
  294. package/src/gir/gir-path.ts +1 -1
  295. package/src/gir/library.ts +10 -2
  296. package/src/gir/namespace.ts +8 -2
  297. package/src/gir/parameter.ts +15 -0
  298. package/src/gir/parse.ts +10 -7
  299. package/src/gir/primitives.ts +1 -1
  300. package/src/guards.ts +23 -0
  301. package/src/internal.ts +2 -0
  302. package/src/json.ts +11 -0
  303. package/src/khronos/args.ts +9 -6
  304. package/src/khronos/modules.ts +25 -9
  305. package/src/khronos/parse.ts +3 -4
  306. package/src/khronos/pipeline.ts +1 -1
  307. package/src/khronos/plan.ts +0 -1
  308. package/src/khronos/render.ts +8 -6
  309. package/src/runner.ts +26 -4
  310. package/src/staging.ts +67 -0
  311. package/src/store/compile-store.ts +7 -38
  312. package/src/store/gi/callables.ts +60 -33
  313. package/src/store/gi/callback.ts +9 -9
  314. package/src/store/gi/class.ts +140 -53
  315. package/src/store/gi/companion.ts +7 -6
  316. package/src/store/gi/constant.ts +13 -3
  317. package/src/store/gi/constructor-props.ts +1 -1
  318. package/src/store/gi/enum.ts +36 -26
  319. package/src/store/gi/function.ts +30 -24
  320. package/src/store/gi/gtype-binding.ts +7 -2
  321. package/src/store/gi/interface.ts +39 -20
  322. package/src/store/gi/method.ts +26 -32
  323. package/src/store/gi/param-marshal.ts +77 -6
  324. package/src/store/gi/pipeline.ts +25 -15
  325. package/src/store/gi/properties.ts +8 -4
  326. package/src/store/gi/property-accessor.ts +73 -161
  327. package/src/store/gi/record-constructor.ts +53 -21
  328. package/src/store/gi/record-field-accessor.ts +26 -4
  329. package/src/store/gi/record-layout.ts +11 -1
  330. package/src/store/gi/record.ts +20 -12
  331. package/src/store/gi/registration.ts +2 -2
  332. package/src/store/gi/return-wrap.ts +1 -1
  333. package/src/store/gi/signal.ts +66 -42
  334. package/src/store/gi/value-marshalable.ts +3 -1
  335. package/src/store/gi/vtable.ts +97 -20
  336. package/src/store/gi-store.ts +26 -31
  337. package/src/store/jsx/generated-elements.ts +17 -8
  338. package/src/store/jsx/jsx.ts +3 -3
  339. package/src/store/jsx/metadata.ts +4 -1
  340. package/src/store/jsx-store.ts +3 -4
  341. package/src/store/resolve-store.ts +133 -18
  342. package/src/store/store-fs.ts +82 -35
  343. package/src/store/store-links.ts +49 -0
  344. package/src/writer/comparison-context.ts +18 -0
  345. package/src/writer/context.ts +12 -6
  346. package/src/writer/module.ts +101 -14
  347. package/src/xml.ts +103 -1
@@ -1,16 +1,26 @@
1
- import { sourceStringLiteral } from "@gtkx/utils";
1
+ import { sanitizeIdentifier, sourceStringLiteral } from "@gtkx/utils";
2
2
  import type { GirConstant } from "../../gir/namespace.js";
3
3
  import type { PrimitiveCategory } from "../../gir/primitives.js";
4
4
  import type { TypeId } from "../../gir/type-id.js";
5
5
  import type { ModuleContext } from "../../writer/context.js";
6
+ import { isEmittableEntity } from "../../gir/emittable.js";
6
7
  import { getDoc } from "./doc-spec.js";
7
8
 
8
9
  const TRUE_VALUES: Set<string> = new Set(["true", "1"]);
9
- const BIGINT_CATEGORIES: Set<PrimitiveCategory> = new Set(["bigint64", "biguint64", "gtype"]);
10
+ const BIGINT_CATEGORIES: Set<PrimitiveCategory> = new Set(["bigint64", "biguint64", "gtype", "pointer"]);
10
11
 
11
12
  const generateConstant = (context: ModuleContext, constant: GirConstant): void => {
13
+ if (!isEmittableEntity(constant)) {
14
+ return;
15
+ }
16
+
12
17
  const doc = getDoc(constant);
13
- context.module.appendDeclaration(`${doc}export const ${constant.name} = ${constantLiteral(context, constant)};`);
18
+ const name = sanitizeIdentifier(constant.name);
19
+
20
+ context.declare({
21
+ name,
22
+ code: `${doc}export const ${name} = ${constantLiteral(context, constant)};`,
23
+ });
14
24
  };
15
25
 
16
26
  const constantLiteral = (context: ModuleContext, constant: GirConstant): string => {
@@ -96,7 +96,7 @@ const renderTranslatingConstructor = (context: ModuleContext, props: GirProperty
96
96
  context.addRuntimeImport("t");
97
97
  context.addRuntimeImport("registerConstructProperties");
98
98
  const bindings = renderConstructBindings(context, props);
99
- context.module.appendRegistration(`registerConstructProperties(${className}, ${bindings});`);
99
+ context.module.appendRegistration(`registerConstructProperties(${className}, ${bindings});`, [className]);
100
100
 
101
101
  return renderBlock(`constructor(props: ${className}ConstructorProps = {})`, "super(props);");
102
102
  };
@@ -1,7 +1,8 @@
1
- import { sourceStringLiteral } from "@gtkx/utils";
1
+ import { escapeIdentifierStart, sanitizeTypeIdentifier, sourceStringLiteral, uniqBy } from "@gtkx/utils";
2
2
  import type { EnumMember, GirEnum } from "../../gir/enum.js";
3
3
  import type { ModuleContext } from "../../writer/context.js";
4
4
  import { hasAnnotations } from "../../gir/annotations.js";
5
+ import { isEmittableEntity } from "../../gir/emittable.js";
5
6
  import { indent } from "../../writer/emit.js";
6
7
  import { getDoc } from "./doc-spec.js";
7
8
 
@@ -14,11 +15,17 @@ const enumDoc = (enumeration: GirEnum): string =>
14
15
  getDoc(enumeration);
15
16
 
16
17
  const generateEnum = (context: ModuleContext, enumeration: GirEnum): void => {
17
- if (!enumeration.introspectable) {
18
+ if (!isEmittableEntity(enumeration)) {
18
19
  return;
19
20
  }
20
21
 
21
- const members = enumeration.members.map((member) => ({ ...member, key: enumMemberKey(member.name) }));
22
+ const members = uniqBy(
23
+ enumeration.members
24
+ .map((member) => ({ ...member, key: enumMemberKey(member.name) }))
25
+ .filter((member) => member.key.length > 0),
26
+ (member) => member.key,
27
+ );
28
+
22
29
  const errorDomain = enumeration.errorDomain;
23
30
 
24
31
  if (errorDomain !== undefined) {
@@ -43,16 +50,20 @@ const appendErrorDomain = (
43
50
  const quarkExpression = renderQuarkExpression(context, errorDomain);
44
51
  const doc = enumDoc(enumeration);
45
52
  const shape = typeFields.length === 0 ? "{}" : `{\n${indent(typeFields.join("\n"), 1)}\n}`;
46
-
47
- context.module.appendDeclaration(
48
- `${doc}export type ${enumeration.name} = number;`,
49
- context.declaredType(enumeration.name),
50
- );
51
-
52
- context.module.appendDeclaration(
53
- `${doc}export const ${enumeration.name}: ErrorDomain<${shape}> = ` +
54
- `createErrorDomain(${quarkExpression}, { ${memberEntries.join(", ")} });`,
55
- );
53
+ const name = sanitizeTypeIdentifier(enumeration.name);
54
+
55
+ context.declare({
56
+ name,
57
+ code: `${doc}export type ${name} = number;`,
58
+ owner: enumeration.name,
59
+ });
60
+
61
+ context.declare({
62
+ name,
63
+ code:
64
+ `${doc}export const ${name}: ErrorDomain<${shape}> = ` +
65
+ `createErrorDomain(${quarkExpression}, { ${memberEntries.join(", ")} });`,
66
+ });
56
67
  };
57
68
 
58
69
  const isMemberDocumented = (member: KeyedMember): boolean =>
@@ -60,31 +71,30 @@ const isMemberDocumented = (member: KeyedMember): boolean =>
60
71
 
61
72
  const appendEnumDeclaration = (context: ModuleContext, enumeration: GirEnum, members: KeyedMember[]): void => {
62
73
  const doc = enumDoc(enumeration);
74
+ const name = sanitizeTypeIdentifier(enumeration.name);
63
75
 
64
76
  if (members.some((member) => isMemberDocumented(member))) {
65
77
  const blocks = members.map((member) => `${memberDoc(member)}${member.key} = ${member.value},`);
66
78
 
67
- context.module.appendDeclaration(
68
- `${doc}export enum ${enumeration.name} {\n${indent(blocks.join("\n"), 1)}\n}`,
69
- context.declaredType(enumeration.name),
70
- );
79
+ context.declare({
80
+ name,
81
+ code: `${doc}export enum ${name} {\n${indent(blocks.join("\n"), 1)}\n}`,
82
+ owner: enumeration.name,
83
+ });
71
84
 
72
85
  return;
73
86
  }
74
87
 
75
88
  const declarations = members.map((member) => `${member.key} = ${member.value}`);
76
89
 
77
- context.module.appendDeclaration(
78
- `${doc}export enum ${enumeration.name} { ${declarations.join(", ")} }`,
79
- context.declaredType(enumeration.name),
80
- );
90
+ context.declare({
91
+ name,
92
+ code: `${doc}export enum ${name} { ${declarations.join(", ")} }`,
93
+ owner: enumeration.name,
94
+ });
81
95
  };
82
96
 
83
- const enumMemberKey = (name: string): string => {
84
- const upper = name.toUpperCase().replaceAll("-", "_");
85
-
86
- return /^\d/.test(upper) ? `_${upper}` : upper;
87
- };
97
+ const enumMemberKey = (name: string): string => escapeIdentifierStart(name.toUpperCase().replaceAll("-", "_"));
88
98
 
89
99
  const renderQuarkExpression = (context: ModuleContext, errorDomain: string): string => {
90
100
  if (context.namespace.name === "GLib") {
@@ -1,6 +1,5 @@
1
1
  import { toCamelIdentifier } from "@gtkx/utils";
2
2
  import type { GirFunction } from "../../gir/function.js";
3
- import type { GirNamespace } from "../../gir/namespace.js";
4
3
  import type { ModuleContext } from "../../writer/context.js";
5
4
  import { tFn } from "../../analysis/descriptor.js";
6
5
  import { hasUnmarshalableParam } from "../../analysis/param-capability.js";
@@ -43,9 +42,14 @@ const renderFnExpression = (context: ModuleContext, fn: GirFunction): string | u
43
42
 
44
43
  context.addRuntimeImport("t");
45
44
  const params = planCallArgs(context, fn).map((arg) => arg.paramLiteral);
46
- const ret = renderReturnDescriptor(context, fn);
47
-
48
- return tFn(library, fn.cIdentifier, { args: arrayLiteral(params), returns: ret, canThrow: fn.throws });
45
+ const returnPlan = renderReturnDescriptor(context, fn);
46
+
47
+ return tFn(library, fn.cIdentifier, {
48
+ args: arrayLiteral(params),
49
+ returns: returnPlan.descriptor,
50
+ isReturnSkipped: returnPlan.isSkipped,
51
+ canThrow: fn.throws,
52
+ });
49
53
  };
50
54
 
51
55
  const isMovedOntoEmittedMember = (context: ModuleContext, fn: GirFunction): boolean => {
@@ -90,13 +94,25 @@ const generateNamespaceFunction = (context: ModuleContext, fn: GirFunction): voi
90
94
  return;
91
95
  }
92
96
 
93
- const bindingName = toCamelIdentifier(cIdentifier);
94
- context.module.appendBinding(`const ${bindingName} = ${expression};`, cIdentifier);
95
97
  const exportName = namespaceFunctionExportName(cIdentifier, fn.name, context.namespace.cSymbolPrefixes);
98
+
99
+ if (exportName.length === 0) {
100
+ return;
101
+ }
102
+
103
+ const bindingName = namespaceBindingName(cIdentifier, exportName);
104
+ context.module.appendBinding(`const ${bindingName} = ${expression};`, cIdentifier);
96
105
  const finish = matchNamespaceFinish(context, fn);
97
106
  const declaration = renderNamespaceFunctionDeclaration({ context, fn, finish, exportName, bindingName });
98
107
  const doc = callableDoc(context, fn, { finishFn: finish?.fn });
99
- context.module.appendDeclaration(`${doc}${declaration}`);
108
+ context.declare({ name: exportName, code: `${doc}${declaration}` });
109
+ appendBootstrapRegistration(context, fn, exportName);
110
+ };
111
+
112
+ const namespaceBindingName = (cIdentifier: string, exportName: string): string => {
113
+ const bindingName = toCamelIdentifier(cIdentifier);
114
+
115
+ return bindingName === exportName ? `_${bindingName}` : bindingName;
100
116
  };
101
117
 
102
118
  const matchNamespaceFinish = (context: ModuleContext, fn: GirFunction): NamespaceFinish | undefined => {
@@ -159,31 +175,21 @@ const stripLongestPrefix = (input: string, prefixes: string[]): string => {
159
175
  return best.length === 0 ? input : input.slice(best.length);
160
176
  };
161
177
 
162
- const isBootstrapFunction = (fn: GirFunction): boolean =>
163
- fn.parameters.length === 0 && fn.introspectable && fn.shadowedBy === undefined && fn.cIdentifier !== undefined;
164
-
165
178
  const appendBootstrapRegistration = (context: ModuleContext, fn: GirFunction, exportName: string): void => {
179
+ if (fn.parameters.length > 0) {
180
+ return;
181
+ }
182
+
166
183
  if (fn.name === "init") {
167
- context.module.appendRegistration(`${exportName}();`);
184
+ context.module.appendRegistration(`${exportName}();`, [exportName]);
168
185
 
169
186
  return;
170
187
  }
171
188
 
172
189
  if (fn.name === "finalize") {
173
190
  context.addRuntimeImport("onExit");
174
- context.module.appendRegistration(`onExit(${exportName});`);
175
- }
176
- };
177
-
178
- const generateNamespaceBootstrap = (context: ModuleContext, namespace: GirNamespace): void => {
179
- for (const fn of namespace.functions) {
180
- if (!isBootstrapFunction(fn) || fn.cIdentifier === undefined) {
181
- continue;
182
- }
183
-
184
- const exportName = namespaceFunctionExportName(fn.cIdentifier, fn.name, context.namespace.cSymbolPrefixes);
185
- appendBootstrapRegistration(context, fn, exportName);
191
+ context.module.appendRegistration(`onExit(${exportName});`, [exportName]);
186
192
  }
187
193
  };
188
194
 
189
- export { renderFnExpression, generateNamespaceFunction, namespaceFunctionExportName, generateNamespaceBootstrap };
195
+ export { renderFnExpression, generateNamespaceFunction, namespaceFunctionExportName };
@@ -24,9 +24,14 @@ const renderInternGtype = (context: ModuleContext, typeName: string | undefined)
24
24
  return `typeFromName(${sourceStringLiteral(typeName)})`;
25
25
  };
26
26
 
27
- const renderResolveGtype = (context: ModuleContext, typeFnName: string): string => {
27
+ const renderResolveGtype = (context: ModuleContext, typeFnName: string): string | undefined => {
28
+ const lib = context.namespace.sharedLibrary;
29
+
30
+ if (lib === undefined) {
31
+ return undefined;
32
+ }
33
+
28
34
  context.addRuntimeImport("resolveType");
29
- const lib = context.namespace.sharedLibrary ?? "";
30
35
 
31
36
  return `resolveType(${sourceStringLiteral(lib)}, ${sourceStringLiteral(typeFnName)})`;
32
37
  };
@@ -1,9 +1,11 @@
1
- import { pascalCase, sourceStringLiteral } from "@gtkx/utils";
1
+ import { sanitizeTypeIdentifier, sourceStringLiteral } from "@gtkx/utils";
2
2
  import type { GirClass } from "../../gir/class.js";
3
3
  import type { GirProperty } from "../../gir/property.js";
4
4
  import type { ModuleContext } from "../../writer/context.js";
5
5
  import { reservedSignalMemberRename, resolvePrerequisiteReference } from "../../analysis/inheritance.js";
6
- import { resolveInterfaces } from "../../gir/ancestry.js";
6
+ import { omittedTypeRef, prerequisiteConflicts } from "../../analysis/interface-conflicts.js";
7
+ import { resolveClassOrInterface, resolveInterfaces } from "../../gir/ancestry.js";
8
+ import { isEmittableEntity } from "../../gir/emittable.js";
7
9
  import { renderJsDoc } from "../../writer/doc.js";
8
10
  import { renderBlock, renderBraced, renderBracedOrEmpty } from "../../writer/emit.js";
9
11
  import {
@@ -72,15 +74,11 @@ const BRAND_NOTE = [
72
74
  ].join("\n");
73
75
 
74
76
  const generateInterface = (context: ModuleContext, iface: GirClass): void => {
75
- if (!iface.introspectable) {
77
+ if (!isEmittableEntity(iface)) {
76
78
  return;
77
79
  }
78
80
 
79
- if (iface.name.length === 0) {
80
- return;
81
- }
82
-
83
- const className = pascalCase(iface.name);
81
+ const className = sanitizeTypeIdentifier(iface.name);
84
82
 
85
83
  const callables: Callables = {
86
84
  constructors: dedupeCallables(iface.constructors),
@@ -92,13 +90,16 @@ const generateInterface = (context: ModuleContext, iface: GirClass): void => {
92
90
  const gtypeExpr = renderSourceGtype(context, iface);
93
91
  const implRef = appendInterfaceTypes(context, iface, className, callables) ?? "unknown";
94
92
  const classCode = renderInterfaceClass(context, { iface, className, callables, gtypeExpr, implRef });
95
- context.module.appendDeclaration(classCode, context.declaredType(className));
93
+ context.declare({ name: className, code: classCode, owner: iface.name });
96
94
 
97
95
  for (const declaration of renderSignalDeclarations(context, iface, className, true)) {
98
- context.module.appendDeclaration(declaration);
96
+ context.declare(declaration);
99
97
  }
100
98
 
101
- context.module.appendDeclaration(renderInterfaceMaker(context, iface, className, callables));
99
+ context.declare({
100
+ name: makerName(className),
101
+ code: renderInterfaceMaker(context, iface, className, callables),
102
+ });
102
103
 
103
104
  appendInterfaceRegistration(context, {
104
105
  className,
@@ -136,7 +137,7 @@ const renderInterfaceLayout = (
136
137
  };
137
138
 
138
139
  const invokerMembers = (context: ModuleContext, iface: GirClass, callables: Callables): Map<string, string> => {
139
- const className = pascalCase(iface.name);
140
+ const className = sanitizeTypeIdentifier(iface.name);
140
141
 
141
142
  const invokers: Set<string> = new Set(
142
143
  iface.vfuncs.map((vfunc) => vfunc.invoker).filter((invoker) => invoker !== undefined),
@@ -201,7 +202,7 @@ const appendInterfaceTypes = (
201
202
  callables: Callables,
202
203
  ): string | undefined => {
203
204
  const typeCode = renderInterfaceType(context, iface, className, callables);
204
- context.module.appendDeclaration(typeCode, context.declaredType(className));
205
+ context.declare({ name: className, code: typeCode, owner: iface.name });
205
206
  const implType = renderInterfaceImplType(context, iface, className);
206
207
 
207
208
  if (implType === undefined) {
@@ -209,21 +210,39 @@ const appendInterfaceTypes = (
209
210
  }
210
211
 
211
212
  const implName = implTypeName(className);
212
- context.module.appendDeclaration(implType, context.declaredType(className, implName));
213
+ context.declare({ name: implName, code: implType, owner: iface.name });
213
214
 
214
215
  return implName;
215
216
  };
216
217
 
218
+ const prerequisiteRef = (context: ModuleContext, iface: GirClass, name: string): string | undefined => {
219
+ const ref = resolvePrerequisiteReference(context, name);
220
+ const base = resolveClassOrInterface(context.library, context.namespace.name, name);
221
+
222
+ if (ref === undefined || base === undefined) {
223
+ return undefined;
224
+ }
225
+
226
+ return omittedTypeRef(ref, prerequisiteConflicts(context.library, iface, base));
227
+ };
228
+
229
+ const rootPrerequisiteRef = (context: ModuleContext, iface: GirClass): string => {
230
+ const ref = context.qualify("GObject", "Object");
231
+ const base = resolveClassOrInterface(context.library, "GObject", "Object");
232
+
233
+ return base === undefined ? ref : omittedTypeRef(ref, prerequisiteConflicts(context.library, iface, base));
234
+ };
235
+
217
236
  const interfaceTypeExtends = (context: ModuleContext, iface: GirClass): string => {
218
237
  const refs = iface.prerequisites
219
- .map((name) => resolvePrerequisiteReference(context, name))
238
+ .map((name) => prerequisiteRef(context, iface, name))
220
239
  .filter((entry): entry is string => entry !== undefined);
221
240
 
222
241
  if (refs.length > 0) {
223
242
  return refs.join(", ");
224
243
  }
225
244
 
226
- return context.qualify("GObject", "Object");
245
+ return rootPrerequisiteRef(context, iface);
227
246
  };
228
247
 
229
248
  const renderInterfaceType = (
@@ -264,7 +283,7 @@ const implPrerequisiteRefs = (context: ModuleContext, iface: GirClass): string[]
264
283
  continue;
265
284
  }
266
285
 
267
- const name = implTypeName(pascalCase(prerequisite.klass.name));
286
+ const name = implTypeName(sanitizeTypeIdentifier(prerequisite.klass.name));
268
287
  refs.push(context.qualify(prerequisite.namespaceName, name));
269
288
  }
270
289
 
@@ -317,11 +336,11 @@ const collectMethodMembers = (options: MethodMemberOptions): string[] => {
317
336
  };
318
337
 
319
338
  const collectPropertyMembers = (options: PropertyMemberOptions): string[] => {
320
- const { context, iface, scope, renderers, claimedNames } = options;
339
+ const { context, iface, renderers, claimedNames } = options;
321
340
  const members: string[] = [];
322
341
 
323
342
  for (const property of iface.properties) {
324
- const block = renderers.renderProperty({ context, property, claimedNames, methodByName: scope.methodByName });
343
+ const block = renderers.renderProperty({ context, property, claimedNames });
325
344
 
326
345
  if (block !== undefined) {
327
346
  members.push(block);
@@ -337,7 +356,7 @@ const renderInterfaceMembers = (
337
356
  callables: Callables,
338
357
  renderers: InterfaceMemberRenderers,
339
358
  ): string[] => {
340
- const className = pascalCase(iface.name);
359
+ const className = sanitizeTypeIdentifier(iface.name);
341
360
  const scope = instanceScope(className, callables);
342
361
  const claimedNames: Set<string> = new Set();
343
362
  const methodMembers = collectMethodMembers({ context, className, scope, callables, renderers, claimedNames });
@@ -1,8 +1,9 @@
1
- import { camelCase, sourceStringLiteral } from "@gtkx/utils";
1
+ import { camelCase, escapeIdentifierStart, sourceStringLiteral } from "@gtkx/utils";
2
2
  import type { GirFunction } from "../../gir/function.js";
3
3
  import type { GirType } from "../../gir/type.js";
4
4
  import type { ModuleContext } from "../../writer/context.js";
5
5
  import {
6
+ isSkippedPrimaryReturn,
6
7
  renderCallbackType,
7
8
  renderDescriptor,
8
9
  renderSelfDescriptor,
@@ -18,12 +19,18 @@ import {
18
19
  inputParameters,
19
20
  parameterIdentifier,
20
21
  } from "../../analysis/param-structure.js";
21
- import { renderTsType } from "../../analysis/ts-type.js";
22
+ import { renderParameterTsType, renderTsType } from "../../analysis/ts-type.js";
22
23
  import { type GirParameter, isCallerAllocatedOut, isInoutParameter, isOutParameter } from "../../gir/parameter.js";
23
24
  import { hasUnknownArrayLength, type TypeId } from "../../gir/type-id.js";
24
25
  import { areClosuresInvoked } from "./closure-invocation.js";
25
26
  import { itemComparatorArgDescriptors, itemComparatorTsType } from "./item-comparators.js";
26
- import { isClosureType, isCollectibleCallerOut, isHandlePassedInPlace, isHandlePassing } from "./param-marshal.js";
27
+ import {
28
+ isClosureType,
29
+ isCollectibleCallerOut,
30
+ isHandlePassedInPlace,
31
+ isHandlePassing,
32
+ renderCallerOutInstance,
33
+ } from "./param-marshal.js";
27
34
 
28
35
  type PromisifiedStep = { hasSeenOptional: boolean; expression: string | undefined };
29
36
 
@@ -54,6 +61,11 @@ type CallArgPlan = {
54
61
  inputExpr: string | undefined;
55
62
  };
56
63
 
64
+ type ReturnDescriptorPlan = {
65
+ descriptor: string;
66
+ isSkipped: boolean;
67
+ };
68
+
57
69
  type ParamDescriptorOptions = {
58
70
  direction?: "out" | "inout";
59
71
  isCallerAllocated?: boolean;
@@ -74,7 +86,8 @@ type PlanArgsContext = {
74
86
  folded: Set<number>;
75
87
  };
76
88
 
77
- const methodExportName = (fn: GirFunction): string => camelCase(fn.name);
89
+ const memberName = (girName: string): string => escapeIdentifierStart(camelCase(girName));
90
+ const methodExportName = (fn: GirFunction): string => memberName(fn.name);
78
91
 
79
92
  const arrayLengthArgument = (source: GirParameter, sourceIndex: number): string => {
80
93
  const identifier = parameterIdentifier(source, sourceIndex);
@@ -107,7 +120,7 @@ const parameterAnnotation = (context: ModuleContext, fn: GirFunction, parameter:
107
120
  return comparator;
108
121
  }
109
122
 
110
- const base = renderTsType(context, parameter.type, parameter.nullable);
123
+ const base = renderParameterTsType(context, parameter.type, parameter.nullable);
111
124
 
112
125
  return requiresClosureAnnotation(context, fn, parameter) ? closureAnnotation(context, base) : base;
113
126
  };
@@ -346,14 +359,16 @@ const paramDescriptorLiteral = (descriptor: string, options: ParamDescriptorOpti
346
359
  return `{ ${parts.join(", ")} }`;
347
360
  };
348
361
 
349
- const renderReturnDescriptor = (context: ModuleContext, fn: GirFunction): string => {
362
+ const renderReturnDescriptor = (context: ModuleContext, fn: GirFunction): ReturnDescriptorPlan => {
350
363
  const instanceOffset = fn.instance === undefined ? 0 : 1;
351
364
 
352
- return renderDescriptor(context, fn.returnValue.type, fn.returnValue.transferOwnership, {
365
+ const descriptor = renderDescriptor(context, fn.returnValue.type, fn.returnValue.transferOwnership, {
353
366
  argIndexOffset: instanceOffset,
354
367
  argIndexMap: emittedArgIndices(fn, instanceOffset),
355
368
  isNewlyCreated: fn.instance === undefined,
356
369
  });
370
+
371
+ return { descriptor, isSkipped: isSkippedPrimaryReturn(context.library, fn.returnValue) };
357
372
  };
358
373
 
359
374
  const planCallArgs = (context: ModuleContext, fn: GirFunction): CallArgPlan[] => {
@@ -473,6 +488,7 @@ const planOutParam = (
473
488
  ): CallArgPlan => {
474
489
  const descriptor = renderDescriptor(context, parameter.type, parameter.transferOwnership, {
475
490
  ...argIndex,
491
+ cursor: parameter.cursor,
476
492
  hasOutIndirection: true,
477
493
  });
478
494
 
@@ -482,41 +498,19 @@ const planOutParam = (
482
498
  };
483
499
  };
484
500
 
485
- const constructibleName = (
486
- context: ModuleContext,
487
- ref: GirParameter["type"],
488
- ): { namespaceName: string; typeName: string } | undefined => {
489
- let current = ref;
490
-
491
- while (current !== undefined) {
492
- const resolved = context.library.typeFor(current);
493
-
494
- if (resolved?.kind === "alias" && resolved.value.target !== undefined) {
495
- current = resolved.value.target;
496
- continue;
497
- }
498
-
499
- return context.library.nameFor(current);
500
- }
501
-
502
- return undefined;
503
- };
504
-
505
501
  const planCallerOut = (
506
502
  context: ModuleContext,
507
503
  parameter: GirParameter,
508
504
  argIndex: ArgIndexOptions,
509
505
  ): CallArgPlan => {
510
506
  const descriptor = renderDescriptor(context, parameter.type, "none", argIndex);
511
- const name = constructibleName(context, parameter.type);
512
507
 
513
- if (name !== undefined && isCollectibleCallerOut(context, parameter)) {
508
+ if (isCollectibleCallerOut(context, parameter)) {
514
509
  context.addRuntimeImport("getHandle");
515
- const classExpression = context.qualify(name.namespaceName, name.typeName);
516
510
 
517
511
  return {
518
512
  paramLiteral: paramDescriptorLiteral(descriptor, { direction: "out", isCallerAllocated: true }),
519
- inputExpr: `new ${classExpression}()`,
513
+ inputExpr: renderCallerOutInstance(context, parameter),
520
514
  };
521
515
  }
522
516
 
@@ -678,8 +672,8 @@ const parameterCallExpression = (
678
672
  };
679
673
 
680
674
  export {
681
- constructibleName,
682
675
  isCallbackParameter,
676
+ memberName,
683
677
  methodExportName,
684
678
  renderMethodSignature,
685
679
  renderMethodReturnType,
@@ -1,7 +1,13 @@
1
+ import { sanitizeTypeIdentifier } from "@gtkx/utils";
1
2
  import type { TypeId } from "../../gir/type-id.js";
2
3
  import type { GirType } from "../../gir/type.js";
3
4
  import type { ModuleContext } from "../../writer/context.js";
4
5
  import { type GirParameter, isInoutParameter } from "../../gir/parameter.js";
6
+ import { recordInlineSize } from "./record-layout.js";
7
+ import { isConstructibleRecord } from "./value-marshalable.js";
8
+
9
+ type TypeName = { namespaceName: string; typeName: string };
10
+ type CallerOutAllocation = TypeName & ({ strategy: "construct" } | { strategy: "allocate"; size: number });
5
11
 
6
12
  const isHandlePassedInPlace = (context: ModuleContext, parameter: GirParameter): boolean => {
7
13
  if (parameter.direction !== "out" && parameter.direction !== "inout") {
@@ -28,14 +34,78 @@ const underlyingType = (context: ModuleContext, ref: TypeId): GirType | undefine
28
34
  const underlyingParamKind = (context: ModuleContext, parameter: GirParameter): GirType["kind"] | undefined =>
29
35
  parameter.type === undefined ? undefined : underlyingType(context, parameter.type)?.kind;
30
36
 
31
- const isCollectibleCallerOut = (context: ModuleContext, parameter: GirParameter): boolean => {
32
- const kind = underlyingParamKind(context, parameter);
37
+ const resolvedTypeName = (context: ModuleContext, ref: TypeId | undefined): TypeName | undefined => {
38
+ let current = ref;
39
+
40
+ while (current !== undefined) {
41
+ const resolved = context.library.typeFor(current);
42
+
43
+ if (resolved?.kind === "alias" && resolved.value.target !== undefined) {
44
+ current = resolved.value.target;
45
+ continue;
46
+ }
47
+
48
+ return context.library.nameFor(current);
49
+ }
50
+
51
+ return undefined;
52
+ };
53
+
54
+ const recordCallerOutAllocation = (
55
+ context: ModuleContext,
56
+ name: TypeName,
57
+ type: Extract<GirType, { kind: "record" }>,
58
+ ): CallerOutAllocation | undefined => {
59
+ const size = recordInlineSize(context, type.value);
60
+
61
+ if (size === undefined) {
62
+ return undefined;
63
+ }
64
+
65
+ return isConstructibleRecord(context, type.namespace.name, type.value)
66
+ ? { ...name, strategy: "construct" }
67
+ : { ...name, strategy: "allocate", size };
68
+ };
69
+
70
+ const callerOutAllocation = (context: ModuleContext, parameter: GirParameter): CallerOutAllocation | undefined => {
71
+ const name = resolvedTypeName(context, parameter.type);
72
+ const type = parameter.type === undefined ? undefined : underlyingType(context, parameter.type);
33
73
 
34
- return kind === "record" || kind === "class";
74
+ if (name === undefined || type === undefined) {
75
+ return undefined;
76
+ }
77
+
78
+ if (type.kind === "class") {
79
+ return { ...name, strategy: "construct" };
80
+ }
81
+
82
+ return type.kind === "record" ? recordCallerOutAllocation(context, name, type) : undefined;
83
+ };
84
+
85
+ const renderCallerOutInstance = (context: ModuleContext, parameter: GirParameter): string => {
86
+ const allocation = callerOutAllocation(context, parameter);
87
+
88
+ if (allocation === undefined) {
89
+ throw new Error("renderCallerOutInstance: expected a caller-allocated out-parameter with a known layout");
90
+ }
91
+
92
+ const classExpression = context.qualify(allocation.namespaceName, sanitizeTypeIdentifier(allocation.typeName));
93
+
94
+ if (allocation.strategy === "construct") {
95
+ return `new ${classExpression}()`;
96
+ }
97
+
98
+ context.addRuntimeImport("alloc");
99
+ context.addRuntimeImport("wrapHandle");
100
+
101
+ return `wrapHandle(alloc(${String(allocation.size)}), ${classExpression})`;
35
102
  };
36
103
 
37
- const isRecordCallerOut = (context: ModuleContext, parameter: GirParameter): boolean =>
38
- underlyingParamKind(context, parameter) === "record";
104
+ const isCollectibleCallerOut = (context: ModuleContext, parameter: GirParameter): boolean =>
105
+ callerOutAllocation(context, parameter) !== undefined;
106
+
107
+ const isAllocatableCallerOut = (context: ModuleContext, parameter: GirParameter): boolean =>
108
+ underlyingParamKind(context, parameter) === "record" && isCollectibleCallerOut(context, parameter);
39
109
 
40
110
  const isRecordInout = (context: ModuleContext, parameter: GirParameter): boolean =>
41
111
  isInoutParameter(parameter) && underlyingParamKind(context, parameter) === "record";
@@ -75,11 +145,12 @@ const isClosureType = (context: ModuleContext, ref: TypeId): boolean => {
75
145
  };
76
146
 
77
147
  export {
148
+ isAllocatableCallerOut,
78
149
  isClosureType,
79
150
  isHandlePassedInPlace,
80
151
  isCollectibleCallerOut,
81
- isRecordCallerOut,
82
152
  isRecordInout,
83
153
  isHandlePassing,
154
+ renderCallerOutInstance,
84
155
  underlyingType,
85
156
  };