@gtkx/codegen 0.21.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 (340) hide show
  1. package/LICENSE +373 -0
  2. package/dist/dsl/context.d.ts +104 -0
  3. package/dist/dsl/context.d.ts.map +1 -0
  4. package/dist/dsl/context.js +140 -0
  5. package/dist/dsl/context.js.map +1 -0
  6. package/dist/dsl/emit.d.ts +28 -0
  7. package/dist/dsl/emit.d.ts.map +1 -0
  8. package/dist/dsl/emit.js +41 -0
  9. package/dist/dsl/emit.js.map +1 -0
  10. package/dist/dsl/identifier.d.ts +28 -0
  11. package/dist/dsl/identifier.d.ts.map +1 -0
  12. package/dist/dsl/identifier.js +45 -0
  13. package/dist/dsl/identifier.js.map +1 -0
  14. package/dist/dsl/imports.d.ts +58 -0
  15. package/dist/dsl/imports.d.ts.map +1 -0
  16. package/dist/dsl/imports.js +107 -0
  17. package/dist/dsl/imports.js.map +1 -0
  18. package/dist/dsl/module.d.ts +53 -0
  19. package/dist/dsl/module.d.ts.map +1 -0
  20. package/dist/dsl/module.js +76 -0
  21. package/dist/dsl/module.js.map +1 -0
  22. package/dist/ffi/pipeline.d.ts +19 -0
  23. package/dist/ffi/pipeline.d.ts.map +1 -0
  24. package/dist/ffi/pipeline.js +107 -0
  25. package/dist/ffi/pipeline.js.map +1 -0
  26. package/dist/fingerprint.d.ts +30 -0
  27. package/dist/fingerprint.d.ts.map +1 -0
  28. package/dist/fingerprint.js +33 -0
  29. package/dist/fingerprint.js.map +1 -0
  30. package/dist/gi-store.d.ts +34 -0
  31. package/dist/gi-store.d.ts.map +1 -0
  32. package/dist/gi-store.js +154 -0
  33. package/dist/gi-store.js.map +1 -0
  34. package/dist/gir/boxed.d.ts +66 -0
  35. package/dist/gir/boxed.d.ts.map +1 -0
  36. package/dist/gir/boxed.js +49 -0
  37. package/dist/gir/boxed.js.map +1 -0
  38. package/dist/gir/callback.d.ts +15 -0
  39. package/dist/gir/callback.d.ts.map +1 -0
  40. package/dist/gir/callback.js +17 -0
  41. package/dist/gir/callback.js.map +1 -0
  42. package/dist/gir/class.d.ts +49 -0
  43. package/dist/gir/class.d.ts.map +1 -0
  44. package/dist/gir/class.js +42 -0
  45. package/dist/gir/class.js.map +1 -0
  46. package/dist/gir/enum.d.ts +39 -0
  47. package/dist/gir/enum.d.ts.map +1 -0
  48. package/dist/gir/enum.js +24 -0
  49. package/dist/gir/enum.js.map +1 -0
  50. package/dist/gir/field.d.ts +27 -0
  51. package/dist/gir/field.d.ts.map +1 -0
  52. package/dist/gir/field.js +19 -0
  53. package/dist/gir/field.js.map +1 -0
  54. package/dist/gir/function.d.ts +47 -0
  55. package/dist/gir/function.d.ts.map +1 -0
  56. package/dist/gir/function.js +28 -0
  57. package/dist/gir/function.js.map +1 -0
  58. package/dist/gir/namespace.d.ts +65 -0
  59. package/dist/gir/namespace.d.ts.map +1 -0
  60. package/dist/gir/namespace.js +60 -0
  61. package/dist/gir/namespace.js.map +1 -0
  62. package/dist/gir/parameter.d.ts +82 -0
  63. package/dist/gir/parameter.d.ts.map +1 -0
  64. package/dist/gir/parameter.js +66 -0
  65. package/dist/gir/parameter.js.map +1 -0
  66. package/dist/gir/parse.d.ts +78 -0
  67. package/dist/gir/parse.d.ts.map +1 -0
  68. package/dist/gir/parse.js +155 -0
  69. package/dist/gir/parse.js.map +1 -0
  70. package/dist/gir/primitives.d.ts +36 -0
  71. package/dist/gir/primitives.d.ts.map +1 -0
  72. package/dist/gir/primitives.js +109 -0
  73. package/dist/gir/primitives.js.map +1 -0
  74. package/dist/gir/property.d.ts +29 -0
  75. package/dist/gir/property.d.ts.map +1 -0
  76. package/dist/gir/property.js +16 -0
  77. package/dist/gir/property.js.map +1 -0
  78. package/dist/gir/qualified-name.d.ts +37 -0
  79. package/dist/gir/qualified-name.d.ts.map +1 -0
  80. package/dist/gir/qualified-name.js +39 -0
  81. package/dist/gir/qualified-name.js.map +1 -0
  82. package/dist/gir/qualify.d.ts +32 -0
  83. package/dist/gir/qualify.d.ts.map +1 -0
  84. package/dist/gir/qualify.js +60 -0
  85. package/dist/gir/qualify.js.map +1 -0
  86. package/dist/gir/repository.d.ts +82 -0
  87. package/dist/gir/repository.d.ts.map +1 -0
  88. package/dist/gir/repository.js +122 -0
  89. package/dist/gir/repository.js.map +1 -0
  90. package/dist/gir/signal.d.ts +22 -0
  91. package/dist/gir/signal.d.ts.map +1 -0
  92. package/dist/gir/signal.js +20 -0
  93. package/dist/gir/signal.js.map +1 -0
  94. package/dist/gir/size.d.ts +67 -0
  95. package/dist/gir/size.d.ts.map +1 -0
  96. package/dist/gir/size.js +87 -0
  97. package/dist/gir/size.js.map +1 -0
  98. package/dist/gir/type-ref.d.ts +79 -0
  99. package/dist/gir/type-ref.d.ts.map +1 -0
  100. package/dist/gir/type-ref.js +101 -0
  101. package/dist/gir/type-ref.js.map +1 -0
  102. package/dist/index.d.ts +12 -0
  103. package/dist/index.d.ts.map +1 -0
  104. package/dist/index.js +12 -0
  105. package/dist/index.js.map +1 -0
  106. package/dist/jsx-store.d.ts +22 -0
  107. package/dist/jsx-store.d.ts.map +1 -0
  108. package/dist/jsx-store.js +40 -0
  109. package/dist/jsx-store.js.map +1 -0
  110. package/dist/react/compounds-meta.d.ts +18 -0
  111. package/dist/react/compounds-meta.d.ts.map +1 -0
  112. package/dist/react/compounds-meta.js +93 -0
  113. package/dist/react/compounds-meta.js.map +1 -0
  114. package/dist/react/compounds.d.ts +27 -0
  115. package/dist/react/compounds.d.ts.map +1 -0
  116. package/dist/react/compounds.js +164 -0
  117. package/dist/react/compounds.js.map +1 -0
  118. package/dist/react/internal.d.ts +14 -0
  119. package/dist/react/internal.d.ts.map +1 -0
  120. package/dist/react/internal.js +79 -0
  121. package/dist/react/internal.js.map +1 -0
  122. package/dist/react/jsx.d.ts +22 -0
  123. package/dist/react/jsx.d.ts.map +1 -0
  124. package/dist/react/jsx.js +134 -0
  125. package/dist/react/jsx.js.map +1 -0
  126. package/dist/react/pipeline.d.ts +13 -0
  127. package/dist/react/pipeline.d.ts.map +1 -0
  128. package/dist/react/pipeline.js +25 -0
  129. package/dist/react/pipeline.js.map +1 -0
  130. package/dist/react/props.d.ts +38 -0
  131. package/dist/react/props.d.ts.map +1 -0
  132. package/dist/react/props.js +231 -0
  133. package/dist/react/props.js.map +1 -0
  134. package/dist/react/slot-props.d.ts +10 -0
  135. package/dist/react/slot-props.d.ts.map +1 -0
  136. package/dist/react/slot-props.js +56 -0
  137. package/dist/react/slot-props.js.map +1 -0
  138. package/dist/react/widgets.d.ts +83 -0
  139. package/dist/react/widgets.d.ts.map +1 -0
  140. package/dist/react/widgets.js +152 -0
  141. package/dist/react/widgets.js.map +1 -0
  142. package/dist/runner.d.ts +55 -0
  143. package/dist/runner.d.ts.map +1 -0
  144. package/dist/runner.js +60 -0
  145. package/dist/runner.js.map +1 -0
  146. package/dist/store-fs.d.ts +109 -0
  147. package/dist/store-fs.d.ts.map +1 -0
  148. package/dist/store-fs.js +98 -0
  149. package/dist/store-fs.js.map +1 -0
  150. package/dist/transpile.d.ts +32 -0
  151. package/dist/transpile.d.ts.map +1 -0
  152. package/dist/transpile.js +63 -0
  153. package/dist/transpile.js.map +1 -0
  154. package/dist/typecheck-store.d.ts +41 -0
  155. package/dist/typecheck-store.d.ts.map +1 -0
  156. package/dist/typecheck-store.js +102 -0
  157. package/dist/typecheck-store.js.map +1 -0
  158. package/dist/writers/alias.d.ts +13 -0
  159. package/dist/writers/alias.d.ts.map +1 -0
  160. package/dist/writers/alias.js +17 -0
  161. package/dist/writers/alias.js.map +1 -0
  162. package/dist/writers/async.d.ts +22 -0
  163. package/dist/writers/async.d.ts.map +1 -0
  164. package/dist/writers/async.js +48 -0
  165. package/dist/writers/async.js.map +1 -0
  166. package/dist/writers/boxed-constructor.d.ts +26 -0
  167. package/dist/writers/boxed-constructor.d.ts.map +1 -0
  168. package/dist/writers/boxed-constructor.js +85 -0
  169. package/dist/writers/boxed-constructor.js.map +1 -0
  170. package/dist/writers/boxed-field-accessor.d.ts +18 -0
  171. package/dist/writers/boxed-field-accessor.d.ts.map +1 -0
  172. package/dist/writers/boxed-field-accessor.js +260 -0
  173. package/dist/writers/boxed-field-accessor.js.map +1 -0
  174. package/dist/writers/boxed-layout.d.ts +27 -0
  175. package/dist/writers/boxed-layout.d.ts.map +1 -0
  176. package/dist/writers/boxed-layout.js +128 -0
  177. package/dist/writers/boxed-layout.js.map +1 -0
  178. package/dist/writers/boxed.d.ts +20 -0
  179. package/dist/writers/boxed.d.ts.map +1 -0
  180. package/dist/writers/boxed.js +71 -0
  181. package/dist/writers/boxed.js.map +1 -0
  182. package/dist/writers/callables.d.ts +124 -0
  183. package/dist/writers/callables.d.ts.map +1 -0
  184. package/dist/writers/callables.js +283 -0
  185. package/dist/writers/callables.js.map +1 -0
  186. package/dist/writers/callback.d.ts +16 -0
  187. package/dist/writers/callback.d.ts.map +1 -0
  188. package/dist/writers/callback.js +38 -0
  189. package/dist/writers/callback.js.map +1 -0
  190. package/dist/writers/class-struct-record.d.ts +31 -0
  191. package/dist/writers/class-struct-record.d.ts.map +1 -0
  192. package/dist/writers/class-struct-record.js +67 -0
  193. package/dist/writers/class-struct-record.js.map +1 -0
  194. package/dist/writers/class-struct.d.ts +22 -0
  195. package/dist/writers/class-struct.d.ts.map +1 -0
  196. package/dist/writers/class-struct.js +85 -0
  197. package/dist/writers/class-struct.js.map +1 -0
  198. package/dist/writers/class.d.ts +16 -0
  199. package/dist/writers/class.d.ts.map +1 -0
  200. package/dist/writers/class.js +307 -0
  201. package/dist/writers/class.js.map +1 -0
  202. package/dist/writers/constant.d.ts +15 -0
  203. package/dist/writers/constant.d.ts.map +1 -0
  204. package/dist/writers/constant.js +23 -0
  205. package/dist/writers/constant.js.map +1 -0
  206. package/dist/writers/constants.d.ts +15 -0
  207. package/dist/writers/constants.d.ts.map +1 -0
  208. package/dist/writers/constants.js +23 -0
  209. package/dist/writers/constants.js.map +1 -0
  210. package/dist/writers/constructor-props.d.ts +32 -0
  211. package/dist/writers/constructor-props.d.ts.map +1 -0
  212. package/dist/writers/constructor-props.js +110 -0
  213. package/dist/writers/constructor-props.js.map +1 -0
  214. package/dist/writers/enum.d.ts +21 -0
  215. package/dist/writers/enum.d.ts.map +1 -0
  216. package/dist/writers/enum.js +48 -0
  217. package/dist/writers/enum.js.map +1 -0
  218. package/dist/writers/function.d.ts +40 -0
  219. package/dist/writers/function.d.ts.map +1 -0
  220. package/dist/writers/function.js +127 -0
  221. package/dist/writers/function.js.map +1 -0
  222. package/dist/writers/gtype-binding.d.ts +19 -0
  223. package/dist/writers/gtype-binding.d.ts.map +1 -0
  224. package/dist/writers/gtype-binding.js +40 -0
  225. package/dist/writers/gtype-binding.js.map +1 -0
  226. package/dist/writers/inheritance.d.ts +48 -0
  227. package/dist/writers/inheritance.d.ts.map +1 -0
  228. package/dist/writers/inheritance.js +90 -0
  229. package/dist/writers/inheritance.js.map +1 -0
  230. package/dist/writers/interface.d.ts +16 -0
  231. package/dist/writers/interface.d.ts.map +1 -0
  232. package/dist/writers/interface.js +155 -0
  233. package/dist/writers/interface.js.map +1 -0
  234. package/dist/writers/method.d.ts +150 -0
  235. package/dist/writers/method.d.ts.map +1 -0
  236. package/dist/writers/method.js +510 -0
  237. package/dist/writers/method.js.map +1 -0
  238. package/dist/writers/param-classify.d.ts +93 -0
  239. package/dist/writers/param-classify.d.ts.map +1 -0
  240. package/dist/writers/param-classify.js +163 -0
  241. package/dist/writers/param-classify.js.map +1 -0
  242. package/dist/writers/property-accessor.d.ts +19 -0
  243. package/dist/writers/property-accessor.d.ts.map +1 -0
  244. package/dist/writers/property-accessor.js +117 -0
  245. package/dist/writers/property-accessor.js.map +1 -0
  246. package/dist/writers/registration.d.ts +27 -0
  247. package/dist/writers/registration.d.ts.map +1 -0
  248. package/dist/writers/registration.js +30 -0
  249. package/dist/writers/registration.js.map +1 -0
  250. package/dist/writers/return-wrap.d.ts +39 -0
  251. package/dist/writers/return-wrap.d.ts.map +1 -0
  252. package/dist/writers/return-wrap.js +152 -0
  253. package/dist/writers/return-wrap.js.map +1 -0
  254. package/dist/writers/runtime-override.d.ts +18 -0
  255. package/dist/writers/runtime-override.d.ts.map +1 -0
  256. package/dist/writers/runtime-override.js +44 -0
  257. package/dist/writers/runtime-override.js.map +1 -0
  258. package/dist/writers/signal.d.ts +21 -0
  259. package/dist/writers/signal.d.ts.map +1 -0
  260. package/dist/writers/signal.js +260 -0
  261. package/dist/writers/signal.js.map +1 -0
  262. package/dist/writers/ts-type.d.ts +50 -0
  263. package/dist/writers/ts-type.d.ts.map +1 -0
  264. package/dist/writers/ts-type.js +75 -0
  265. package/dist/writers/ts-type.js.map +1 -0
  266. package/dist/writers/types-ts.d.ts +27 -0
  267. package/dist/writers/types-ts.d.ts.map +1 -0
  268. package/dist/writers/types-ts.js +97 -0
  269. package/dist/writers/types-ts.js.map +1 -0
  270. package/dist/writers/value.d.ts +89 -0
  271. package/dist/writers/value.d.ts.map +1 -0
  272. package/dist/writers/value.js +402 -0
  273. package/dist/writers/value.js.map +1 -0
  274. package/package.json +55 -0
  275. package/src/dsl/context.ts +146 -0
  276. package/src/dsl/emit.ts +42 -0
  277. package/src/dsl/identifier.ts +52 -0
  278. package/src/dsl/imports.ts +109 -0
  279. package/src/dsl/module.ts +75 -0
  280. package/src/ffi/pipeline.ts +113 -0
  281. package/src/fingerprint.ts +50 -0
  282. package/src/gi-store.ts +199 -0
  283. package/src/gir/boxed.ts +94 -0
  284. package/src/gir/callback.ts +26 -0
  285. package/src/gir/class.ts +79 -0
  286. package/src/gir/enum.ts +55 -0
  287. package/src/gir/field.ts +40 -0
  288. package/src/gir/function.ts +67 -0
  289. package/src/gir/namespace.ts +118 -0
  290. package/src/gir/parameter.ts +120 -0
  291. package/src/gir/parse.ts +171 -0
  292. package/src/gir/primitives.ts +137 -0
  293. package/src/gir/property.ts +39 -0
  294. package/src/gir/qualified-name.ts +55 -0
  295. package/src/gir/qualify.ts +64 -0
  296. package/src/gir/repository.ts +149 -0
  297. package/src/gir/signal.ts +36 -0
  298. package/src/gir/size.ts +129 -0
  299. package/src/gir/type-ref.ts +180 -0
  300. package/src/index.ts +16 -0
  301. package/src/jsx-store.ts +53 -0
  302. package/src/react/compounds-meta.ts +99 -0
  303. package/src/react/compounds.ts +204 -0
  304. package/src/react/internal.ts +91 -0
  305. package/src/react/jsx.ts +155 -0
  306. package/src/react/pipeline.ts +29 -0
  307. package/src/react/props.ts +307 -0
  308. package/src/react/slot-props.ts +57 -0
  309. package/src/react/widgets.ts +185 -0
  310. package/src/runner.ts +89 -0
  311. package/src/store-fs.ts +157 -0
  312. package/src/transpile.ts +80 -0
  313. package/src/typecheck-store.ts +136 -0
  314. package/src/writers/alias.ts +19 -0
  315. package/src/writers/async.ts +44 -0
  316. package/src/writers/boxed-constructor.ts +105 -0
  317. package/src/writers/boxed-field-accessor.ts +306 -0
  318. package/src/writers/boxed-layout.ts +166 -0
  319. package/src/writers/boxed.ts +77 -0
  320. package/src/writers/callables.ts +339 -0
  321. package/src/writers/callback.ts +40 -0
  322. package/src/writers/class-struct-record.ts +75 -0
  323. package/src/writers/class-struct.ts +96 -0
  324. package/src/writers/class.ts +384 -0
  325. package/src/writers/constant.ts +29 -0
  326. package/src/writers/constructor-props.ts +130 -0
  327. package/src/writers/enum.ts +53 -0
  328. package/src/writers/function.ts +136 -0
  329. package/src/writers/gtype-binding.ts +48 -0
  330. package/src/writers/inheritance.ts +104 -0
  331. package/src/writers/interface.ts +168 -0
  332. package/src/writers/method.ts +678 -0
  333. package/src/writers/param-classify.ts +178 -0
  334. package/src/writers/property-accessor.ts +139 -0
  335. package/src/writers/registration.ts +42 -0
  336. package/src/writers/return-wrap.ts +180 -0
  337. package/src/writers/runtime-override.ts +59 -0
  338. package/src/writers/signal.ts +318 -0
  339. package/src/writers/ts-type.ts +115 -0
  340. package/src/writers/value.ts +485 -0
