@gtkx/codegen 1.0.0-rc.3 → 1.0.0-rc.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 (229) hide show
  1. package/README.md +4 -5
  2. package/dist/analysis/descriptor-render.d.ts +1 -3
  3. package/dist/analysis/descriptor-render.d.ts.map +1 -1
  4. package/dist/analysis/descriptor-render.js +14 -37
  5. package/dist/analysis/descriptor-render.js.map +1 -1
  6. package/dist/analysis/descriptor.d.ts +6 -6
  7. package/dist/analysis/descriptor.d.ts.map +1 -1
  8. package/dist/analysis/descriptor.js +7 -7
  9. package/dist/analysis/descriptor.js.map +1 -1
  10. package/dist/analysis/param-structure.d.ts +2 -2
  11. package/dist/analysis/param-structure.d.ts.map +1 -1
  12. package/dist/analysis/param-structure.js +5 -7
  13. package/dist/analysis/param-structure.js.map +1 -1
  14. package/dist/analysis/ts-type.d.ts +1 -1
  15. package/dist/analysis/ts-type.d.ts.map +1 -1
  16. package/dist/analysis/ts-type.js +3 -5
  17. package/dist/analysis/ts-type.js.map +1 -1
  18. package/dist/compile.d.ts.map +1 -1
  19. package/dist/compile.js +2 -1
  20. package/dist/compile.js.map +1 -1
  21. package/dist/docs/api-reference.d.ts +77 -1
  22. package/dist/docs/api-reference.d.ts.map +1 -1
  23. package/dist/docs/api-reference.js +62 -0
  24. package/dist/docs/api-reference.js.map +1 -1
  25. package/dist/docs/pipeline.d.ts +4 -4
  26. package/dist/docs/pipeline.d.ts.map +1 -1
  27. package/dist/docs/pipeline.js +4 -4
  28. package/dist/docs/pipeline.js.map +1 -1
  29. package/dist/docs/render.js +6 -6
  30. package/dist/docs/render.js.map +1 -1
  31. package/dist/docs/symbol-page.d.ts +5 -0
  32. package/dist/docs/symbol-page.d.ts.map +1 -1
  33. package/dist/docs/symbol-page.js +2 -2
  34. package/dist/docs/symbol-page.js.map +1 -1
  35. package/dist/fingerprint.d.ts +2 -5
  36. package/dist/fingerprint.d.ts.map +1 -1
  37. package/dist/fingerprint.js +6 -8
  38. package/dist/fingerprint.js.map +1 -1
  39. package/dist/gi.d.ts +3 -11
  40. package/dist/gi.d.ts.map +1 -1
  41. package/dist/gi.js +0 -7
  42. package/dist/gi.js.map +1 -1
  43. package/dist/gir/field.d.ts +0 -1
  44. package/dist/gir/field.d.ts.map +1 -1
  45. package/dist/gir/field.js +0 -3
  46. package/dist/gir/field.js.map +1 -1
  47. package/dist/gir/gir-path.d.ts +7 -0
  48. package/dist/gir/gir-path.d.ts.map +1 -1
  49. package/dist/gir/gir-path.js +7 -0
  50. package/dist/gir/gir-path.js.map +1 -1
  51. package/dist/gir/libraries.d.ts +13 -0
  52. package/dist/gir/libraries.d.ts.map +1 -1
  53. package/dist/gir/libraries.js +12 -0
  54. package/dist/gir/libraries.js.map +1 -1
  55. package/dist/gir/parameter.d.ts.map +1 -1
  56. package/dist/gir/parameter.js +0 -4
  57. package/dist/gir/parameter.js.map +1 -1
  58. package/dist/gir/size.d.ts.map +1 -1
  59. package/dist/gir/size.js +0 -3
  60. package/dist/gir/size.js.map +1 -1
  61. package/dist/gir/type-id.d.ts +1 -1
  62. package/dist/gir/type-id.d.ts.map +1 -1
  63. package/dist/gir/type-id.js +1 -3
  64. package/dist/gir/type-id.js.map +1 -1
  65. package/dist/gir/type-ref.js +1 -1
  66. package/dist/gir/type-ref.js.map +1 -1
  67. package/dist/index.d.ts +18 -6
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/index.js +12 -3
  70. package/dist/index.js.map +1 -1
  71. package/dist/internal.d.ts +3 -0
  72. package/dist/internal.d.ts.map +1 -0
  73. package/dist/internal.js +3 -0
  74. package/dist/internal.js.map +1 -0
  75. package/dist/jsx.d.ts +7 -12
  76. package/dist/jsx.d.ts.map +1 -1
  77. package/dist/jsx.js +18 -19
  78. package/dist/jsx.js.map +1 -1
  79. package/dist/khronos/args.d.ts.map +1 -1
  80. package/dist/khronos/args.js +1 -1
  81. package/dist/khronos/args.js.map +1 -1
  82. package/dist/khronos/pipeline.js +1 -1
  83. package/dist/khronos/pipeline.js.map +1 -1
  84. package/dist/khronos/plan.d.ts +2 -2
  85. package/dist/khronos/plan.d.ts.map +1 -1
  86. package/dist/khronos/plan.js +6 -6
  87. package/dist/khronos/plan.js.map +1 -1
  88. package/dist/react/element-config.d.ts +17 -11
  89. package/dist/react/element-config.d.ts.map +1 -1
  90. package/dist/react/element-config.js +22 -15
  91. package/dist/react/element-config.js.map +1 -1
  92. package/dist/runner.d.ts +35 -17
  93. package/dist/runner.d.ts.map +1 -1
  94. package/dist/runner.js +19 -20
  95. package/dist/runner.js.map +1 -1
  96. package/dist/store/compile-store.d.ts +1 -2
  97. package/dist/store/compile-store.d.ts.map +1 -1
  98. package/dist/store/compile-store.js +2 -2
  99. package/dist/store/compile-store.js.map +1 -1
  100. package/dist/store/gi/callables.js +4 -4
  101. package/dist/store/gi/callables.js.map +1 -1
  102. package/dist/store/gi/constant.d.ts.map +1 -1
  103. package/dist/store/gi/constant.js +0 -2
  104. package/dist/store/gi/constant.js.map +1 -1
  105. package/dist/store/gi/function.d.ts.map +1 -1
  106. package/dist/store/gi/function.js +1 -5
  107. package/dist/store/gi/function.js.map +1 -1
  108. package/dist/store/gi/method.d.ts.map +1 -1
  109. package/dist/store/gi/method.js +25 -23
  110. package/dist/store/gi/method.js.map +1 -1
  111. package/dist/store/gi/property-accessor.d.ts +1 -1
  112. package/dist/store/gi/property-accessor.d.ts.map +1 -1
  113. package/dist/store/gi/property-accessor.js +5 -7
  114. package/dist/store/gi/property-accessor.js.map +1 -1
  115. package/dist/store/gi/record-field-accessor.d.ts +1 -1
  116. package/dist/store/gi/record-field-accessor.d.ts.map +1 -1
  117. package/dist/store/gi/record-field-accessor.js +3 -9
  118. package/dist/store/gi/record-field-accessor.js.map +1 -1
  119. package/dist/store/gi/record-layout.d.ts.map +1 -1
  120. package/dist/store/gi/record-layout.js +0 -4
  121. package/dist/store/gi/record-layout.js.map +1 -1
  122. package/dist/store/gi/return-wrap.d.ts +1 -1
  123. package/dist/store/gi/return-wrap.d.ts.map +1 -1
  124. package/dist/store/gi/return-wrap.js +4 -4
  125. package/dist/store/gi/return-wrap.js.map +1 -1
  126. package/dist/store/gi/signal.d.ts.map +1 -1
  127. package/dist/store/gi/signal.js +13 -16
  128. package/dist/store/gi/signal.js.map +1 -1
  129. package/dist/store/gi/value-marshalable.d.ts +0 -8
  130. package/dist/store/gi/value-marshalable.d.ts.map +1 -1
  131. package/dist/store/gi/value-marshalable.js +0 -9
  132. package/dist/store/gi/value-marshalable.js.map +1 -1
  133. package/dist/store/gi-store.d.ts +2 -3
  134. package/dist/store/gi-store.d.ts.map +1 -1
  135. package/dist/store/gi-store.js.map +1 -1
  136. package/dist/store/jsx/element-components.d.ts +0 -2
  137. package/dist/store/jsx/element-components.d.ts.map +1 -1
  138. package/dist/store/jsx/element-components.js +0 -4
  139. package/dist/store/jsx/element-components.js.map +1 -1
  140. package/dist/store/jsx/element-prop-imports.d.ts +2 -3
  141. package/dist/store/jsx/element-prop-imports.d.ts.map +1 -1
  142. package/dist/store/jsx/element-prop-imports.js +0 -2
  143. package/dist/store/jsx/element-prop-imports.js.map +1 -1
  144. package/dist/store/jsx/element-prop-types.d.ts +0 -1
  145. package/dist/store/jsx/element-prop-types.d.ts.map +1 -1
  146. package/dist/store/jsx/element-prop-types.js +0 -1
  147. package/dist/store/jsx/element-prop-types.js.map +1 -1
  148. package/dist/store/jsx/generated-elements.d.ts +29 -0
  149. package/dist/store/jsx/generated-elements.d.ts.map +1 -0
  150. package/dist/store/jsx/generated-elements.js +30 -0
  151. package/dist/store/jsx/generated-elements.js.map +1 -0
  152. package/dist/store/jsx/jsx.js +6 -6
  153. package/dist/store/jsx/jsx.js.map +1 -1
  154. package/dist/store/jsx/metadata.js +7 -7
  155. package/dist/store/jsx/metadata.js.map +1 -1
  156. package/dist/store/jsx/omitted-props.d.ts +2 -4
  157. package/dist/store/jsx/omitted-props.d.ts.map +1 -1
  158. package/dist/store/jsx/omitted-props.js +2 -4
  159. package/dist/store/jsx/omitted-props.js.map +1 -1
  160. package/dist/store/jsx/pipeline.d.ts +3 -1
  161. package/dist/store/jsx/pipeline.d.ts.map +1 -1
  162. package/dist/store/jsx/pipeline.js +3 -2
  163. package/dist/store/jsx/pipeline.js.map +1 -1
  164. package/dist/store/jsx/props.js +2 -2
  165. package/dist/store/jsx/props.js.map +1 -1
  166. package/dist/store/jsx-store.d.ts +2 -3
  167. package/dist/store/jsx-store.d.ts.map +1 -1
  168. package/dist/store/jsx-store.js +3 -3
  169. package/dist/store/jsx-store.js.map +1 -1
  170. package/dist/store/resolve-store.d.ts +28 -0
  171. package/dist/store/resolve-store.d.ts.map +1 -0
  172. package/dist/store/resolve-store.js +65 -0
  173. package/dist/store/resolve-store.js.map +1 -0
  174. package/dist/store/store-fs.d.ts +5 -1
  175. package/dist/store/store-fs.d.ts.map +1 -1
  176. package/dist/store/store-fs.js +6 -4
  177. package/dist/store/store-fs.js.map +1 -1
  178. package/overrides/gobject/object.ts.ejs +8 -8
  179. package/package.json +6 -10
  180. package/src/analysis/descriptor-render.ts +20 -45
  181. package/src/analysis/descriptor.ts +13 -13
  182. package/src/analysis/param-structure.ts +8 -10
  183. package/src/analysis/ts-type.ts +4 -6
  184. package/src/compile.ts +2 -1
  185. package/src/docs/api-reference.ts +127 -4
  186. package/src/docs/pipeline.ts +8 -8
  187. package/src/docs/render.ts +7 -7
  188. package/src/docs/symbol-page.ts +7 -2
  189. package/src/fingerprint.ts +8 -13
  190. package/src/gi.ts +4 -11
  191. package/src/gir/field.ts +0 -4
  192. package/src/gir/gir-path.ts +7 -0
  193. package/src/gir/libraries.ts +13 -0
  194. package/src/gir/parameter.ts +0 -4
  195. package/src/gir/size.ts +0 -3
  196. package/src/gir/type-id.ts +2 -4
  197. package/src/gir/type-ref.ts +1 -1
  198. package/src/index.ts +18 -16
  199. package/src/internal.ts +2 -0
  200. package/src/jsx.ts +26 -26
  201. package/src/khronos/args.ts +1 -1
  202. package/src/khronos/pipeline.ts +1 -1
  203. package/src/khronos/plan.ts +8 -8
  204. package/src/react/element-config.ts +22 -19
  205. package/src/runner.ts +57 -39
  206. package/src/store/compile-store.ts +3 -4
  207. package/src/store/gi/callables.ts +5 -5
  208. package/src/store/gi/constant.ts +0 -2
  209. package/src/store/gi/function.ts +1 -5
  210. package/src/store/gi/method.ts +30 -28
  211. package/src/store/gi/property-accessor.ts +6 -8
  212. package/src/store/gi/record-field-accessor.ts +4 -10
  213. package/src/store/gi/record-layout.ts +0 -4
  214. package/src/store/gi/return-wrap.ts +5 -5
  215. package/src/store/gi/signal.ts +17 -17
  216. package/src/store/gi/value-marshalable.ts +0 -9
  217. package/src/store/gi-store.ts +2 -4
  218. package/src/store/jsx/element-components.ts +0 -6
  219. package/src/store/jsx/element-prop-imports.ts +7 -4
  220. package/src/store/jsx/element-prop-types.ts +0 -1
  221. package/src/store/jsx/generated-elements.ts +60 -0
  222. package/src/store/jsx/jsx.ts +7 -7
  223. package/src/store/jsx/metadata.ts +8 -8
  224. package/src/store/jsx/omitted-props.ts +2 -4
  225. package/src/store/jsx/pipeline.ts +5 -3
  226. package/src/store/jsx/props.ts +2 -2
  227. package/src/store/jsx-store.ts +5 -7
  228. package/src/store/resolve-store.ts +100 -0
  229. package/src/store/store-fs.ts +12 -5
