@gtkx/codegen 1.0.0-rc.2 → 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 (254) hide show
  1. package/README.md +4 -5
  2. package/dist/analysis/descriptor-render.d.ts +2 -2
  3. package/dist/analysis/descriptor-render.d.ts.map +1 -1
  4. package/dist/analysis/descriptor-render.js +30 -32
  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 +7 -13
  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 +66 -8
  24. package/dist/docs/api-reference.js.map +1 -1
  25. package/dist/docs/element-page.d.ts.map +1 -1
  26. package/dist/docs/element-page.js +5 -4
  27. package/dist/docs/element-page.js.map +1 -1
  28. package/dist/docs/pipeline.d.ts +5 -3
  29. package/dist/docs/pipeline.d.ts.map +1 -1
  30. package/dist/docs/pipeline.js +5 -3
  31. package/dist/docs/pipeline.js.map +1 -1
  32. package/dist/docs/render.js +6 -6
  33. package/dist/docs/render.js.map +1 -1
  34. package/dist/docs/symbol-page.d.ts +5 -0
  35. package/dist/docs/symbol-page.d.ts.map +1 -1
  36. package/dist/docs/symbol-page.js +2 -2
  37. package/dist/docs/symbol-page.js.map +1 -1
  38. package/dist/fingerprint.d.ts +2 -4
  39. package/dist/fingerprint.d.ts.map +1 -1
  40. package/dist/fingerprint.js +7 -6
  41. package/dist/fingerprint.js.map +1 -1
  42. package/dist/gi.d.ts +7 -10
  43. package/dist/gi.d.ts.map +1 -1
  44. package/dist/gi.js +4 -9
  45. package/dist/gi.js.map +1 -1
  46. package/dist/gir/field.d.ts +0 -1
  47. package/dist/gir/field.d.ts.map +1 -1
  48. package/dist/gir/field.js +0 -3
  49. package/dist/gir/field.js.map +1 -1
  50. package/dist/gir/gir-path.d.ts +7 -0
  51. package/dist/gir/gir-path.d.ts.map +1 -1
  52. package/dist/gir/gir-path.js +7 -0
  53. package/dist/gir/gir-path.js.map +1 -1
  54. package/dist/gir/libraries.d.ts +17 -3
  55. package/dist/gir/libraries.d.ts.map +1 -1
  56. package/dist/gir/libraries.js +14 -1
  57. package/dist/gir/libraries.js.map +1 -1
  58. package/dist/gir/parameter.d.ts.map +1 -1
  59. package/dist/gir/parameter.js +0 -4
  60. package/dist/gir/parameter.js.map +1 -1
  61. package/dist/gir/size.d.ts.map +1 -1
  62. package/dist/gir/size.js +0 -3
  63. package/dist/gir/size.js.map +1 -1
  64. package/dist/gir/type-id.d.ts +1 -1
  65. package/dist/gir/type-id.d.ts.map +1 -1
  66. package/dist/gir/type-id.js +1 -3
  67. package/dist/gir/type-id.js.map +1 -1
  68. package/dist/gir/type-ref.js +1 -1
  69. package/dist/gir/type-ref.js.map +1 -1
  70. package/dist/index.d.ts +18 -5
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +12 -2
  73. package/dist/index.js.map +1 -1
  74. package/dist/internal.d.ts +3 -0
  75. package/dist/internal.d.ts.map +1 -0
  76. package/dist/internal.js +3 -0
  77. package/dist/internal.js.map +1 -0
  78. package/dist/jsx.d.ts +8 -11
  79. package/dist/jsx.d.ts.map +1 -1
  80. package/dist/jsx.js +18 -15
  81. package/dist/jsx.js.map +1 -1
  82. package/dist/khronos/args.d.ts.map +1 -1
  83. package/dist/khronos/args.js +1 -1
  84. package/dist/khronos/args.js.map +1 -1
  85. package/dist/khronos/pipeline.js +1 -1
  86. package/dist/khronos/pipeline.js.map +1 -1
  87. package/dist/khronos/plan.d.ts +2 -2
  88. package/dist/khronos/plan.d.ts.map +1 -1
  89. package/dist/khronos/plan.js +6 -6
  90. package/dist/khronos/plan.js.map +1 -1
  91. package/dist/react/element-config.d.ts +18 -9
  92. package/dist/react/element-config.d.ts.map +1 -1
  93. package/dist/react/element-config.js +23 -13
  94. package/dist/react/element-config.js.map +1 -1
  95. package/dist/runner.d.ts +36 -16
  96. package/dist/runner.d.ts.map +1 -1
  97. package/dist/runner.js +22 -20
  98. package/dist/runner.js.map +1 -1
  99. package/dist/store/compile-store.d.ts +1 -2
  100. package/dist/store/compile-store.d.ts.map +1 -1
  101. package/dist/store/compile-store.js +2 -2
  102. package/dist/store/compile-store.js.map +1 -1
  103. package/dist/store/gi/callables.d.ts.map +1 -1
  104. package/dist/store/gi/callables.js +4 -9
  105. package/dist/store/gi/callables.js.map +1 -1
  106. package/dist/store/gi/constant.d.ts.map +1 -1
  107. package/dist/store/gi/constant.js +0 -2
  108. package/dist/store/gi/constant.js.map +1 -1
  109. package/dist/store/gi/function.d.ts.map +1 -1
  110. package/dist/store/gi/function.js +1 -7
  111. package/dist/store/gi/function.js.map +1 -1
  112. package/dist/store/gi/method.d.ts.map +1 -1
  113. package/dist/store/gi/method.js +26 -23
  114. package/dist/store/gi/method.js.map +1 -1
  115. package/dist/store/gi/property-accessor.d.ts +1 -1
  116. package/dist/store/gi/property-accessor.d.ts.map +1 -1
  117. package/dist/store/gi/property-accessor.js +5 -7
  118. package/dist/store/gi/property-accessor.js.map +1 -1
  119. package/dist/store/gi/record-constructor.d.ts.map +1 -1
  120. package/dist/store/gi/record-constructor.js +5 -4
  121. package/dist/store/gi/record-constructor.js.map +1 -1
  122. package/dist/store/gi/record-field-accessor.d.ts +3 -2
  123. package/dist/store/gi/record-field-accessor.d.ts.map +1 -1
  124. package/dist/store/gi/record-field-accessor.js +21 -11
  125. package/dist/store/gi/record-field-accessor.js.map +1 -1
  126. package/dist/store/gi/record-layout.d.ts.map +1 -1
  127. package/dist/store/gi/record-layout.js +0 -4
  128. package/dist/store/gi/record-layout.js.map +1 -1
  129. package/dist/store/gi/record.d.ts.map +1 -1
  130. package/dist/store/gi/record.js +0 -7
  131. package/dist/store/gi/record.js.map +1 -1
  132. package/dist/store/gi/return-wrap.d.ts +1 -1
  133. package/dist/store/gi/return-wrap.d.ts.map +1 -1
  134. package/dist/store/gi/return-wrap.js +4 -4
  135. package/dist/store/gi/return-wrap.js.map +1 -1
  136. package/dist/store/gi/signal.d.ts.map +1 -1
  137. package/dist/store/gi/signal.js +13 -16
  138. package/dist/store/gi/signal.js.map +1 -1
  139. package/dist/store/gi/value-marshalable.d.ts +7 -0
  140. package/dist/store/gi/value-marshalable.d.ts.map +1 -0
  141. package/dist/store/gi/value-marshalable.js +57 -0
  142. package/dist/store/gi/value-marshalable.js.map +1 -0
  143. package/dist/store/gi-store.d.ts +2 -3
  144. package/dist/store/gi-store.d.ts.map +1 -1
  145. package/dist/store/gi-store.js.map +1 -1
  146. package/dist/store/jsx/element-components.d.ts +0 -2
  147. package/dist/store/jsx/element-components.d.ts.map +1 -1
  148. package/dist/store/jsx/element-components.js +0 -4
  149. package/dist/store/jsx/element-components.js.map +1 -1
  150. package/dist/store/jsx/element-prop-imports.d.ts +2 -3
  151. package/dist/store/jsx/element-prop-imports.d.ts.map +1 -1
  152. package/dist/store/jsx/element-prop-imports.js +0 -2
  153. package/dist/store/jsx/element-prop-imports.js.map +1 -1
  154. package/dist/store/jsx/element-prop-types.d.ts +0 -1
  155. package/dist/store/jsx/element-prop-types.d.ts.map +1 -1
  156. package/dist/store/jsx/element-prop-types.js +0 -1
  157. package/dist/store/jsx/element-prop-types.js.map +1 -1
  158. package/dist/store/jsx/generated-elements.d.ts +29 -0
  159. package/dist/store/jsx/generated-elements.d.ts.map +1 -0
  160. package/dist/store/jsx/generated-elements.js +30 -0
  161. package/dist/store/jsx/generated-elements.js.map +1 -0
  162. package/dist/store/jsx/intrinsic-elements.d.ts +1 -2
  163. package/dist/store/jsx/intrinsic-elements.d.ts.map +1 -1
  164. package/dist/store/jsx/intrinsic-elements.js +1 -2
  165. package/dist/store/jsx/intrinsic-elements.js.map +1 -1
  166. package/dist/store/jsx/jsx.js +6 -6
  167. package/dist/store/jsx/jsx.js.map +1 -1
  168. package/dist/store/jsx/metadata.js +7 -7
  169. package/dist/store/jsx/metadata.js.map +1 -1
  170. package/dist/store/jsx/omitted-props.d.ts +8 -0
  171. package/dist/store/jsx/omitted-props.d.ts.map +1 -0
  172. package/dist/store/jsx/omitted-props.js +20 -0
  173. package/dist/store/jsx/omitted-props.js.map +1 -0
  174. package/dist/store/jsx/pipeline.d.ts +4 -0
  175. package/dist/store/jsx/pipeline.d.ts.map +1 -1
  176. package/dist/store/jsx/pipeline.js +4 -1
  177. package/dist/store/jsx/pipeline.js.map +1 -1
  178. package/dist/store/jsx/props.d.ts +1 -1
  179. package/dist/store/jsx/props.d.ts.map +1 -1
  180. package/dist/store/jsx/props.js +8 -13
  181. package/dist/store/jsx/props.js.map +1 -1
  182. package/dist/store/jsx-store.d.ts +2 -3
  183. package/dist/store/jsx-store.d.ts.map +1 -1
  184. package/dist/store/jsx-store.js +3 -3
  185. package/dist/store/jsx-store.js.map +1 -1
  186. package/dist/store/resolve-store.d.ts +28 -0
  187. package/dist/store/resolve-store.d.ts.map +1 -0
  188. package/dist/store/resolve-store.js +65 -0
  189. package/dist/store/resolve-store.js.map +1 -0
  190. package/dist/store/store-fs.d.ts +5 -1
  191. package/dist/store/store-fs.d.ts.map +1 -1
  192. package/dist/store/store-fs.js +6 -4
  193. package/dist/store/store-fs.js.map +1 -1
  194. package/overrides/gobject/object.ts.ejs +8 -8
  195. package/package.json +6 -11
  196. package/src/analysis/descriptor-render.ts +45 -38
  197. package/src/analysis/descriptor.ts +13 -13
  198. package/src/analysis/param-structure.ts +8 -10
  199. package/src/analysis/ts-type.ts +8 -17
  200. package/src/compile.ts +2 -1
  201. package/src/docs/api-reference.ts +131 -13
  202. package/src/docs/element-page.ts +5 -9
  203. package/src/docs/pipeline.ts +9 -6
  204. package/src/docs/render.ts +7 -7
  205. package/src/docs/symbol-page.ts +7 -2
  206. package/src/fingerprint.ts +21 -12
  207. package/src/gi.ts +13 -11
  208. package/src/gir/field.ts +0 -4
  209. package/src/gir/gir-path.ts +7 -0
  210. package/src/gir/libraries.ts +18 -4
  211. package/src/gir/parameter.ts +0 -4
  212. package/src/gir/size.ts +0 -3
  213. package/src/gir/type-id.ts +2 -4
  214. package/src/gir/type-ref.ts +1 -1
  215. package/src/index.ts +18 -15
  216. package/src/internal.ts +2 -0
  217. package/src/jsx.ts +26 -21
  218. package/src/khronos/args.ts +1 -1
  219. package/src/khronos/pipeline.ts +1 -1
  220. package/src/khronos/plan.ts +8 -8
  221. package/src/react/element-config.ts +25 -16
  222. package/src/runner.ts +62 -37
  223. package/src/store/compile-store.ts +3 -4
  224. package/src/store/gi/callables.ts +5 -11
  225. package/src/store/gi/constant.ts +0 -2
  226. package/src/store/gi/function.ts +1 -7
  227. package/src/store/gi/method.ts +31 -28
  228. package/src/store/gi/property-accessor.ts +6 -8
  229. package/src/store/gi/record-constructor.ts +9 -4
  230. package/src/store/gi/record-field-accessor.ts +41 -12
  231. package/src/store/gi/record-layout.ts +0 -4
  232. package/src/store/gi/record.ts +0 -9
  233. package/src/store/gi/return-wrap.ts +5 -5
  234. package/src/store/gi/signal.ts +17 -17
  235. package/src/store/gi/value-marshalable.ts +87 -0
  236. package/src/store/gi-store.ts +2 -4
  237. package/src/store/jsx/element-components.ts +0 -6
  238. package/src/store/jsx/element-prop-imports.ts +7 -4
  239. package/src/store/jsx/element-prop-types.ts +0 -1
  240. package/src/store/jsx/generated-elements.ts +60 -0
  241. package/src/store/jsx/intrinsic-elements.ts +0 -9
  242. package/src/store/jsx/jsx.ts +7 -7
  243. package/src/store/jsx/metadata.ts +8 -8
  244. package/src/store/jsx/omitted-props.ts +30 -0
  245. package/src/store/jsx/pipeline.ts +6 -1
  246. package/src/store/jsx/props.ts +8 -20
  247. package/src/store/jsx-store.ts +5 -7
  248. package/src/store/resolve-store.ts +100 -0
  249. package/src/store/store-fs.ts +12 -5
  250. package/dist/store/gi/class-struct-record.d.ts +0 -10
  251. package/dist/store/gi/class-struct-record.d.ts.map +0 -1
  252. package/dist/store/gi/class-struct-record.js +0 -52
  253. package/dist/store/gi/class-struct-record.js.map +0 -1
  254. package/src/store/gi/class-struct-record.ts +0 -72