@@ -0,0 +1,64 @@
1
+ import type { GirFunction } from "./function.js";
2
+ import type { GirParameter } from "./parameter.js";
3
+ import type { GirTypeRef } from "./type-ref.js";
4
+
5
+ /**
6
+ * Stamps a default namespace onto an unqualified `named` reference and
7
+ * recurses into composite (`array`, `list`, `hashtable`) references.
8
+ *
9
+ * GIR omits the namespace when a reference points to a sibling in the same
10
+ * file. When writers walk a class hierarchy across namespaces, the parent's
11
+ * references must be qualified with the parent's namespace before they can be
12
+ * resolved against the repository.
13
+ *
14
+ * Returns `undefined` for an `undefined` input so callers can pass through
15
+ * void return types unchanged.
16
+ *
17
+ * @param ref - The reference to qualify, or `undefined`
18
+ * @param defaultNamespace - The namespace to stamp on unqualified refs
19
+ */
20
+ export const qualifyTypeRef = (ref: GirTypeRef | undefined, defaultNamespace: string): GirTypeRef | undefined => {
21
+ if (ref === undefined) return undefined;
22
+ switch (ref.kind) {
23
+ case "named":
24
+ return { ...ref, namespaceName: ref.namespaceName ?? defaultNamespace };
25
+ case "array":
26
+ return { ...ref, element: qualifyTypeRef(ref.element, defaultNamespace) ?? ref.element };
27
+ case "list":
28
+ return { ...ref, element: qualifyTypeRef(ref.element, defaultNamespace) ?? ref.element };
29
+ case "hashtable":
30
+ return {
31
+ ...ref,
32
+ key: qualifyTypeRef(ref.key, defaultNamespace) ?? ref.key,
33
+ value: qualifyTypeRef(ref.value, defaultNamespace) ?? ref.value,
34
+ };
35
+ case "primitive":
36
+ case "callback":
37
+ case "varargs":
38
+ return ref;
39
+ }
40
+ };
41
+
42
+ const qualifyParameter = (parameter: GirParameter, defaultNamespace: string): GirParameter => ({
43
+ ...parameter,
44
+ type: qualifyTypeRef(parameter.type, defaultNamespace),
45
+ });
46
+
47
+ /**
48
+ * Re-roots every type reference of a callable to `defaultNamespace`.
49
+ *
50
+ * Interface methods are flattened onto each implementing class, but their
51
+ * GIR type references are unqualified relative to the interface's own
52
+ * namespace. Stamping the interface namespace onto the instance parameter,
53
+ * each regular parameter, and the return value lets the class writer resolve
54
+ * and import those references as if the method had been authored on the class.
55
+ *
56
+ * @param fn - The callable whose references to qualify
57
+ * @param defaultNamespace - The namespace the callable's references belong to
58
+ */
59
+ export const qualifyFunction = (fn: GirFunction, defaultNamespace: string): GirFunction => ({
60
+ ...fn,
61
+ instance: fn.instance === undefined ? undefined : qualifyParameter(fn.instance, defaultNamespace),
62
+ parameters: fn.parameters.map((parameter) => qualifyParameter(parameter, defaultNamespace)),
63
+ returnValue: { ...fn.returnValue, type: qualifyTypeRef(fn.returnValue.type, defaultNamespace) },
64
+ });
@@ -0,0 +1,149 @@
1
+ import { existsSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import type { GirBoxed } from "./boxed.js";
4
+ import type { GirCallback } from "./callback.js";
5
+ import type { GirClass } from "./class.js";
6
+ import type { GirEnum } from "./enum.js";
7
+ import { type GirNamespace, namespaceFromRepository } from "./namespace.js";
8
+ import { parseGirFile } from "./parse.js";
9
+ import type { GirTypeRef } from "./type-ref.js";
10
+
11
+ /**
12
+ * Resolved entity that a {@link GirRepository.resolveNamed} call returns.
13
+ *
14
+ * Wraps the matching entity along with the namespace it lives in, so
15
+ * writers can pull the namespace identifier or shared library name without
16
+ * a second lookup.
17
+ */
18
+ export type ResolvedNamed =
19
+ | { readonly kind: "class"; readonly namespace: GirNamespace; readonly value: GirClass }
20
+ | { readonly kind: "interface"; readonly namespace: GirNamespace; readonly value: GirClass }
21
+ | { readonly kind: "boxed"; readonly namespace: GirNamespace; readonly value: GirBoxed }
22
+ | { readonly kind: "enum"; readonly namespace: GirNamespace; readonly value: GirEnum }
23
+ | { readonly kind: "callback"; readonly namespace: GirNamespace; readonly value: GirCallback }
24
+ | {
25
+ readonly kind: "alias";
26
+ readonly namespace: GirNamespace;
27
+ readonly target: string | undefined;
28
+ readonly targetRef: GirTypeRef | undefined;
29
+ };
30
+
31
+ /**
32
+ * In-memory database of every loaded GIR namespace, indexed by name.
33
+ *
34
+ * Construct via {@link loadGirRepository}; the public API after that is the
35
+ * `namespaces` map and {@link resolveNamed} for cross-namespace lookups.
36
+ */
37
+ export class GirRepository {
38
+ /** Namespaces keyed by their unqualified name (e.g. `"Gtk"`, `"GLib"`). */
39
+ public readonly namespaces: ReadonlyMap<string, GirNamespace>;
40
+ /** Absolute paths of every `.gir` file loaded, for staleness fingerprinting. */
41
+ public readonly girFiles: readonly string[];
42
+ private readonly entityIndex: Map<string, ResolvedNamed>;
43
+
44
+ /**
45
+ * Constructs a repository from the supplied namespace map.
46
+ *
47
+ * Callers should prefer {@link loadGirRepository} which discovers and
48
+ * parses files for you.
49
+ *
50
+ * @param namespaces - Namespaces keyed by unqualified name
51
+ * @param girFiles - Absolute paths of the `.gir` files the namespaces came from
52
+ */
53
+ constructor(namespaces: ReadonlyMap<string, GirNamespace>, girFiles: readonly string[] = []) {
54
+ this.namespaces = namespaces;
55
+ this.girFiles = girFiles;
56
+ this.entityIndex = new Map();
57
+ for (const namespace of namespaces.values()) {
58
+ indexNamespace(this.entityIndex, namespace);
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Looks up a type by `(namespace, name)`. Aliases are followed one step
64
+ * to their target. Returns `undefined` when neither the namespace nor a
65
+ * matching entity exists.
66
+ *
67
+ * @param namespaceName - Namespace to look in (e.g. `"GLib"`)
68
+ * @param typeName - Local type name within the namespace (e.g. `"Variant"`)
69
+ */
70
+ resolveNamed(namespaceName: string, typeName: string): ResolvedNamed | undefined {
71
+ const key = entityKey(namespaceName, typeName);
72
+ const direct = this.entityIndex.get(key);
73
+ if (direct !== undefined) return direct;
74
+ return undefined;
75
+ }
76
+ }
77
+
78
+ const entityKey = (namespaceName: string, typeName: string): string => `${namespaceName}.${typeName}`;
79
+
80
+ const indexNamespace = (index: Map<string, ResolvedNamed>, namespace: GirNamespace): void => {
81
+ for (const value of namespace.classes) {
82
+ index.set(entityKey(namespace.name, value.name), { kind: "class", namespace, value });
83
+ }
84
+ for (const value of namespace.interfaces) {
85
+ index.set(entityKey(namespace.name, value.name), { kind: "interface", namespace, value });
86
+ }
87
+ for (const value of namespace.boxeds) {
88
+ index.set(entityKey(namespace.name, value.name), { kind: "boxed", namespace, value });
89
+ }
90
+ for (const value of namespace.enums) {
91
+ index.set(entityKey(namespace.name, value.name), { kind: "enum", namespace, value });
92
+ }
93
+ for (const value of namespace.callbacks) {
94
+ index.set(entityKey(namespace.name, value.name), { kind: "callback", namespace, value });
95
+ }
96
+ for (const alias of namespace.aliases) {
97
+ const target = alias.target?.kind === "named" ? alias.target.typeName : undefined;
98
+ index.set(entityKey(namespace.name, alias.name), {
99
+ kind: "alias",
100
+ namespace,
101
+ target,
102
+ targetRef: alias.target,
103
+ });
104
+ }
105
+ };
106
+
107
+ /**
108
+ * Discovers and parses every GIR file needed to satisfy `libraries` and
109
+ * their transitive `<include>` dependencies.
110
+ *
111
+ * @param libraries - Resolved `Name-Version` namespace identifiers
112
+ * @param girPath - Ordered list of directories to search for `.gir` files
113
+ * @returns A populated {@link GirRepository}
114
+ * @throws If any required GIR file cannot be located on `girPath`
115
+ */
116
+ export const loadGirRepository = (libraries: readonly string[], girPath: readonly string[]): GirRepository => {
117
+ const namespaces = new Map<string, GirNamespace>();
118
+ const girFiles: string[] = [];
119
+ const queue: string[] = [...libraries];
120
+ while (queue.length > 0) {
121
+ const identifier = queue.shift();
122
+ if (identifier === undefined) continue;
123
+ const namespaceName = identifier.split("-")[0] ?? identifier;
124
+ if (namespaces.has(namespaceName)) continue;
125
+ const path = locateGirFile(identifier, girPath);
126
+ girFiles.push(path);
127
+ const root = parseGirFile(path);
128
+ const repository = root.repository;
129
+ if (typeof repository !== "object" || repository === null) {
130
+ throw new Error(`GIR file at ${path} has no <repository> root`);
131
+ }
132
+ const namespace = namespaceFromRepository(repository as Record<string, unknown>);
133
+ namespaces.set(namespace.name, namespace);
134
+ for (const include of namespace.includes) {
135
+ queue.push(`${include.name}-${include.version}`);
136
+ }
137
+ }
138
+ return new GirRepository(namespaces, girFiles);
139
+ };
140
+
141
+ const locateGirFile = (identifier: string, girPath: readonly string[]): string => {
142
+ const filename = `${identifier}.gir`;
143
+ for (const directory of girPath) {
144
+ const candidate = join(directory, filename);
145
+ if (existsSync(candidate)) return candidate;
146
+ }
147
+ const tried = girPath.map((directory) => join(directory, filename)).join(", ");
148
+ throw new Error(`GIR file ${filename} not found on girPath. Tried: ${tried}`);
149
+ };
@@ -0,0 +1,36 @@
1
+ import { type GirParameter, type GirReturnValue, parameterFromNode, returnValueFromNode } from "./parameter.js";
2
+ import { attr, attrBool, childOf, childrenOf, type RawNode } from "./parse.js";
3
+
4
+ /** Emission stage (`<glib:signal when="…">`). */
5
+ type SignalWhen = "first" | "last" | "cleanup";
6
+
7
+ /** A GObject `<glib:signal>` declaration. */
8
+ export type GirSignal = {
9
+ /** GIR signal name, kebab-case (e.g. `"activate-link"`). */
10
+ readonly name: string;
11
+ readonly parameters: readonly GirParameter[];
12
+ readonly returnValue: GirReturnValue;
13
+ readonly when: SignalWhen;
14
+ readonly detailed: boolean;
15
+ readonly action: boolean;
16
+ readonly noRecurse: boolean;
17
+ readonly noHooks: boolean;
18
+ };
19
+
20
+ /**
21
+ * Builds a {@link GirSignal} from a `<glib:signal>` element.
22
+ */
23
+ export const signalFromNode = (node: RawNode): GirSignal => {
24
+ const parametersNode = childOf(node, "parameters");
25
+ const parameterNodes = childrenOf(parametersNode, "parameter");
26
+ return {
27
+ name: attr(node, "name") ?? "",
28
+ parameters: parameterNodes.map((parameter) => parameterFromNode(parameter, false)),
29
+ returnValue: returnValueFromNode(childOf(node, "return-value")),
30
+ when: (attr(node, "when") ?? "last") as SignalWhen,
31
+ detailed: attrBool(node, "detailed"),
32
+ action: attrBool(node, "action"),
33
+ noRecurse: attrBool(node, "no-recurse"),
34
+ noHooks: attrBool(node, "no-hooks"),
35
+ };
36
+ };
@@ -0,0 +1,129 @@
1
+ import { PRIMITIVE_SIZE, type PrimitiveCategory } from "./primitives.js";
2
+
3
+ /**
4
+ * Size and alignment of a single field as it appears in a C struct laid out
5
+ * according to the x86-64 ABI.
6
+ */
7
+ export type FieldLayout = {
8
+ /** Width of the field in bytes. */
9
+ readonly size: number;
10
+ /** Required alignment in bytes; storage offset rounds up to a multiple of this. */
11
+ readonly align: number;
12
+ };
13
+
14
+ /**
15
+ * Returns the `{ size, align }` pair for a primitive category.
16
+ *
17
+ * Pointers and pointer-sized integers (the `pointer` and 64-bit categories)
18
+ * report 8/8. Smaller integers and floats report their natural width.
19
+ *
20
+ * @param category - The primitive category
21
+ */
22
+ export const layoutOfPrimitive = (category: PrimitiveCategory): FieldLayout => {
23
+ const size = PRIMITIVE_SIZE[category];
24
+ return { size, align: size === 0 ? 1 : size };
25
+ };
26
+
27
+ const roundUp = (value: number, multiple: number): number => {
28
+ if (multiple <= 1) return value;
29
+ const remainder = value % multiple;
30
+ return remainder === 0 ? value : value + (multiple - remainder);
31
+ };
32
+
33
+ /**
34
+ * Layout slot for a single field that may participate in bitfield packing.
35
+ *
36
+ * `byteOffset` is always the offset of the underlying storage word; for
37
+ * non-bitfield fields it is the field's offset directly, and for bitfield
38
+ * members it is the start of the shared storage unit. `bitOffset` and
39
+ * `bitWidth` are populated only for bitfield members.
40
+ */
41
+ export type FieldSlot = {
42
+ /** Byte offset of the storage word the field occupies. */
43
+ readonly byteOffset: number;
44
+ /** Bit position within the storage word, for bitfield members. */
45
+ readonly bitOffset: number | undefined;
46
+ /** Width in bits, for bitfield members. */
47
+ readonly bitWidth: number | undefined;
48
+ };
49
+
50
+ /**
51
+ * Describes a field for the purposes of layout computation.
52
+ */
53
+ export type FieldLayoutInput = {
54
+ /** Natural byte size and alignment of the field's value type. */
55
+ readonly layout: FieldLayout;
56
+ /** When set, the field is a bitfield member with this many bits. */
57
+ readonly bits: number | undefined;
58
+ };
59
+
60
+ /**
61
+ * Computes per-field byte offsets for a record, grouping consecutive
62
+ * bitfield members of compatible storage widths into a shared storage
63
+ * word.
64
+ *
65
+ * Mirrors the GCC/Itanium ABI rules for C bitfield packing in a
66
+ * single-storage-word model: a new storage word is opened when the
67
+ * underlying type's size changes, when the new field is not a bitfield,
68
+ * or when adding the bits would exceed the word's bit count.
69
+ *
70
+ * A union (`isUnion`) overlays every member at byte offset 0; its size is the
71
+ * largest member rounded up to the strongest member alignment.
72
+ *
73
+ * @param fields - Ordered field layouts and bit widths
74
+ * @param isUnion - Whether the fields are union members (overlaid at offset 0)
75
+ * @returns Parallel slot array and the total record size in bytes
76
+ */
77
+ export const computeFieldSlots = (
78
+ fields: readonly FieldLayoutInput[],
79
+ isUnion = false,
80
+ ): { readonly slots: readonly FieldSlot[]; readonly size: number } => {
81
+ if (isUnion) {
82
+ let maxSize = 0;
83
+ let maxAlign = 1;
84
+ const unionSlots = fields.map((field) => {
85
+ maxSize = Math.max(maxSize, field.layout.size);
86
+ maxAlign = Math.max(maxAlign, field.layout.align);
87
+ return { byteOffset: 0, bitOffset: field.bits === undefined ? undefined : 0, bitWidth: field.bits };
88
+ });
89
+ return { slots: unionSlots, size: roundUp(maxSize, maxAlign) };
90
+ }
91
+ const slots: FieldSlot[] = [];
92
+ let cursor = 0;
93
+ let maxAlign = 1;
94
+ let bitfieldWordOffset: number | undefined;
95
+ let bitfieldWordSize = 0;
96
+ let bitfieldUsedBits = 0;
97
+ for (const field of fields) {
98
+ const align = Math.max(1, field.layout.align);
99
+ if (align > maxAlign) maxAlign = align;
100
+ if (field.bits === undefined) {
101
+ bitfieldWordOffset = undefined;
102
+ bitfieldWordSize = 0;
103
+ bitfieldUsedBits = 0;
104
+ cursor = roundUp(cursor, align);
105
+ slots.push({ byteOffset: cursor, bitOffset: undefined, bitWidth: undefined });
106
+ cursor += field.layout.size;
107
+ continue;
108
+ }
109
+ const wordSizeBits = field.layout.size * 8;
110
+ const fits =
111
+ bitfieldWordOffset !== undefined &&
112
+ bitfieldWordSize === field.layout.size &&
113
+ bitfieldUsedBits + field.bits <= wordSizeBits;
114
+ if (!fits) {
115
+ cursor = roundUp(cursor, align);
116
+ bitfieldWordOffset = cursor;
117
+ bitfieldWordSize = field.layout.size;
118
+ bitfieldUsedBits = 0;
119
+ cursor += field.layout.size;
120
+ }
121
+ slots.push({
122
+ byteOffset: bitfieldWordOffset ?? 0,
123
+ bitOffset: bitfieldUsedBits,
124
+ bitWidth: field.bits,
125
+ });
126
+ bitfieldUsedBits += field.bits;
127
+ }
128
+ return { slots, size: roundUp(cursor, maxAlign) };
129
+ };
@@ -0,0 +1,180 @@
1
+ import { attr, attrBool, childOf, childrenOf, type RawNode } from "./parse.js";
2
+ import { type PrimitiveCategory, primitiveCategory } from "./primitives.js";
3
+
4
+ /**
5
+ * Lazily-resolved reference to a GIR type as it appears in a `<type>` or
6
+ * `<array>` slot.
7
+ *
8
+ * The reference captures everything the writers need at emission time
9
+ * without forcing entity resolution to happen at parse time (which would
10
+ * impose a topological-sort order on namespace loading). Resolution into a
11
+ * concrete `GirClass` / `GirBoxed` / `GirEnum` / … is performed on demand
12
+ * by the writers via `GirRepository.resolveNamed`.
13
+ */
14
+ export type GirTypeRef =
15
+ | PrimitiveTypeRef
16
+ | NamedTypeRef
17
+ | ArrayTypeRef
18
+ | ListTypeRef
19
+ | HashTableTypeRef
20
+ | InlineCallbackTypeRef
21
+ | VarargsTypeRef;
22
+
23
+ /** A GIR scalar primitive: `gint`, `gboolean`, `utf8`, `gpointer`, etc. */
24
+ export type PrimitiveTypeRef = {
25
+ readonly kind: "primitive";
26
+ readonly category: PrimitiveCategory;
27
+ readonly cType: string | undefined;
28
+ };
29
+
30
+ /**
31
+ * A named type that resolves to a class, interface, boxed, enum, alias, or
32
+ * fundamental in some namespace.
33
+ *
34
+ * `namespaceName` is the namespace prefix from the GIR (`"GLib"`, `"Gtk"`,
35
+ * …) or `undefined` for an unqualified reference. The unqualified form
36
+ * implies "look in the namespace the reference appears in".
37
+ */
38
+ export type NamedTypeRef = {
39
+ readonly kind: "named";
40
+ readonly namespaceName: string | undefined;
41
+ readonly typeName: string;
42
+ readonly cType: string | undefined;
43
+ };
44
+
45
+ /** A C array (`<array>`) with optional length, fixed-size, or zero-terminated metadata. */
46
+ export type ArrayTypeRef = {
47
+ readonly kind: "array";
48
+ readonly element: GirTypeRef;
49
+ readonly cType: string | undefined;
50
+ readonly lengthParameterIndex: number | undefined;
51
+ readonly fixedSize: number | undefined;
52
+ readonly zeroTerminated: boolean;
53
+ };
54
+
55
+ /** A GLib `GList` / `GSList` / `GPtrArray` / `GArray` / `GByteArray`. */
56
+ export type ListTypeRef = {
57
+ readonly kind: "list";
58
+ readonly flavor: "glist" | "gslist" | "gptrarray" | "garray" | "gbytearray";
59
+ readonly element: GirTypeRef;
60
+ readonly cType: string | undefined;
61
+ };
62
+
63
+ /** A GLib `GHashTable` with key and value element types. */
64
+ export type HashTableTypeRef = {
65
+ readonly kind: "hashtable";
66
+ readonly key: GirTypeRef;
67
+ readonly value: GirTypeRef;
68
+ readonly cType: string | undefined;
69
+ };
70
+
71
+ /** An inline `<callback>` (used for vtable slots and callback parameters). */
72
+ type InlineCallbackTypeRef = {
73
+ readonly kind: "callback";
74
+ readonly callback: RawNode;
75
+ };
76
+
77
+ /** A `<varargs/>` parameter placeholder; not marshalable. */
78
+ type VarargsTypeRef = { readonly kind: "varargs" };
79
+
80
+ const LIST_KIND_BY_NAME: ReadonlyMap<string, "glist" | "gslist" | "gptrarray" | "garray" | "gbytearray"> = new Map([
81
+ ["GLib.List", "glist"],
82
+ ["GLib.SList", "gslist"],
83
+ ["GLib.PtrArray", "gptrarray"],
84
+ ["GLib.Array", "garray"],
85
+ ["GLib.ByteArray", "gbytearray"],
86
+ ] as const);
87
+
88
+ /**
89
+ * Builds a {@link GirTypeRef} from a parent XML node whose first `<type>`,
90
+ * `<array>`, or `<varargs>` child describes the slot.
91
+ *
92
+ * Pass the parent (`<parameter>`, `<return-value>`, `<field>`, `<property>`,
93
+ * `<constant>`, `<alias>`). The helper extracts the right child and routes
94
+ * to {@link typeRefFromTypeNode}.
95
+ *
96
+ * @param parent - The element whose typed slot we are inspecting
97
+ * @returns The reference, or `undefined` if no type slot exists
98
+ */
99
+ export const typeRefFromSlot = (parent: RawNode | undefined): GirTypeRef | undefined => {
100
+ if (parent === undefined) return undefined;
101
+ if (childOf(parent, "varargs") !== undefined) return { kind: "varargs" };
102
+ const arrayNode = childOf(parent, "array");
103
+ if (arrayNode !== undefined) return arrayTypeRefFromNode(arrayNode);
104
+ const typeNode = childOf(parent, "type");
105
+ if (typeNode !== undefined) return typeRefFromTypeNode(typeNode);
106
+ const callback = childOf(parent, "callback");
107
+ if (callback !== undefined) return { kind: "callback", callback };
108
+ return undefined;
109
+ };
110
+
111
+ /**
112
+ * Builds a {@link GirTypeRef} from a `<type>` element.
113
+ *
114
+ * Splits a `Namespace.TypeName` form into namespace + type, recognises GLib
115
+ * container types (`GLib.List`, `GLib.HashTable`, …) by name and routes
116
+ * them to the dedicated branches, otherwise produces a primitive or named
117
+ * reference for later resolution.
118
+ *
119
+ * @param typeNode - A `<type>` element
120
+ */
121
+ const typeRefFromTypeNode = (typeNode: RawNode): GirTypeRef => {
122
+ const name = attr(typeNode, "name") ?? "";
123
+ const cType = attr(typeNode, "c:type");
124
+
125
+ const listFlavor = LIST_KIND_BY_NAME.get(name);
126
+ if (listFlavor !== undefined) {
127
+ const elementNode = childOf(typeNode, "type");
128
+ const element = elementNode === undefined ? pointerFallback() : typeRefFromTypeNode(elementNode);
129
+ return { kind: "list", flavor: listFlavor, element, cType };
130
+ }
131
+
132
+ if (name === "GLib.HashTable") {
133
+ const elementTypes = childrenOf(typeNode, "type");
134
+ const keyNode = elementTypes[0];
135
+ const valueNode = elementTypes[1];
136
+ return {
137
+ kind: "hashtable",
138
+ key: keyNode === undefined ? pointerFallback() : typeRefFromTypeNode(keyNode),
139
+ value: valueNode === undefined ? pointerFallback() : typeRefFromTypeNode(valueNode),
140
+ cType,
141
+ };
142
+ }
143
+
144
+ const primitive = primitiveCategory(name);
145
+ if (primitive !== undefined) {
146
+ return { kind: "primitive", category: primitive, cType };
147
+ }
148
+
149
+ const [namespaceName, typeName] = splitOptionalNamespace(name);
150
+ return { kind: "named", namespaceName, typeName, cType };
151
+ };
152
+
153
+ const arrayTypeRefFromNode = (arrayNode: RawNode): ArrayTypeRef | ListTypeRef => {
154
+ const elementNode = childOf(arrayNode, "type");
155
+ const element: GirTypeRef = elementNode === undefined ? pointerFallback() : typeRefFromTypeNode(elementNode);
156
+ const cType = attr(arrayNode, "c:type");
157
+ const arrayName = attr(arrayNode, "name");
158
+ const listFlavor = arrayName === undefined ? undefined : LIST_KIND_BY_NAME.get(arrayName);
159
+ if (listFlavor !== undefined) {
160
+ return { kind: "list", flavor: listFlavor, element, cType };
161
+ }
162
+ const lengthAttr = attr(arrayNode, "length");
163
+ const fixedSizeAttr = attr(arrayNode, "fixed-size");
164
+ return {
165
+ kind: "array",
166
+ element,
167
+ cType,
168
+ lengthParameterIndex: lengthAttr === undefined ? undefined : Number.parseInt(lengthAttr, 10),
169
+ fixedSize: fixedSizeAttr === undefined ? undefined : Number.parseInt(fixedSizeAttr, 10),
170
+ zeroTerminated: attrBool(arrayNode, "zero-terminated", false),
171
+ };
172
+ };
173
+
174
+ const pointerFallback = (): PrimitiveTypeRef => ({ kind: "primitive", category: "pointer", cType: undefined });
175
+
176
+ const splitOptionalNamespace = (name: string): [string | undefined, string] => {
177
+ const dot = name.indexOf(".");
178
+ if (dot === -1) return [undefined, name];
179
+ return [name.slice(0, dot), name.slice(dot + 1)];
180
+ };
package/src/index.ts ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Public API of `@gtkx/codegen`.
3
+ *
4
+ * The package exposes a single entry point — {@link CodegenRunner} — that
5
+ * orchestrates the GIR-driven code generation for the FFI and React
6
+ * surfaces. Internal modules (`gir/`, `dsl/`, `writers/`, `ffi/`,
7
+ * `react/`) are not part of the supported surface and may change in any
8
+ * release.
9
+ */
10
+ export {
11
+ CODEGEN_VERSION,
12
+ type CodegenFingerprint,
13
+ computeFingerprint,
14
+ FINGERPRINT_FILENAME,
15
+ } from "./fingerprint.js";
16
+ export { CodegenRunner } from "./runner.js";
@@ -0,0 +1,53 @@
1
+ import { type StoreOptions, writeStore } from "./store-fs.js";
2
+
3
+ /**
4
+ * Options for assembling the injected `@gtkx/react-jsx` unit.
5
+ */
6
+ export type JsxStoreOptions = StoreOptions & {
7
+ /** Absolute path to the gi store, for the unit's own `node_modules/@gtkx/gi`. */
8
+ readonly giStoreDir: string;
9
+ /** Real (symlink-resolved) directory of the installed `react` runtime. */
10
+ readonly realReactRuntimeDir: string;
11
+ /** Real (symlink-resolved) directory of the installed `@gtkx/react`. */
12
+ readonly realReactPackageDir: string;
13
+ };
14
+
15
+ const stem = (relativePath: string): string => relativePath.replace(/\.(tsx|ts)$/, "");
16
+
17
+ /**
18
+ * Assembles the self-contained injected `@gtkx/react-jsx` unit: the generated
19
+ * `jsx`/`internal`/`compounds` modules plus a `package.json` and the unit's own
20
+ * `node_modules` symlinks to `@gtkx/gi` and `react`.
21
+ *
22
+ * @param options - Resolved store/link/dependency paths
23
+ * @param files - React pipeline output keyed by source filename
24
+ */
25
+ export const writeJsxStore = (options: JsxStoreOptions, files: ReadonlyMap<string, string>): void => {
26
+ writeStore({
27
+ storeDir: options.storeDir,
28
+ linkDir: options.linkDir,
29
+ files: [...files].map(([relativePath, source]) => ({
30
+ stem: stem(relativePath),
31
+ fileName: relativePath,
32
+ source,
33
+ })),
34
+ manifest: {
35
+ name: "@gtkx/react-jsx",
36
+ type: "module",
37
+ version: options.version,
38
+ sideEffects: ["./internal.js"],
39
+ exports: {
40
+ "./package.json": "./package.json",
41
+ ".": { types: "./jsx.d.ts", default: "./jsx.js" },
42
+ "./jsx": { types: "./jsx.d.ts", default: "./jsx.js" },
43
+ "./compounds": { types: "./compounds.d.ts", default: "./compounds.js" },
44
+ "./internal": { types: "./internal.d.ts", default: "./internal.js" },
45
+ },
46
+ },
47
+ symlinks: [
48
+ { segments: ["node_modules", "@gtkx", "gi"], target: options.giStoreDir },
49
+ { segments: ["node_modules", "@gtkx", "react"], target: options.realReactPackageDir },
50
+ { segments: ["node_modules", "react"], target: options.realReactRuntimeDir },
51
+ ],
52
+ });
53
+ };