@@ -28,7 +28,7 @@ type AdmittedField = {
28
28
  type RecordFieldEntry = {
29
29
  jsName: string;
30
30
  tsType: string;
31
- writable: boolean;
31
+ isWritable: boolean;
32
32
  doc: string | undefined;
33
33
  };
34
34
 
@@ -91,8 +91,6 @@ type AccessorOptions = {
91
91
  fieldType: TypeId;
92
92
  };
93
93
 
94
- // An inline record field is read and written through its own bytes, so it can only be exposed when
95
- // those bytes are copyable; a pointer field is marshalled as a handle and is always fine.
96
94
  const isMarshalableField = (context: ModuleContext, field: GirField): boolean => {
97
95
  if (field.cType?.endsWith("*") === true) {
98
96
  return true;
@@ -180,7 +178,7 @@ const resolveRecordFieldEntry = (
180
178
  return {
181
179
  jsName: admitted.jsName,
182
180
  tsType: renderTsType(context, admitted.field.type, false),
183
- writable: admitted.field.writable,
181
+ isWritable: admitted.field.writable,
184
182
  doc: admitted.field.doc,
185
183
  };
186
184
  };
@@ -211,8 +209,6 @@ const renderRecordFieldAccessor = (
211
209
  return `${doc}declare ${jsName}: ${tsType};`;
212
210
  }
213
211
 
214
- // A record field whose C type is the record itself rather than a pointer to it holds the value
215
- // in place, so its own address is the value and no word may be loaded out of it.
216
212
  const descriptor = context.hoistDescriptor(
217
213
  renderDescriptor(context, field.type, "none", { isInline: isInlineField(context, field) }),
218
214
  );
@@ -269,8 +265,6 @@ const isAccessorEligibleType = (context: ModuleContext, ref: TypeId): boolean =>
269
265
  }
270
266
  };
271
267
 
272
- // A field whose record is embedded by value is read and written through its own bytes, so the
273
- // constructor and the setter have to describe it the same way.
274
268
  const isInlineField = (context: ModuleContext, field: GirField): boolean =>
275
269
  field.type !== undefined && resolveInlineStructFields(context, field.type, field.cType) !== undefined;
276
270
 
@@ -571,7 +565,7 @@ const renderStructArrayAccessor = (context: ModuleContext, target: StructArrayTa
571
565
  elementDescriptor: tStruct("borrowed", {
572
566
  size: `${lengthExpr} * ${String(elementSize)}`,
573
567
  wrapperClass: undefined,
574
- callerAllocated: false,
568
+ isCallerAllocated: false,
575
569
  }),
576
570
  offset: slot.byteOffset,
577
571
  lengthExpr,
@@ -603,7 +597,7 @@ const getterBlock = (options: AccessorOptions): string => {
603
597
 
604
598
  const wrapped = wrapReturnValue(context, {
605
599
  ref: fieldType,
606
- nullable: false,
600
+ isNullable: false,
607
601
  valueExpression,
608
602
  });
609
603
 
@@ -20,10 +20,6 @@ type RecordFieldSlot = {
20
20
  const POINTER_LAYOUT: FieldLayout = { size: 8, align: 8 };
21
21
  const recordLayoutCache: Map<string, FieldLayout> = new Map();
22
22
 
23
- // GIR carries no alignment attribute, and a type whose alignment exceeds its widest member cannot be
24
- // derived from the field list: Graphene models `graphene_simd4f_t` as four `gfloat`, which computes
25
- // to align 4 while the real type is a 16-byte SIMD vector. Keying the override on `c:type` keeps it
26
- // to the handful of types where the XML genuinely cannot express the ABI.
27
23
  const ALIGNMENT_OVERRIDES: Map<string, FieldLayout> = new Map([
28
24
  ["graphene_simd4f_t", { size: 16, align: 16 }],
29
25
  ["graphene_simd4x4f_t", { size: 64, align: 16 }],
@@ -6,14 +6,14 @@ import { renderTsType } from "../../analysis/ts-type.js";
6
6
 
7
7
  type WrapReturnOptions = {
8
8
  ref: TypeId | undefined;
9
- nullable: boolean;
9
+ isNullable: boolean;
10
10
  valueExpression: string;
11
11
  };
12
12
 
13
13
  const BIGINT_CATEGORIES: Set<PrimitiveCategory> = new Set(["gtype", "bigint64", "biguint64"]);
14
14
 
15
15
  const wrapReturnValue = (context: ModuleContext, options: WrapReturnOptions): string => {
16
- const { ref, nullable, valueExpression } = options;
16
+ const { ref, isNullable, valueExpression } = options;
17
17
 
18
18
  if (ref === undefined) {
19
19
  return valueExpression;
@@ -27,7 +27,7 @@ const wrapReturnValue = (context: ModuleContext, options: WrapReturnOptions): st
27
27
 
28
28
  switch (type.kind) {
29
29
  case "primitive": {
30
- return wrapPrimitive(type.category, nullable, valueExpression);
30
+ return wrapPrimitive(type.category, isNullable, valueExpression);
31
31
  }
32
32
  case "varargs": {
33
33
  return `(${valueExpression} as unknown[])`;
@@ -39,7 +39,7 @@ const wrapReturnValue = (context: ModuleContext, options: WrapReturnOptions): st
39
39
  return `(${valueExpression} as number)`;
40
40
  }
41
41
  case "alias": {
42
- return wrapAlias(context, type.value.target, nullable, valueExpression);
42
+ return wrapAlias(context, type.value.target, isNullable, valueExpression);
43
43
  }
44
44
  case "carray":
45
45
  case "class":
@@ -65,7 +65,7 @@ const wrapAlias = (
65
65
  ): string =>
66
66
  target === undefined
67
67
  ? valueExpression
68
- : wrapReturnValue(context, { ref: target, nullable: isNullable, valueExpression });
68
+ : wrapReturnValue(context, { ref: target, isNullable, valueExpression });
69
69
 
70
70
  const wrapValue = (context: ModuleContext, ref: TypeId, valueExpression: string): string => {
71
71
  context.addRuntimeImport("fromNative");
@@ -28,7 +28,7 @@ type SignalMapSpec = {
28
28
  context: ModuleContext;
29
29
  klass: GirClass;
30
30
  className: string;
31
- parentlessExtendsObject: boolean;
31
+ isParentlessObjectSubclass: boolean;
32
32
  suffix: string;
33
33
  renderEntry: (context: ModuleContext, signal: GirCallable) => string;
34
34
  };
@@ -66,7 +66,7 @@ const renderSignalMembers = (context: ModuleContext, klass: GirClass): string[]
66
66
 
67
67
  const connectDefault = isRootObject
68
68
  ? "default:\n throw new globalThis.Error(\"Unknown signal '\" + signal + \"'\");"
69
- : "default:\n return super.connect(signal, handler, after);";
69
+ : "default:\n return super.connect(signal, handler, isAfter);";
70
70
 
71
71
  const emitDefault = isRootObject
72
72
  ? "default:\n throw new globalThis.Error(\"Unknown signal '\" + sigName + \"'\");"
@@ -78,7 +78,10 @@ const renderSignalMembers = (context: ModuleContext, klass: GirClass): string[]
78
78
  const emitSwitch = `switch (getSignalBaseName(sigName)) {\n${emitBody}\n}`;
79
79
 
80
80
  return [
81
- renderBlock(`connect(signal: string, handler: ${SIGNAL_HANDLER_TYPE}, after?: boolean): number`, connectSwitch),
81
+ renderBlock(
82
+ `connect(signal: string, handler: ${SIGNAL_HANDLER_TYPE}, isAfter?: boolean): number`,
83
+ connectSwitch,
84
+ ),
82
85
  renderBlock("emit(sigName: string, ...args: unknown[]): unknown", emitSwitch),
83
86
  ];
84
87
  };
@@ -89,7 +92,7 @@ const renderSignalDeclarations = (
89
92
  className: string,
90
93
  isParentlessObjectSubclass: boolean,
91
94
  ): string[] => {
92
- const base = { context, klass, className, parentlessExtendsObject: isParentlessObjectSubclass };
95
+ const base = { context, klass, className, isParentlessObjectSubclass };
93
96
 
94
97
  const declarations = [
95
98
  renderSignalMap({ ...base, suffix: SIGNALS_SUFFIX, renderEntry: renderSignalHandlerType }),
@@ -110,8 +113,8 @@ const renderSignalDeclarations = (
110
113
  };
111
114
 
112
115
  const renderSignalMap = (spec: SignalMapSpec): string => {
113
- const { context, klass, className, parentlessExtendsObject, suffix, renderEntry } = spec;
114
- const extendsRefs = signalMapParentRefs(context, klass, parentlessExtendsObject, suffix);
116
+ const { context, klass, className, isParentlessObjectSubclass, suffix, renderEntry } = spec;
117
+ const extendsRefs = signalMapParentRefs(context, klass, isParentlessObjectSubclass, suffix);
115
118
  const extendsClause = extendsRefs.length === 0 ? "" : ` extends ${extendsRefs.join(", ")}`;
116
119
 
117
120
  const signalEntries = collectClassSignals(context, klass).map((signal) => {
@@ -177,8 +180,8 @@ const renderSignalConnectInterface = (className: string, isRootObject: boolean):
177
180
 
178
181
  const lines = [
179
182
  `__signals__?: ${map};`,
180
- `connect<K extends keyof ${map}>(signal: K, handler: ${map}[K], after?: boolean): number;`,
181
- `connect(signal: string, handler: ${SIGNAL_HANDLER_TYPE}, after?: boolean): number;`,
183
+ `connect<K extends keyof ${map}>(signal: K, handler: ${map}[K], isAfter?: boolean): number;`,
184
+ `connect(signal: string, handler: ${SIGNAL_HANDLER_TYPE}, isAfter?: boolean): number;`,
182
185
  `emit<K extends keyof ${emitMap}>(sigName: K, ...args: ${emitMap}[K]["args"]): ${emitMap}[K]["result"];`,
183
186
  "emit(sigName: string, ...args: unknown[]): unknown;",
184
187
  ];
@@ -193,7 +196,7 @@ const renderSignalConnectInterface = (className: string, isRootObject: boolean):
193
196
  }
194
197
  };
195
198
 
196
- chainable(["on", "once", "addEventListener"], ", after?: boolean");
199
+ chainable(["on", "once", "addEventListener"], ", isAfter?: boolean");
197
200
  chainable(["off", "removeEventListener"], "");
198
201
  }
199
202
 
@@ -216,8 +219,8 @@ const renderResultType = (
216
219
  library: context.library,
217
220
  signal,
218
221
  renderType: (ref, nullable) => renderTsType(context, ref, nullable),
219
- includeCallerAllocated: shouldIncludeCallerAllocated,
220
- optOut: isOptOut,
222
+ shouldIncludeCallerAllocated,
223
+ isOptOut,
221
224
  });
222
225
 
223
226
  const renderSignalEmitEntry = (context: ModuleContext, signal: GirCallable): string => {
@@ -237,7 +240,7 @@ const nonVarargParameters = (signal: GirCallable): GirParameter[] =>
237
240
 
238
241
  const renderConnectCase = (context: ModuleContext, signal: GirCallable): string => {
239
242
  const callback = renderCallback(context, signal);
240
- const body = `return connectSignal(this, signal, { callback: ${callback}, handler, after: after ?? false });`;
243
+ const body = `return connectSignal(this, signal, { callback: ${callback}, handler, isAfter: isAfter ?? false });`;
241
244
 
242
245
  return renderBlock(`case ${sourceStringLiteral(signal.name)}:`, body);
243
246
  };
@@ -260,7 +263,7 @@ const renderEmitArgLiteral = (options: EmitArgOptions): { literal: string; nextA
260
263
  const value = renderCallerOutAllocation(context, parameter);
261
264
 
262
265
  return {
263
- literal: `{ type: ${descriptor}, direction: "out", callerAllocated: true, value: ${value} }`,
266
+ literal: `{ type: ${descriptor}, direction: "out", isCallerAllocated: true, value: ${value} }`,
264
267
  nextArgIndex: argIndex,
265
268
  };
266
269
  }
@@ -268,7 +271,7 @@ const renderEmitArgLiteral = (options: EmitArgOptions): { literal: string; nextA
268
271
  if (isRecordInout(context, parameter)) {
269
272
  return {
270
273
  literal:
271
- `{ type: ${descriptor}, direction: "inout", callerAllocated: true, ` +
274
+ `{ type: ${descriptor}, direction: "inout", isCallerAllocated: true, ` +
272
275
  `value: args[${String(argIndex)}] }`,
273
276
  nextArgIndex: argIndex + 1,
274
277
  };
@@ -328,9 +331,6 @@ const renderCallerOutAllocation = (context: ModuleContext, parameter: GirParamet
328
331
  const renderCallback = (context: ModuleContext, signal: GirCallable): string => {
329
332
  const params = nonVarargParameters(signal);
330
333
 
331
- // The emitted argument list prepends the instance the signal was raised on, so every index a
332
- // parameter descriptor carries (an array's `sizeParamIndex`, above all) sits one slot further
333
- // right than the position GIR assigned it.
334
334
  const callbackParamDescriptors = params.map((parameter) =>
335
335
  renderParamDescriptor(context, parameter, parameter.type, { argIndexOffset: 1 }),
336
336
  );
@@ -7,7 +7,6 @@ import type { ModuleContext } from "../../writer/context.js";
7
7
 
8
8
  type Scope = { context: ModuleContext; seen: Set<string> };
9
9
 
10
- /** Primitive categories that are a pointer at the C level, so copying the bytes aliases the pointee. */
11
10
  const POINTER_CATEGORIES: Set<PrimitiveCategory> = new Set<PrimitiveCategory>(["string", "pointer"]);
12
11
 
13
12
  const recordKey = (namespaceName: string, record: GirRecord): string => `${namespaceName}.${record.name}`;
@@ -79,17 +78,9 @@ function isValueSafeRecord(scope: Scope, namespaceName: string, record: GirRecor
79
78
  return isSafe;
80
79
  }
81
80
 
82
- /**
83
- * Whether a record can be copied by value. A plain struct is duplicated with a byte-wise `g_memdup2`,
84
- * which shallow-copies whatever the bytes hold, so only a record whose every field is transitively a
85
- * scalar can be owned, allocated or written into an inline slot. A pointer, a string, a function
86
- * pointer or an opaque record makes it borrow-only. Records that carry their own copy/free pair are
87
- * duplicated through that instead and never reach the byte-wise path.
88
- */
89
81
  const isValueMarshalable = (context: ModuleContext, namespaceName: string, record: GirRecord): boolean =>
90
82
  isValueSafeRecord({ context, seen: new Set<string>() }, namespaceName, record);
91
83
 
92
- /** Whether a record can be allocated and populated from JavaScript. */
93
84
  const isConstructibleRecord = (context: ModuleContext, namespaceName: string, record: GirRecord): boolean =>
94
85
  hasOwnCopySemantics(record) || isValueMarshalable(context, namespaceName, record);
95
86
 
@@ -4,8 +4,6 @@ import { fileURLToPath } from "node:url";
4
4
  import { FINGERPRINT_FILENAME, type GiFingerprint } from "../fingerprint.js";
5
5
  import { buildManifest, type StoreOptions, subpathExport, writeStore } from "./store-fs.js";
6
6
 
7
- type GiStoreOptions = StoreOptions;
8
-
9
7
  type GiNamespaceInput = {
10
8
  directory: string;
11
9
  rawSource: string;
@@ -69,7 +67,7 @@ const collectStoreSources = (
69
67
  };
70
68
 
71
69
  const writeGiStore = (
72
- options: GiStoreOptions,
70
+ options: StoreOptions,
73
71
  namespaces: GiNamespaceInput[],
74
72
  fingerprint: GiFingerprint,
75
73
  ): void => {
@@ -89,4 +87,4 @@ const writeGiStore = (
89
87
  });
90
88
  };
91
89
 
92
- export { writeGiStore, type GiStoreOptions, type GiNamespaceInput };
90
+ export { writeGiStore, type GiNamespaceInput };
@@ -6,9 +6,7 @@ import type { LazyElementSpec } from "./element-prop-types.js";
6
6
  import { renderJsDoc } from "../../writer/doc.js";
7
7
  import { ancestorGlibNames, type GlibNamedClass } from "./intrinsic-elements.js";
8
8
 
9
- /** A component that wraps a generated element, keyed by GLib type name (built-in or user-provided). */
10
9
  type ElementComponent = { module: string; export: string };
11
- /** Component wrappers keyed by GLib type name; the framework's built-ins merged with the project's own. */
12
10
  type ElementComponentOverrides = Record<string, ElementComponent>;
13
11
 
14
12
  type ExportCollector = {
@@ -73,9 +71,6 @@ const appendCandidateExport = (
73
71
  collector.exportedNames.add(candidate.glibName);
74
72
  };
75
73
 
76
- // An abstract GType cannot be instantiated: `g_object_new` on one is a fatal GObject error rather
77
- // than a NULL return. Its props interface and metadata still have to be emitted, since every
78
- // concrete subclass extends them, so only the constructible component export is withheld.
79
74
  const collectCandidateExports = (collector: ExportCollector, options: CandidateExportOptions): void => {
80
75
  for (const candidate of options.intrinsicElements) {
81
76
  if (candidate.klass.isAbstract) {
@@ -121,7 +116,6 @@ const renderCandidateExport = (
121
116
  return `${renderJsDoc(klass.doc)}${renderElementComponentExport(glibName, component)}`;
122
117
  };
123
118
 
124
- /** The component for the nearest ancestry match, most-derived first; user overrides win on their exact type. */
125
119
  const resolveElementComponent = (
126
120
  ancestry: string[],
127
121
  components: Record<string, ElementComponent>,
@@ -1,11 +1,15 @@
1
- /** Props interface a generated element's props extend, declared by hand in `@gtkx/react`. */
2
1
  type ElementPropTypeRef = { type: string; module: string; export: string };
2
+
3
3
  /** Base props interface each element extends, keyed by GLib type name (the module exports it). */
4
- type ElementProps = Record<string, { module: string; export: string }>;
4
+ type ElementProps = Record<string, {
5
+ /** Specifier the props interface is imported from. */
6
+ module: string;
7
+ /** Identifier the module exports it under. */
8
+ export: string;
9
+ }>;
5
10
 
6
11
  const elementProps: Map<string, { module: string; export: string }> = new Map();
7
12
 
8
- /** Installs the base props each element extends (GLib type name → `{ module, export }`); set once per run. */
9
13
  const setElementProps = (props: ElementProps): void => {
10
14
  elementProps.clear();
11
15
 
@@ -14,7 +18,6 @@ const setElementProps = (props: ElementProps): void => {
14
18
  }
15
19
  };
16
20
 
17
- /** The base props interface an element extends, when its element config declares one. */
18
21
  const elementPropTypeFor = (glibName: string): ElementPropTypeRef | undefined => {
19
22
  const ref = elementProps.get(glibName);
20
23
 
@@ -37,7 +37,6 @@ const createLazyElementSpec = (context: GirIndex, element: string, entry: GirTyp
37
37
  return { element, typeName, typeSource: `export type ${typeName} = ${base} & { children?: ReactNode };` };
38
38
  };
39
39
 
40
- /** Lazy element prop types to emit, grouped by the namespace declaring each element. */
41
40
  const lazyElementSpecs = (context: GirIndex, lazyElements: string[]): Map<string, LazyElementSpec[]> => {
42
41
  const specs: Map<string, LazyElementSpec[]> = new Map();
43
42
 
@@ -0,0 +1,60 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import type { GlibNamedClass } from "./intrinsic-elements.js";
4
+ import { namespaceDirectory } from "../../gir/namespace.js";
5
+
6
+ /** One element the `@gtkx/jsx` store binds. */
7
+ type GeneratedElement = {
8
+ /** GIR namespace name, such as `"Gtk"`. */
9
+ namespace: string;
10
+ /** Subexport the element is reachable through, such as `"gtk"` in `@gtkx/jsx/gtk`. */
11
+ directory: string;
12
+ /** GLib type name, which is also the JSX tag name, such as `"GtkButton"`. */
13
+ glibName: string;
14
+ /**
15
+ * Whether the element can be rendered. An abstract GType is bound for its props and metadata but
16
+ * exports no component, because `g_object_new` on one is a fatal GObject error.
17
+ */
18
+ isMountable: boolean;
19
+ };
20
+
21
+ const ELEMENTS_FILENAME = "elements.json";
22
+
23
+ const collectGeneratedElements = (intrinsicElements: GlibNamedClass[]): GeneratedElement[] =>
24
+ intrinsicElements
25
+ .map((entry) => ({
26
+ namespace: entry.namespace.name,
27
+ directory: namespaceDirectory(entry.namespace),
28
+ glibName: entry.glibName,
29
+ isMountable: !entry.klass.isAbstract,
30
+ }))
31
+ .toSorted((a, b) => a.glibName.localeCompare(b.glibName));
32
+
33
+ const renderGeneratedElements = (elements: GeneratedElement[]): string =>
34
+ `${JSON.stringify(elements, null, 2)}\n`;
35
+
36
+ /**
37
+ * Reads the inventory of elements the `@gtkx/jsx` store binds, written into the store by codegen. Answers
38
+ * "what does this project's JSX layer cover" without loading the store, which resolves `virtual:` specifiers
39
+ * that only exist inside a Vite or Vitest build.
40
+ *
41
+ * @param jsxStoreDir The jsx store directory, as given by `resolveStore(projectRoot).jsx.storeDir`.
42
+ * @returns Every bound element, sorted by GLib type name, or an empty array when the store has no inventory.
43
+ */
44
+ const readGeneratedElements = (jsxStoreDir: string): GeneratedElement[] => {
45
+ const path = join(jsxStoreDir, ELEMENTS_FILENAME);
46
+
47
+ if (!existsSync(path)) {
48
+ return [];
49
+ }
50
+
51
+ return JSON.parse(readFileSync(path, "utf8")) as GeneratedElement[];
52
+ };
53
+
54
+ export {
55
+ ELEMENTS_FILENAME,
56
+ collectGeneratedElements,
57
+ readGeneratedElements,
58
+ renderGeneratedElements,
59
+ type GeneratedElement,
60
+ };
@@ -109,7 +109,7 @@ const generateJsxSection = (
109
109
  addReactBuiltin(imports, "ReactNode");
110
110
  addReactBuiltin(imports, "Ref");
111
111
  const interfaceResult = renderInterfacePropBlocks(library, targetNamespace.name, options);
112
- let isNeedsReactElement = interfaceResult.needsReactElement;
112
+ let requiresReactElement = interfaceResult.requiresReactElement;
113
113
  const propBlocks: string[] = [...interfaceResult.blocks];
114
114
 
115
115
  const blockContext: RenderPropBlockContext = {
@@ -124,13 +124,13 @@ const generateJsxSection = (
124
124
  const { block, objectPropNames } = renderPropBlock(library, entry, blockContext);
125
125
 
126
126
  if (objectPropNames.length > 0) {
127
- isNeedsReactElement = true;
127
+ requiresReactElement = true;
128
128
  }
129
129
 
130
130
  propBlocks.push(block);
131
131
  }
132
132
 
133
- if (isNeedsReactElement) {
133
+ if (requiresReactElement) {
134
134
  addReactBuiltin(imports, "ReactElement");
135
135
  }
136
136
 
@@ -152,11 +152,11 @@ const renderInterfacePropBlocks = (
152
152
  library: Library,
153
153
  targetNamespaceName: string,
154
154
  options: GenerateJsxOptions,
155
- ): { blocks: string[]; needsReactElement: boolean; hasContainerProps: HasContainerProps } => {
155
+ ): { blocks: string[]; requiresReactElement: boolean; hasContainerProps: HasContainerProps } => {
156
156
  const { imports, intrinsicElements } = options;
157
157
  const context: InterfaceBlockContext = { library, targetNamespaceName, imports, hasContainerProps };
158
158
  const blocks: string[] = [];
159
- let isNeedsReactElement = false;
159
+ let requiresReactElement = false;
160
160
 
161
161
  for (const iface of collectInterfacePropsClasses(
162
162
  library,
@@ -173,13 +173,13 @@ const renderInterfacePropBlocks = (
173
173
  const { block, objectPropNames } = renderInterfacePropsBlock(iface, glibName, context);
174
174
 
175
175
  if (objectPropNames.length > 0) {
176
- isNeedsReactElement = true;
176
+ requiresReactElement = true;
177
177
  }
178
178
 
179
179
  blocks.push(block);
180
180
  }
181
181
 
182
- return { blocks, needsReactElement: isNeedsReactElement, hasContainerProps };
182
+ return { blocks, requiresReactElement, hasContainerProps };
183
183
  };
184
184
 
185
185
  const registerCrossNsProps = (
@@ -23,7 +23,7 @@ type IntrinsicElementEntry = {
23
23
  };
24
24
 
25
25
  type PropNameCollector = {
26
- keep: (property: GirProperty) => boolean;
26
+ shouldKeep: (property: GirProperty) => boolean;
27
27
  seen: Set<string>;
28
28
  names: string[];
29
29
  };
@@ -57,10 +57,10 @@ const generateMetadata = (library: Library): string => {
57
57
  .map(({ glibName, defaults }) => ` "${glibName}": ${renderDefaultsObject(defaults)},`);
58
58
 
59
59
  return `${[
60
- `export const SIGNALS: Record<string, Record<string, string>> = {\n${signalsEntries.join("\n")}\n};`,
61
- `export const CONSTRUCT_ONLY_PROPS: Record<string, Set<string>> = {\n${constructOnlyEntries.join("\n")}\n};`,
62
- `export const CONSTRUCT_PROPS: Record<string, Set<string>> = {\n${constructableEntries.join("\n")}\n};`,
63
- `export const DEFAULT_PROPS: Record<string, Record<string, unknown>> = {\n${defaultsEntries.join("\n")}\n};`,
60
+ `export const signals: Record<string, Record<string, string>> = {\n${signalsEntries.join("\n")}\n};`,
61
+ `export const constructOnlyProps: Record<string, Set<string>> = {\n${constructOnlyEntries.join("\n")}\n};`,
62
+ `export const constructProps: Record<string, Set<string>> = {\n${constructableEntries.join("\n")}\n};`,
63
+ `export const defaultProps: Record<string, Record<string, unknown>> = {\n${defaultsEntries.join("\n")}\n};`,
64
64
  ].join("\n\n")}\n`;
65
65
  };
66
66
 
@@ -114,10 +114,10 @@ const collectSignals = (sources: GirClass[]): [string, string][] => {
114
114
  };
115
115
 
116
116
  const collectPropNamesFromSource = (source: GirClass, collector: PropNameCollector): void => {
117
- const { keep, seen, names } = collector;
117
+ const { shouldKeep, seen, names } = collector;
118
118
 
119
119
  for (const property of source.properties) {
120
- if (!keep(property)) {
120
+ if (!shouldKeep(property)) {
121
121
  continue;
122
122
  }
123
123
 
@@ -133,7 +133,7 @@ const collectPropNamesFromSource = (source: GirClass, collector: PropNameCollect
133
133
  };
134
134
 
135
135
  const collectPropNames = (sources: GirClass[], shouldKeep: (property: GirProperty) => boolean): string[] => {
136
- const collector: PropNameCollector = { keep: shouldKeep, seen: new Set<string>(), names: [] };
136
+ const collector: PropNameCollector = { shouldKeep, seen: new Set<string>(), names: [] };
137
137
 
138
138
  for (const source of sources) {
139
139
  collectPropNamesFromSource(source, collector);
@@ -3,7 +3,6 @@ type OmittedProps = Record<string, string[]>;
3
3
 
4
4
  const omittedProps: Map<string, Set<string>> = new Map();
5
5
 
6
- /** Installs the props each element omits (GLib type name → prop names); set once per run. */
7
6
  const setOmittedProps = (props: OmittedProps): void => {
8
7
  omittedProps.clear();
9
8
 
@@ -12,12 +11,11 @@ const setOmittedProps = (props: OmittedProps): void => {
12
11
  }
13
12
  };
14
13
 
15
- /** Whether the element config declares this prop omitted for the type that declares the property. */
16
14
  const isOmittedProp = (glibName: string | undefined, jsName: string): boolean =>
17
15
  glibName !== undefined && omittedProps.get(glibName)?.has(jsName) === true;
18
16
 
19
17
  /** Merges omitted-prop maps keyed by GLib type name, concatenating the names each map contributes. */
20
- const mergeOmitProps = (...maps: OmittedProps[]): OmittedProps => {
18
+ const mergeOmittedProps = (...maps: OmittedProps[]): OmittedProps => {
21
19
  const merged: OmittedProps = {};
22
20
 
23
21
  for (const map of maps) {
@@ -29,4 +27,4 @@ const mergeOmitProps = (...maps: OmittedProps[]): OmittedProps => {
29
27
  return merged;
30
28
  };
31
29
 
32
- export { setOmittedProps, isOmittedProp, mergeOmitProps, type OmittedProps };
30
+ export { setOmittedProps, isOmittedProp, mergeOmittedProps, type OmittedProps };
@@ -5,6 +5,7 @@ import { ImportsBuilder } from "../../writer/imports.js";
5
5
  import { type ElementComponentOverrides, generateElementComponentsSection } from "./element-components.js";
6
6
  import { type ElementProps, setElementProps } from "./element-prop-imports.js";
7
7
  import { type LazyElementSpec, lazyElementSpecs } from "./element-prop-types.js";
8
+ import { collectGeneratedElements, type GeneratedElement } from "./generated-elements.js";
8
9
  import { buildGirIndex } from "./gir-index.js";
9
10
  import { collectIntrinsicElementClasses, type GlibNamedClass } from "./intrinsic-elements.js";
10
11
  import { generateJsxSection } from "./jsx.js";
@@ -20,13 +21,14 @@ type JsxFiles = {
20
21
  namespaces: JsxNamespaceFile[];
21
22
  metadata: string;
22
23
  intrinsicElementCount: number;
24
+ elements: GeneratedElement[];
23
25
  };
24
26
 
25
27
  type JsxGenerationOptions = {
26
28
  reactSubexports?: string[];
27
29
  components?: ElementComponentOverrides;
28
30
  props?: ElementProps;
29
- omitProps?: OmittedProps;
31
+ omittedProps?: OmittedProps;
30
32
  lazyElements?: string[];
31
33
  };
32
34
 
@@ -49,7 +51,7 @@ type JsxNamespaceContext = {
49
51
 
50
52
  const generateJsxFiles = (library: Library, options: JsxGenerationOptions = {}): JsxFiles => {
51
53
  setElementProps(options.props ?? {});
52
- setOmittedProps(options.omitProps ?? {});
54
+ setOmittedProps(options.omittedProps ?? {});
53
55
  const intrinsicElements = collectIntrinsicElementClasses(library);
54
56
  const intrinsicElementByGlibName = new Map(intrinsicElements.map((entry) => [entry.glibName, entry]));
55
57
  const girIndex = buildGirIndex(library);
@@ -66,7 +68,7 @@ const generateJsxFiles = (library: Library, options: JsxGenerationOptions = {}):
66
68
 
67
69
  const metadata = generateMetadata(library);
68
70
 
69
- return { namespaces, metadata, intrinsicElementCount };
71
+ return { namespaces, metadata, intrinsicElementCount, elements: collectGeneratedElements(intrinsicElements) };
70
72
  };
71
73
 
72
74
  const orderedIntrinsicNamespaces = (intrinsicElements: GlibNamedClass[]): GirNamespace[] => {
@@ -231,8 +231,8 @@ const renderSignalHandler = (options: SignalRenderOptions): string => {
231
231
  library: types.library,
232
232
  signal,
233
233
  renderType: (ref, nullable) => renderReactPropType(types, ref, nullable),
234
- includeCallerAllocated: false,
235
- optOut: true,
234
+ shouldIncludeCallerAllocated: false,
235
+ isOptOut: true,
236
236
  });
237
237
 
238
238
  return `(${params.join(", ")}) => ${result}`;
@@ -2,13 +2,11 @@ import type { JsxNamespaceFile } from "./jsx/pipeline.js";
2
2
  import type { RawFile } from "./store-fs.js";
3
3
  import { buildManifest, type StoreOptions, subpathExport, writeStore } from "./store-fs.js";
4
4
 
5
- type JsxStoreOptions = StoreOptions;
6
-
7
5
  const writeJsxStore = (
8
- options: JsxStoreOptions,
6
+ options: StoreOptions,
9
7
  namespaces: JsxNamespaceFile[],
10
8
  metadata: string,
11
- fingerprint: RawFile,
9
+ rawFiles: RawFile[],
12
10
  ): void => {
13
11
  const exportsMap: Record<string, unknown> = {
14
12
  "./metadata": subpathExport("metadata"),
@@ -31,9 +29,9 @@ const writeJsxStore = (
31
29
  exports: exportsMap,
32
30
  peerDependencies: { "@gtkx/gi": "*", "@gtkx/react": "*", react: "*" },
33
31
  }),
34
- rawFiles: [fingerprint],
35
- configEnv: true,
32
+ rawFiles,
33
+ requiresEnvReference: true,
36
34
  });
37
35
  };
38
36
 
39
- export { writeJsxStore, type JsxStoreOptions };
37
+ export { writeJsxStore };