@@ -1,14 +1,24 @@
1
- import type { Config } from "@gtkx/config";
2
- import { GIR_LIBRARY_PATTERN, LIBRARIES_WILDCARD } from "@gtkx/config/internal";
3
1
  import { sortStrings } from "@gtkx/utils";
4
2
  import { readdirSync } from "node:fs";
5
3
 
6
4
  type GirNamespace = { name: string; version: string; identifier: string };
5
+ /** A `libraries` config value: an explicit list, `"*"` for everything installed, or absent for the default. */
6
+ type LibrarySelection = typeof LIBRARIES_WILDCARD | string[] | undefined;
7
7
 
8
+ /** The `libraries` value that stands for every GIR library installed on the search path. */
9
+ const LIBRARIES_WILDCARD = "*";
10
+ const GIR_LIBRARY_PATTERN = /^[A-Za-z][A-Za-z0-9]*-\d+(?:\.\d+)*$/;
8
11
  const DEFAULT_LIBRARIES: string[] = ["Gtk-4.0"];
9
12
  const GIR_FILE_SUFFIX = ".gir";
10
13
 
11
- const resolveLibraries = (libraries: Config["libraries"], girPath: string[]): string[] => {
14
+ /**
15
+ * Expands a `libraries` config value into the GIR identifiers to generate from: `"Gtk-4.0"` alone when
16
+ * nothing is configured, everything installed for `"*"`, and otherwise the given list with `"Gtk-4.0"`
17
+ * prepended unless it already names a Gtk version.
18
+ *
19
+ * @throws If `"*"` matched no `.gir` file anywhere on the GIR path.
20
+ */
21
+ const resolveLibraries = (libraries: LibrarySelection, girPath: string[]): string[] => {
12
22
  if (libraries === undefined) {
13
23
  return [...DEFAULT_LIBRARIES];
14
24
  }
@@ -73,6 +83,10 @@ const collectDirNamespaces = (highestByName: Map<string, GirNamespace>, dir: str
73
83
  }
74
84
  };
75
85
 
86
+ /**
87
+ * Every GIR library installed on the search path, as sorted `Name-Version` identifiers. A namespace found
88
+ * in more than one version contributes only its highest, and unreadable directories are skipped.
89
+ */
76
90
  const discoverGirNamespaces = (girPath: string[]): string[] => {
77
91
  const highestByName: Map<string, GirNamespace> = new Map();
78
92
 
@@ -99,4 +113,4 @@ const compareVersions = (a: string, b: string): number => {
99
113
  return 0;
100
114
  };
101
115
 
102
- export { resolveLibraries, discoverGirNamespaces };
116
+ export { resolveLibraries, discoverGirNamespaces, type LibrarySelection };
@@ -53,10 +53,6 @@ const SCOPES: Set<CallbackScope> = new Set(["call", "notified", "async", "foreve
53
53
  const transferOwnership = (node: RawNode): ParameterTransfer =>
54
54
  parseEnumAttr(attr(node, "transfer-ownership"), TRANSFERS, "none", "transfer-ownership");
55
55
 
56
- // `allow-none` is the legacy spelling of two different attributes: on an in-parameter it means the
57
- // value may be NULL (`nullable`), but on an out-parameter it means the caller may pass a NULL
58
- // location (`optional`). Folding it into `nullable` for an out-parameter would claim the returned
59
- // value can be null for the 494 out-parameters across the installed GIRs that only say `allow-none`.
60
56
  const isInDirection = (node: RawNode): boolean =>
61
57
  parseEnumAttr(attr(node, "direction"), DIRECTIONS, "in", "direction") === "in";
62
58
 
package/src/gir/size.ts CHANGED
@@ -59,9 +59,6 @@ const pushPlainField = (state: StructLayoutState, slots: FieldSlot[], field: Fie
59
59
  state.bitCursor = (byteOffset + field.layout.size) * 8;
60
60
  };
61
61
 
62
- // SysV AMD64 places a bit-field at the current bit offset whenever it still fits inside a storage
63
- // unit of its declared type aligned to that type's alignment, so the unit the cursor already sits in
64
- // may have room even though the cursor is not on a unit boundary.
65
62
  const pushBitfield = (input: {
66
63
  state: StructLayoutState;
67
64
  slots: FieldSlot[];
@@ -12,7 +12,7 @@ type CArrayType = {
12
12
  elementCType: string | undefined;
13
13
  lengthParameterIndex: number | undefined;
14
14
  fixedSize: number | undefined;
15
- zeroTerminated: boolean;
15
+ isZeroTerminated: boolean;
16
16
  };
17
17
 
18
18
  type ListType = {
@@ -46,10 +46,8 @@ const LIST_FLAVOR_BY_NAME = {
46
46
  "GLib.ByteArray": "gbytearray",
47
47
  } as const;
48
48
 
49
- // An array with no length parameter, no fixed size and an explicit `zero-terminated="0"` carries no
50
- // way to recover its length, so it is a bare pointer rather than something that can be walked.
51
49
  const hasUnknownArrayLength = (ref: CArrayType): boolean =>
52
- !ref.zeroTerminated && ref.lengthParameterIndex === undefined && ref.fixedSize === undefined;
50
+ !ref.isZeroTerminated && ref.lengthParameterIndex === undefined && ref.fixedSize === undefined;
53
51
 
54
52
  export {
55
53
  hasUnknownArrayLength,
@@ -90,7 +90,7 @@ const arrayTypeRefFromNode = (arrayNode: RawNode, context: ParseContext): TypeId
90
90
  elementCType: elementNode === undefined ? undefined : attr(elementNode, "c:type"),
91
91
  lengthParameterIndex: intAttr(arrayNode, "length"),
92
92
  fixedSize: intAttr(arrayNode, "fixed-size"),
93
- zeroTerminated: isAttrTrue(arrayNode, "zero-terminated", true),
93
+ isZeroTerminated: isAttrTrue(arrayNode, "zero-terminated", true),
94
94
  };
95
95
 
96
96
  return context.addContainer(carray);
package/src/index.ts CHANGED
@@ -1,3 +1,4 @@
1
+ /** @public */
1
2
  export {
2
3
  API_SYMBOL_KINDS,
3
4
  type ApiLookupResult,
@@ -7,22 +8,24 @@ export {
7
8
  type ApiSearchOptions,
8
9
  type ApiSymbol,
9
10
  type ApiSymbolKind,
11
+ type ApiSymbolQuery,
10
12
  loadApiReference,
11
13
  } from "./docs/api-reference.js";
12
- export {
13
- type DocsElementLink,
14
- type DocsNamespace,
15
- type DocsOptions,
16
- type DocsResult,
17
- writeDocs,
18
- } from "./docs/pipeline.js";
14
+ /** @public */
19
15
  export { resolveGirPath } from "./gir/gir-path.js";
20
- export { discoverGirNamespaces, resolveLibraries } from "./gir/libraries.js";
21
- export {
22
- type BuiltinElement,
23
- type BuiltinElements,
24
- type ModuleExport,
25
- readBuiltinElements,
26
- } from "./react/element-config.js";
27
- export { runCodegen } from "./runner.js";
16
+ /** @public */
17
+ export { discoverGirNamespaces, type LibrarySelection, resolveLibraries } from "./gir/libraries.js";
18
+ /** @public */
19
+ export { type BuiltinElements, type ModuleExport, readBuiltinElements } from "./react/element-config.js";
20
+ /** @public */
21
+ export { type CodegenRunnerOptions, type CodegenRunnerResult, runCodegen } from "./runner.js";
22
+ /** @public */
28
23
  export type { ElementProps } from "./store/jsx/element-prop-imports.js";
24
+ /** @public */
25
+ export { type GeneratedElement, readGeneratedElements } from "./store/jsx/generated-elements.js";
26
+ /** @public */
27
+ export { mergeOmittedProps, type OmittedProps } from "./store/jsx/omitted-props.js";
28
+ /** @public */
29
+ export { type ResolvedStore, resolveStore } from "./store/resolve-store.js";
30
+ /** @public */
31
+ export type { StoreOptions } from "./store/store-fs.js";
@@ -0,0 +1,2 @@
1
+ export { writeDocs } from "./docs/pipeline.js";
2
+ export { runGlCodegen } from "./runner.js";
package/src/jsx.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { Library } from "./gir/library.js";
2
+ import type { StoreOptions } from "./store/store-fs.js";
2
3
  import {
3
4
  computeJsxFingerprint,
4
5
  FINGERPRINT_FILENAME,
@@ -6,65 +7,69 @@ import {
6
7
  jsxStoreFreshness,
7
8
  } from "./fingerprint.js";
8
9
  import { type ModuleExport, readBuiltinElements } from "./react/element-config.js";
9
- import { type JsxStoreOptions, writeJsxStore } from "./store/jsx-store.js";
10
+ import { writeJsxStore } from "./store/jsx-store.js";
11
+ import { ELEMENTS_FILENAME, renderGeneratedElements } from "./store/jsx/generated-elements.js";
12
+ import { mergeOmittedProps, type OmittedProps } from "./store/jsx/omitted-props.js";
10
13
  import { generateJsxFiles } from "./store/jsx/pipeline.js";
11
14
 
12
15
  type RunJsxCodegenOptions = {
13
16
  getLibrary: () => Library;
14
- jsx: JsxStoreOptions;
17
+ jsx: StoreOptions;
15
18
  giStoreDir: string;
16
19
  reactSubexports: string[];
17
20
  userComponents: Record<string, ModuleExport>;
18
21
  userLazyElements: string[];
19
22
  userProps: Record<string, ModuleExport>;
20
- giRegenerated: boolean;
21
- force: boolean;
23
+ userOmittedProps: OmittedProps;
24
+ isGiRegenerated: boolean;
25
+ isForced: boolean;
22
26
  };
23
27
 
24
28
  type RunJsxCodegenResult = {
25
- regenerated: boolean;
29
+ isRegenerated: boolean;
26
30
  intrinsicElementCount: number;
27
31
  };
28
32
 
29
- /**
30
- * Generates the `@gtkx/jsx` store, reading the framework's built-in element config from the freshly
31
- * linked `@gtkx/react` and layering the project's own element config over it. This is the react-importing
32
- * half of codegen: it must run only after the gi store has been written and linked.
33
- */
34
33
  const runJsxCodegen = async (options: RunJsxCodegenOptions): Promise<RunJsxCodegenResult> => {
35
34
  const builtin = await readBuiltinElements(options.reactSubexports, options.giStoreDir);
36
35
  const components = { ...builtin.components, ...options.userComponents };
37
36
  const lazyElements = [...builtin.lazyElements, ...options.userLazyElements];
38
37
  const props = { ...builtin.props, ...options.userProps };
38
+ const omittedProps = mergeOmittedProps(builtin.omittedProps, options.userOmittedProps);
39
39
 
40
40
  const fingerprintInput: JsxFingerprintInput = {
41
41
  reactVersion: options.jsx.version,
42
42
  components,
43
43
  lazyElements,
44
44
  props,
45
+ omittedProps,
45
46
  };
46
47
 
47
- if (!options.force && !options.giRegenerated) {
48
- const { fresh, intrinsicElementCount } = jsxStoreFreshness(options.jsx.storeDir, fingerprintInput);
48
+ if (!options.isForced && !options.isGiRegenerated) {
49
+ const { isFresh, intrinsicElementCount } = jsxStoreFreshness(options.jsx.storeDir, fingerprintInput);
49
50
 
50
- if (fresh) {
51
- return { regenerated: false, intrinsicElementCount };
51
+ if (isFresh) {
52
+ return { isRegenerated: false, intrinsicElementCount };
52
53
  }
53
54
  }
54
55
 
55
- const { namespaces, metadata, intrinsicElementCount } = generateJsxFiles(options.getLibrary(), {
56
+ const { namespaces, metadata, intrinsicElementCount, elements } = generateJsxFiles(options.getLibrary(), {
56
57
  reactSubexports: options.reactSubexports,
57
58
  components,
58
59
  lazyElements,
59
60
  props,
61
+ omittedProps,
60
62
  });
61
63
 
62
- writeJsxStore(options.jsx, namespaces, metadata, {
63
- relativePath: FINGERPRINT_FILENAME,
64
- content: `${JSON.stringify(computeJsxFingerprint(fingerprintInput, intrinsicElementCount), null, 2)}\n`,
65
- });
64
+ writeJsxStore(options.jsx, namespaces, metadata, [
65
+ {
66
+ relativePath: FINGERPRINT_FILENAME,
67
+ content: `${JSON.stringify(computeJsxFingerprint(fingerprintInput, intrinsicElementCount), null, 2)}\n`,
68
+ },
69
+ { relativePath: ELEMENTS_FILENAME, content: renderGeneratedElements(elements) },
70
+ ]);
66
71
 
67
- return { regenerated: true, intrinsicElementCount };
72
+ return { isRegenerated: true, intrinsicElementCount };
68
73
  };
69
74
 
70
- export { runJsxCodegen, type RunJsxCodegenOptions, type RunJsxCodegenResult };
75
+ export { runJsxCodegen };
@@ -52,7 +52,7 @@ type BuildArgOptions = {
52
52
  const OUT_PLAN_KINDS: Set<string> = new Set(["ref-out", "ref-array-out", "ref-fixed-out", "string-out"]);
53
53
 
54
54
  const scalarAliasOrGroup = (scalar: GlScalar, group: string | undefined): string =>
55
- group !== undefined && scalar.groupBearing === true ? group : scalar.tsAlias;
55
+ group !== undefined && scalar.isGroupBearing === true ? group : scalar.tsAlias;
56
56
 
57
57
  const paramIndexByName = (command: GlCommand, name: string): number => {
58
58
  const index = command.params.findIndex((param) => param.name === name);
@@ -143,7 +143,7 @@ const mergeGroupAlias = (aliases: Map<string, string>, scalar: GlScalar, group:
143
143
  return;
144
144
  }
145
145
 
146
- if (scalar.groupBearing !== true) {
146
+ if (scalar.isGroupBearing !== true) {
147
147
  return;
148
148
  }
149
149
 
@@ -5,13 +5,13 @@ type GlScalar = {
5
5
  descriptor: string;
6
6
  tsAlias: string;
7
7
  viewType?: string;
8
- groupBearing?: boolean;
8
+ isGroupBearing?: boolean;
9
9
  };
10
10
 
11
11
  type ParsedCType = {
12
12
  base: string;
13
13
  pointers: number;
14
- constData: boolean;
14
+ isConstData: boolean;
15
15
  };
16
16
 
17
17
  type ParamPlan =
@@ -61,10 +61,10 @@ type CommandPlan =
61
61
  type ParamOutcome = { plan: ParamPlan } | { reason: GlExclusionReason };
62
62
 
63
63
  const GL_SCALARS: Map<string, GlScalar> = new Map([
64
- ["GLenum", { descriptor: tScalar("uint32"), tsAlias: "GLenum", viewType: "Uint32Array", groupBearing: true }],
64
+ ["GLenum", { descriptor: tScalar("uint32"), tsAlias: "GLenum", viewType: "Uint32Array", isGroupBearing: true }],
65
65
  [
66
66
  "GLbitfield",
67
- { descriptor: tScalar("uint32"), tsAlias: "GLbitfield", viewType: "Uint32Array", groupBearing: true },
67
+ { descriptor: tScalar("uint32"), tsAlias: "GLbitfield", viewType: "Uint32Array", isGroupBearing: true },
68
68
  ],
69
69
  ["GLuint", { descriptor: tScalar("uint32"), tsAlias: "GLuint", viewType: "Uint32Array" }],
70
70
  ["GLint", { descriptor: tScalar("int32"), tsAlias: "GLint", viewType: "Int32Array" }],
@@ -96,7 +96,7 @@ const parseCType = (cType: string): ParsedCType => {
96
96
  .filter((token) => token.length > 0 && token !== "const" && token !== "struct")
97
97
  .join(" ");
98
98
 
99
- return { base, pointers, constData: isConstData };
99
+ return { base, pointers, isConstData };
100
100
  };
101
101
 
102
102
  const isCompsize = (len: string): boolean => len.includes("COMPSIZE(");
@@ -158,11 +158,11 @@ const charStringOutLen = (command: GlCommand, param: GlParam, parsed: ParsedCTyp
158
158
  };
159
159
 
160
160
  const planCharParam = (command: GlCommand, param: GlParam, parsed: ParsedCType): ParamOutcome => {
161
- if (parsed.pointers === 1 && parsed.constData) {
161
+ if (parsed.pointers === 1 && parsed.isConstData) {
162
162
  return { plan: { kind: "string-in" } };
163
163
  }
164
164
 
165
- if (parsed.pointers === 2 && parsed.constData) {
165
+ if (parsed.pointers === 2 && parsed.isConstData) {
166
166
  return { plan: { kind: "string-array-in" } };
167
167
  }
168
168
 
@@ -191,7 +191,7 @@ const planScalarParam = (
191
191
  return { plan: { kind: "scalar", scalar } };
192
192
  }
193
193
 
194
- if (parsed.pointers === 1 && parsed.constData) {
194
+ if (parsed.pointers === 1 && parsed.isConstData) {
195
195
  return { plan: { kind: "array-in", scalar } };
196
196
  }
197
197
 
@@ -1,14 +1,19 @@
1
- import type { ModuleExport } from "@gtkx/react/config";
1
+ import type { ModuleExport } from "@gtkx/react/internal";
2
2
  import { readdirSync } from "node:fs";
3
+ import type { OmittedProps } from "../store/jsx/omitted-props.js";
3
4
 
4
- /** The codegen-relevant subset of a React element config; behaviors are ignored at codegen time. */
5
- type BuiltinElement = { component?: ModuleExport; lazy?: boolean; props?: ModuleExport };
5
+ type BuiltinElement = { component?: ModuleExport; isLazy?: boolean; props?: ModuleExport; omittedProps?: string[] };
6
6
 
7
7
  /** The framework's built-in element config, split into the maps codegen consumes. */
8
8
  type BuiltinElements = {
9
+ /** Component wrappers keyed by GLib type name; an element without one inherits its nearest ancestor's. */
9
10
  components: Record<string, ModuleExport>;
11
+ /** GLib type names with no GObject of their own, exported as elements that drop their construct-only props. */
10
12
  lazyElements: string[];
13
+ /** Base props interfaces the generated element props extend, keyed by GLib type name. */
11
14
  props: Record<string, ModuleExport>;
15
+ /** Props left out of the generated element props, keyed by GLib type name. */
16
+ omittedProps: OmittedProps;
12
17
  };
13
18
 
14
19
  const CONFIG_ENTRYPOINT = "config";
@@ -27,10 +32,6 @@ const presentNamespaceDirs = (giStoreDir: string): Set<string> => {
27
32
  return dirs;
28
33
  };
29
34
 
30
- /**
31
- * The clean, reconciler-free `@gtkx/react` config entrypoints to import: the base `config` entry plus
32
- * each namespace's `<ns>/config` entry whose GIR namespace is present in the gi store.
33
- */
34
35
  const configEntrypoints = (reactSubexports: string[], present: Set<string>): string[] =>
35
36
  reactSubexports.filter((sub) => {
36
37
  if (sub === CONFIG_ENTRYPOINT) {
@@ -59,26 +60,34 @@ const applyBuiltinElement = (target: BuiltinElements, type: string, config: Buil
59
60
  target.props[type] = config.props;
60
61
  }
61
62
 
62
- if (config.lazy === true) {
63
+ if (config.omittedProps !== undefined) {
64
+ target.omittedProps[type] = [...(target.omittedProps[type] ?? []), ...config.omittedProps];
65
+ }
66
+
67
+ if (config.isLazy === true) {
63
68
  target.lazyElements.push(type);
64
69
  }
65
70
  };
66
71
 
67
- /**
68
- * Reads the framework's built-in element config by importing the freshly linked `@gtkx/react` config
69
- * entrypoints. These are reconciler-free, so importing them resolves `@gtkx/gi` but never `virtual:gtkx-config`;
70
- * it must run only after the gi store has been linked.
71
- */
72
72
  const collectBuiltinElements = (target: BuiltinElements, elements: Record<string, BuiltinElement>): void => {
73
73
  for (const [type, config] of Object.entries(elements)) {
74
74
  applyBuiltinElement(target, type, config);
75
75
  }
76
76
  };
77
77
 
78
+ /**
79
+ * Reads the framework's built-in element config by importing the `config` entrypoints of the installed
80
+ * `@gtkx/react`, skipping the per-namespace ones whose namespace the gi store does not carry. Those
81
+ * entrypoints are reconciler-free, so importing them resolves `@gtkx/gi` but never `virtual:gtkx-config`,
82
+ * which means this must run only after the gi store has been written and linked.
83
+ *
84
+ * @param reactSubexports Subexport names of the installed `@gtkx/react`, as `resolveStore` reports them.
85
+ * @param giStoreDir The gi store directory, whose subdirectories name the generated namespaces.
86
+ */
78
87
  const readBuiltinElements = async (reactSubexports: string[], giStoreDir: string): Promise<BuiltinElements> => {
79
88
  const present = presentNamespaceDirs(giStoreDir);
80
89
  const entrypoints = configEntrypoints(reactSubexports, present);
81
- const result: BuiltinElements = { components: {}, lazyElements: [], props: {} };
90
+ const result: BuiltinElements = { components: {}, lazyElements: [], props: {}, omittedProps: {} };
82
91
 
83
92
  for (const entrypoint of entrypoints) {
84
93
  collectBuiltinElements(result, await importBuiltinElements(entrypoint));
@@ -87,5 +96,5 @@ const readBuiltinElements = async (reactSubexports: string[], giStoreDir: string
87
96
  return result;
88
97
  };
89
98
 
90
- export { type ModuleExport } from "@gtkx/react/config";
91
- export { readBuiltinElements, type BuiltinElement, type BuiltinElements };
99
+ export type { ModuleExport } from "@gtkx/react/internal";
100
+ export { readBuiltinElements, type BuiltinElements };
package/src/runner.ts CHANGED
@@ -1,14 +1,20 @@
1
1
  import { mkdirSync, writeFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
- import type { GiStoreOptions } from "./store/gi-store.js";
4
- import type { JsxStoreOptions } from "./store/jsx-store.js";
3
+ import type { OmittedProps } from "./store/jsx/omitted-props.js";
4
+ import type { StoreOptions } from "./store/store-fs.js";
5
5
  import { checkModules } from "./compile.js";
6
6
  import { isGiStoreFresh } from "./fingerprint.js";
7
7
  import { runGiCodegen } from "./gi.js";
8
8
  import { Library } from "./gir/library.js";
9
9
  import { generateGlModules, type GlGenerationReport } from "./khronos/pipeline.js";
10
10
 
11
- type ModuleExport = { module: string; export: string };
11
+ /** A named export in a module, referenced as plain data (the module is never imported at runtime). */
12
+ type ModuleExport = {
13
+ /** Specifier the export is imported from. */
14
+ module: string;
15
+ /** Identifier the module exports it under. */
16
+ export: string;
17
+ };
12
18
 
13
19
  type GlCodegenOptions = {
14
20
  registryPath: string;
@@ -17,57 +23,71 @@ type GlCodegenOptions = {
17
23
  resolveFrom: string;
18
24
  };
19
25
 
26
+ /** What to generate and where to write it. */
20
27
  type CodegenRunnerOptions = {
21
- libraries?: string[];
22
- girPath?: string[];
23
- gi?: GiStoreOptions;
24
- jsx?: JsxStoreOptions | undefined;
28
+ /** GIR library identifiers such as `"Gtk-4.0"`; a `"*"` selection must be expanded before it gets here. */
29
+ libraries: string[];
30
+ /** Directories to search for `.gir` files. */
31
+ girPath: string[];
32
+ /** Where to write and link the `@gtkx/gi` store. */
33
+ gi: StoreOptions;
34
+ /** Where to write and link the `@gtkx/jsx` store; omit to generate the gi store alone. */
35
+ jsx?: StoreOptions | undefined;
36
+ /** Subexport names of the installed `@gtkx/react`, whose element config shapes the jsx store. */
25
37
  reactSubexports?: string[];
38
+ /** Component wrappers the project layers over the built-ins, keyed by GLib type name. */
26
39
  userComponents?: Record<string, ModuleExport>;
40
+ /** GLib type names whose GObject their parent container creates, added to the framework's own. */
27
41
  userLazyElements?: string[];
42
+ /** Base props interfaces the project's elements extend, keyed by GLib type name. */
28
43
  userProps?: Record<string, ModuleExport>;
29
- gl?: GlCodegenOptions;
30
- force?: boolean;
44
+ /** Props the project drops from the generated element props, keyed by GLib type name. */
45
+ userOmittedProps?: OmittedProps;
46
+ /** Regenerates both stores even when their fingerprints are fresh. */
47
+ isForced?: boolean;
31
48
  };
32
49
 
50
+ /** What a `runCodegen` run produced. */
33
51
  type CodegenRunnerResult = {
34
- regenerated: boolean;
52
+ /** Whether either store was rewritten; false means both were already fresh. */
53
+ isRegenerated: boolean;
54
+ /** How many namespaces the gi store was written with, zero when it was already fresh. */
35
55
  namespaces: number;
56
+ /** How many JSX elements the jsx store binds, zero when no jsx store was requested. */
36
57
  intrinsicElements: number;
58
+ /** Wall-clock duration of the run, in milliseconds. */
37
59
  duration: number;
38
- gl?: GlGenerationReport | undefined;
39
60
  };
40
61
 
41
62
  type StoreResult = {
42
- regenerated: boolean;
63
+ isRegenerated: boolean;
43
64
  namespaces: number;
44
65
  intrinsicElements: number;
45
66
  };
46
67
 
47
68
  /**
48
- * Runs the `@gtkx` code generators, producing the `@gtkx/gi`, `@gtkx/jsx`, and `@gtkx/gl` bindings from the
49
- * configured GObject-introspection libraries and OpenGL registry. The gi store is regenerated only when its
50
- * fingerprint is stale unless `options.force` is set, then the jsx store is regenerated when the gi store or
51
- * the React element config changed; the OpenGL modules are regenerated whenever `options.gl` is provided.
69
+ * Writes and links a project's `@gtkx/gi` and `@gtkx/jsx` stores from the given GObject-Introspection
70
+ * libraries. The gi store is rewritten only when its GIR inputs changed, and the jsx store only when the gi
71
+ * store or the React element config changed, unless `options.isForced` is set. Pass the spread of
72
+ * `resolveStore(projectRoot)` for everything but `libraries` and `girPath`.
52
73
  *
53
- * @param options - What to generate and where to write it.
74
+ * @param options What to generate and where to write it.
54
75
  * @returns A summary of what was regenerated and how long the run took.
76
+ * @throws If `girPath` is empty, which would otherwise generate nothing and report success.
55
77
  */
56
78
  const runCodegen = async (options: CodegenRunnerOptions): Promise<CodegenRunnerResult> => {
57
79
  const start = Date.now();
58
- const gl = options.gl === undefined ? undefined : emitGlModules(options.gl);
59
80
  const store = await emitStores(options);
60
81
 
61
82
  return {
62
- regenerated: store.regenerated,
83
+ isRegenerated: store.isRegenerated,
63
84
  namespaces: store.namespaces,
64
85
  intrinsicElements: store.intrinsicElements,
65
86
  duration: Date.now() - start,
66
- gl,
67
87
  };
68
88
  };
69
89
 
70
- const emitGlModules = (options: GlCodegenOptions): GlGenerationReport => {
90
+ const runGlCodegen = (options: GlCodegenOptions): GlGenerationReport => {
71
91
  const { files, report } = generateGlModules({
72
92
  registryPath: options.registryPath,
73
93
  overrideExports: options.overrideExports,
@@ -95,22 +115,24 @@ const jsxUserOptions = (
95
115
  userComponents: Record<string, ModuleExport>;
96
116
  userLazyElements: string[];
97
117
  userProps: Record<string, ModuleExport>;
118
+ userOmittedProps: OmittedProps;
98
119
  } => ({
99
120
  reactSubexports: options.reactSubexports ?? [],
100
121
  userComponents: options.userComponents ?? {},
101
122
  userLazyElements: options.userLazyElements ?? [],
102
123
  userProps: options.userProps ?? {},
124
+ userOmittedProps: options.userOmittedProps ?? {},
103
125
  });
104
126
 
105
127
  const emitJsxStore = async (input: {
106
128
  options: CodegenRunnerOptions;
107
- jsx: JsxStoreOptions;
108
- gi: GiStoreOptions;
129
+ jsx: StoreOptions;
130
+ gi: StoreOptions;
109
131
  loadLibrary: () => Library;
110
- giRegenerated: boolean;
132
+ isGiRegenerated: boolean;
111
133
  namespaces: number;
112
134
  }): Promise<StoreResult> => {
113
- const { options, jsx, gi, loadLibrary, giRegenerated, namespaces } = input;
135
+ const { options, jsx, gi, loadLibrary, isGiRegenerated, namespaces } = input;
114
136
  const { runJsxCodegen } = await import("./jsx.js");
115
137
 
116
138
  const jsxResult = await runJsxCodegen({
@@ -118,12 +140,12 @@ const emitJsxStore = async (input: {
118
140
  jsx,
119
141
  giStoreDir: gi.storeDir,
120
142
  ...jsxUserOptions(options),
121
- giRegenerated,
122
- force: options.force === true,
143
+ isGiRegenerated,
144
+ isForced: options.isForced === true,
123
145
  });
124
146
 
125
147
  return {
126
- regenerated: giRegenerated || jsxResult.regenerated,
148
+ isRegenerated: isGiRegenerated || jsxResult.isRegenerated,
127
149
  namespaces,
128
150
  intrinsicElements: jsxResult.intrinsicElementCount,
129
151
  };
@@ -131,32 +153,35 @@ const emitJsxStore = async (input: {
131
153
 
132
154
  const emitStoresWithConfig = async (config: {
133
155
  options: CodegenRunnerOptions;
134
- gi: GiStoreOptions;
135
- jsx: JsxStoreOptions | undefined;
156
+ gi: StoreOptions;
157
+ jsx: StoreOptions | undefined;
136
158
  libraries: string[];
137
159
  girPath: string[];
138
160
  }): Promise<StoreResult> => {
139
161
  const { options, gi, jsx, libraries, girPath } = config;
140
162
  let library: Library | undefined;
141
163
  const loadLibrary = (): Library => (library ??= Library.load(libraries, girPath));
142
- const isGiRegenerated = options.force === true || !isGiStoreFresh(gi.storeDir, libraries, girPath);
143
- const namespaces = isGiRegenerated ? runGiCodegen(loadLibrary(), gi, libraries, girPath) : 0;
164
+ const isGiRegenerated = options.isForced === true || !isGiStoreFresh(gi.storeDir, libraries, girPath);
165
+
166
+ const namespaces = isGiRegenerated
167
+ ? runGiCodegen(loadLibrary(), { gi, libraries, girPath })
168
+ : 0;
144
169
 
145
170
  if (jsx === undefined) {
146
- return { regenerated: isGiRegenerated, namespaces, intrinsicElements: 0 };
171
+ return { isRegenerated: isGiRegenerated, namespaces, intrinsicElements: 0 };
147
172
  }
148
173
 
149
- return emitJsxStore({ options, jsx, gi, loadLibrary, giRegenerated: isGiRegenerated, namespaces });
174
+ return emitJsxStore({ options, jsx, gi, loadLibrary, isGiRegenerated, namespaces });
150
175
  };
151
176
 
152
177
  const emitStores = async (options: CodegenRunnerOptions): Promise<StoreResult> => {
153
178
  const { gi, jsx, libraries, girPath } = options;
154
179
 
155
- if (gi === undefined || libraries === undefined || girPath === undefined) {
156
- return { regenerated: false, namespaces: 0, intrinsicElements: 0 };
180
+ if (girPath.length === 0) {
181
+ throw new Error("codegen needs at least one GIR search path; pass the result of resolveGirPath");
157
182
  }
158
183
 
159
184
  return emitStoresWithConfig({ options, gi, jsx, libraries, girPath });
160
185
  };
161
186
 
162
- export { runCodegen, type GlCodegenOptions, type CodegenRunnerOptions, type CodegenRunnerResult };
187
+ export { runCodegen, runGlCodegen, type CodegenRunnerOptions, type CodegenRunnerResult };
@@ -6,8 +6,7 @@ type CompileStoreParams = {
6
6
  storeDir: string;
7
7
  files: SourceModule[];
8
8
  packageName: string;
9
- /** Declare `virtual:gtkx-config` for the typecheck, needed when it follows imports into `@gtkx/react` source. */
10
- configEnv?: boolean;
9
+ requiresEnvReference?: boolean;
11
10
  };
12
11
 
13
12
  const EMIT_OPTIONS = {
@@ -32,14 +31,14 @@ const writeEnvReference = (storeDir: string): (() => void) => {
32
31
  const compileStore = (params: CompileStoreParams): void => {
33
32
  const fileNames = params.files.map((file) => file.fileName);
34
33
 
35
- const removeEnvReference = params.configEnv === true
34
+ const removeEnvReference = params.requiresEnvReference === true
36
35
  ? writeEnvReference(params.storeDir)
37
36
  : (): void => undefined;
38
37
 
39
38
  try {
40
39
  compileProject({
41
40
  projectDir: params.storeDir,
42
- fileNames: params.configEnv === true ? [ENV_REFERENCE_FILE, ...fileNames] : fileNames,
41
+ fileNames: params.requiresEnvReference === true ? [ENV_REFERENCE_FILE, ...fileNames] : fileNames,
43
42
  compilerOptions: EMIT_OPTIONS,
44
43
  label: `the generated ${params.packageName} store`,
45
44
  });