@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,8 +28,8 @@ type DocsOptions = {
28
28
  outDir: string;
29
29
  basePath?: string;
30
30
  props?: ElementProps;
31
- omitProps?: OmittedProps;
32
- force?: boolean;
31
+ omittedProps?: OmittedProps;
32
+ isForced?: boolean;
33
33
  };
34
34
 
35
35
  type DocsManifest = {
@@ -45,7 +45,7 @@ type Page = { path: string; content: string };
45
45
  type NamespacePages = { docs: DocsNamespace; pages: Page[] };
46
46
 
47
47
  type DocsResult = {
48
- regenerated: boolean;
48
+ isRegenerated: boolean;
49
49
  namespaces: DocsNamespace[];
50
50
  };
51
51
 
@@ -193,7 +193,7 @@ const generatePages = (options: DocsOptions, basePath: string, library: Library)
193
193
  };
194
194
 
195
195
  const cachedDocsResult = (options: DocsOptions, manifestPath: string): DocsResult | undefined => {
196
- if (options.force === true || !isGiStoreFresh(options.outDir, options.libraries, options.girPath)) {
196
+ if (options.isForced === true || !isGiStoreFresh(options.outDir, options.libraries, options.girPath)) {
197
197
  return undefined;
198
198
  }
199
199
 
@@ -203,7 +203,7 @@ const cachedDocsResult = (options: DocsOptions, manifestPath: string): DocsResul
203
203
 
204
204
  const manifest = JSON.parse(readFileSync(manifestPath, "utf8")) as DocsManifest;
205
205
 
206
- return { regenerated: false, namespaces: manifest.namespaces };
206
+ return { isRegenerated: false, namespaces: manifest.namespaces };
207
207
  };
208
208
 
209
209
  const writePages = (outDir: string, pages: Page[]): void => {
@@ -216,7 +216,7 @@ const writePages = (outDir: string, pages: Page[]): void => {
216
216
 
217
217
  const writeDocs = (options: DocsOptions): DocsResult => {
218
218
  setElementProps(options.props ?? {});
219
- setOmittedProps(options.omitProps ?? {});
219
+ setOmittedProps(options.omittedProps ?? {});
220
220
  const basePath = options.basePath ?? "/reference";
221
221
  const manifestPath = join(options.outDir, MANIFEST_FILENAME);
222
222
  const cached = cachedDocsResult(options, manifestPath);
@@ -238,7 +238,7 @@ const writeDocs = (options: DocsOptions): DocsResult => {
238
238
  JSON.stringify(computeGiFingerprint(library.girFiles, options.libraries, options.girPath)),
239
239
  );
240
240
 
241
- return { regenerated: true, namespaces };
241
+ return { isRegenerated: true, namespaces };
242
242
  };
243
243
 
244
- export { writeDocs, type DocsElementLink, type DocsNamespace, type DocsOptions, type DocsResult };
244
+ export { writeDocs };
@@ -45,8 +45,8 @@ const renderDocsHandlerResultType = (library: Library, signal: GirCallable): str
45
45
  library,
46
46
  signal,
47
47
  renderType: (ref, nullable) => renderDocsType(library, ref, nullable),
48
- includeCallerAllocated: false,
49
- optOut: true,
48
+ shouldIncludeCallerAllocated: false,
49
+ isOptOut: true,
50
50
  });
51
51
 
52
52
  const renderDocsHandlerParameters = (library: Library, signal: GirCallable): string[] =>
@@ -69,16 +69,16 @@ const stripDocMedia = (markdown: string): string =>
69
69
  .replaceAll(/<video[\s\S]*?(?:<\/video>|\/>)/g, "")
70
70
  .replaceAll(/<img[^>]*>/g, "");
71
71
 
72
- const demoteLine = (line: string, isInFence: boolean): { text: string; inFence: boolean } => {
72
+ const demoteLine = (line: string, isInFence: boolean): { text: string; isInFence: boolean } => {
73
73
  if (FENCE_LINE.test(line)) {
74
- return { text: line, inFence: !isInFence };
74
+ return { text: line, isInFence: !isInFence };
75
75
  }
76
76
 
77
77
  if (isInFence) {
78
- return { text: line, inFence: isInFence };
78
+ return { text: line, isInFence };
79
79
  }
80
80
 
81
- return { text: HEADING_LINE.test(line) ? `#${line}` : line, inFence: isInFence };
81
+ return { text: HEADING_LINE.test(line) ? `#${line}` : line, isInFence };
82
82
  };
83
83
 
84
84
  const demoteHeadings = (markdown: string): string => {
@@ -87,7 +87,7 @@ const demoteHeadings = (markdown: string): string => {
87
87
 
88
88
  for (const line of markdown.split("\n")) {
89
89
  const result = demoteLine(line, isInFence);
90
- isInFence = result.inFence;
90
+ isInFence = result.isInFence;
91
91
  lines.push(result.text);
92
92
  }
93
93
 
@@ -49,12 +49,17 @@ import {
49
49
  type SignatureEntry,
50
50
  } from "./render.js";
51
51
 
52
+ /** What every indexed GIR symbol carries, whatever its kind. */
52
53
  type GiSymbolBase = {
54
+ /** GIR namespace declaring the symbol. */
53
55
  namespace: GirNamespace;
56
+ /** Name the bindings export it under: camelCase for functions, PascalCase for classes, the GIR name otherwise. */
54
57
  name: string;
58
+ /** Raw gtk-doc text from the GIR, undefined when the symbol is undocumented. */
55
59
  doc: string | undefined;
56
60
  };
57
61
 
62
+ /** A GIR symbol the reference indexes, discriminated by `kind` and carrying the GIR node its page renders from. */
58
63
  type GiSymbolEntry =
59
64
  | (GiSymbolBase & { kind: "class" | "interface"; klass: GirClass }) |
60
65
  (GiSymbolBase & { kind: "record"; record: GirRecord }) |
@@ -270,7 +275,7 @@ const propertyMeta = (property: GirProperty, accessor: ResolvedAccessor, origin:
270
275
  meta.push("construct-only");
271
276
  }
272
277
 
273
- if (!accessor.writable) {
278
+ if (!accessor.isWritable) {
274
279
  meta.push("read-only");
275
280
  } else if (!accessor.hasGetter) {
276
281
  meta.push("write-only");
@@ -495,7 +500,7 @@ const recordPage = (entry: GiSymbolBase & { kind: "record"; record: GirRecord },
495
500
  };
496
501
 
497
502
  const fieldMeta = (field: ResolvedRecordField): string =>
498
- [`\`${field.tsType}\``, ...(field.writable ? [] : ["read-only"])].join(" · ");
503
+ [`\`${field.tsType}\``, ...(field.isWritable ? [] : ["read-only"])].join(" · ");
499
504
 
500
505
  const fieldsSection = (record: GirRecord, context: ModuleContext, claimedNames: Set<string>): string[] => {
501
506
  const { slots } = computeRecordFieldSlots(context, record.fields, record.isUnion);
@@ -5,7 +5,6 @@ import { createRequire } from "node:module";
5
5
  import { dirname, join, resolve } from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
7
 
8
- /** The freshness sentinel of the `@gtkx/gi` store, derived purely from the GIR inputs. */
9
8
  type GiFingerprint = {
10
9
  value: string;
11
10
  girFiles: string[];
@@ -15,16 +14,14 @@ type GiFingerprint = {
15
14
 
16
15
  type ModuleExport = { module: string; export: string };
17
16
 
18
- /** The `@gtkx/react` element config that shapes the generated `@gtkx/jsx` store. */
19
17
  type JsxFingerprintInput = {
20
18
  reactVersion: string;
21
19
  components: Record<string, ModuleExport>;
22
20
  lazyElements: string[];
23
21
  props: Record<string, ModuleExport>;
24
- omitProps: Record<string, string[]>;
22
+ omittedProps: Record<string, string[]>;
25
23
  };
26
24
 
27
- /** The freshness sentinel of the `@gtkx/jsx` store, derived from the React element config. */
28
25
  type JsxFingerprint = {
29
26
  value: string;
30
27
  intrinsicElementCount: number;
@@ -37,8 +34,6 @@ const OVERRIDES_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..", "o
37
34
 
38
35
  const sortAlpha = (values: string[]): string => sortStrings(values).join(",");
39
36
 
40
- // The overrides are copied verbatim into the store, so editing one changes the output even though no
41
- // GIR file moved. Without them in the hash a stale override survives every non-forced run.
42
37
  const overrideFiles = (): string[] => {
43
38
  if (!existsSync(OVERRIDES_ROOT)) {
44
39
  return [];
@@ -116,7 +111,7 @@ const hasMatchingRecordedInputs = (sentinel: GiFingerprint, libraries: string[],
116
111
  const serializeModuleExports = (map: Record<string, ModuleExport>): [string, string, string][] =>
117
112
  sortStrings(Object.keys(map)).map((type) => [type, map[type]?.module ?? "", map[type]?.export ?? ""]);
118
113
 
119
- const serializeOmitProps = (map: Record<string, string[]>): [string, string][] =>
114
+ const serializeOmittedProps = (map: Record<string, string[]>): [string, string][] =>
120
115
  sortStrings(Object.keys(map)).map((type) => [type, sortAlpha(map[type] ?? [])]);
121
116
 
122
117
  const hashJsx = (input: JsxFingerprintInput): string =>
@@ -128,7 +123,7 @@ const hashJsx = (input: JsxFingerprintInput): string =>
128
123
  serializeModuleExports(input.components),
129
124
  sortStrings(input.lazyElements),
130
125
  serializeModuleExports(input.props),
131
- serializeOmitProps(input.omitProps),
126
+ serializeOmittedProps(input.omittedProps),
132
127
  ]),
133
128
  )
134
129
  .digest("hex");
@@ -141,11 +136,11 @@ const computeJsxFingerprint = (input: JsxFingerprintInput, intrinsicElementCount
141
136
  const jsxStoreFreshness = (
142
137
  jsxStoreDir: string,
143
138
  input: JsxFingerprintInput,
144
- ): { fresh: boolean; intrinsicElementCount: number } => {
139
+ ): { isFresh: boolean; intrinsicElementCount: number } => {
145
140
  const sentinelPath = join(jsxStoreDir, FINGERPRINT_FILENAME);
146
141
 
147
142
  if (!existsSync(sentinelPath)) {
148
- return { fresh: false, intrinsicElementCount: 0 };
143
+ return { isFresh: false, intrinsicElementCount: 0 };
149
144
  }
150
145
 
151
146
  let sentinel: JsxFingerprint;
@@ -153,12 +148,12 @@ const jsxStoreFreshness = (
153
148
  try {
154
149
  sentinel = JSON.parse(readFileSync(sentinelPath, "utf8")) as JsxFingerprint;
155
150
  } catch {
156
- return { fresh: false, intrinsicElementCount: 0 };
151
+ return { isFresh: false, intrinsicElementCount: 0 };
157
152
  }
158
153
 
159
154
  return sentinel.value === hashJsx(input)
160
- ? { fresh: true, intrinsicElementCount: sentinel.intrinsicElementCount }
161
- : { fresh: false, intrinsicElementCount: 0 };
155
+ ? { isFresh: true, intrinsicElementCount: sentinel.intrinsicElementCount }
156
+ : { isFresh: false, intrinsicElementCount: 0 };
162
157
  };
163
158
 
164
159
  export {
package/src/gi.ts CHANGED
@@ -1,21 +1,16 @@
1
1
  import type { Library } from "./gir/library.js";
2
+ import type { StoreOptions } from "./store/store-fs.js";
2
3
  import { computeGiFingerprint } from "./fingerprint.js";
3
4
  import { namespaceDirectory } from "./gir/namespace.js";
4
- import { type GiNamespaceInput, type GiStoreOptions, writeGiStore } from "./store/gi-store.js";
5
+ import { type GiNamespaceInput, writeGiStore } from "./store/gi-store.js";
5
6
  import { generateNamespaceModule } from "./store/gi/pipeline.js";
6
7
 
7
8
  type GiCodegenOptions = {
8
- gi: GiStoreOptions;
9
+ gi: StoreOptions;
9
10
  libraries: string[];
10
11
  girPath: string[];
11
12
  };
12
13
 
13
- /**
14
- * Generates the `@gtkx/gi` store from the loaded GIR library and links it into the project. This is the
15
- * react-free half of codegen: it can run before `@gtkx/gi` (or `@gtkx/react`) exists, since it produces them.
16
- *
17
- * @returns The number of namespaces written.
18
- */
19
14
  const runGiCodegen = (library: Library, options: GiCodegenOptions): number => {
20
15
  const { gi, libraries, girPath } = options;
21
16
 
@@ -30,6 +25,4 @@ const runGiCodegen = (library: Library, options: GiCodegenOptions): number => {
30
25
  return library.namespaces.size;
31
26
  };
32
27
 
33
- export { isGiStoreFresh } from "./fingerprint.js";
34
- export type { GiStoreOptions } from "./store/gi-store.js";
35
- export { runGiCodegen, type GiCodegenOptions };
28
+ export { runGiCodegen };
package/src/gir/field.ts CHANGED
@@ -11,7 +11,6 @@ type GirField = {
11
11
  writable: boolean;
12
12
  private: boolean;
13
13
  bits: number | undefined;
14
- /** Members of an anonymous nested `<union>`/`<record>`, which occupies a slot but has no type. */
15
14
  inlineMembers: GirField[] | undefined;
16
15
  inlineIsUnion: boolean;
17
16
  };
@@ -29,9 +28,6 @@ const fieldFromNode = (node: RawNode, context: ParseContext): GirField => ({
29
28
  inlineIsUnion: false,
30
29
  });
31
30
 
32
- // A record may embed an anonymous `<union>` or `<record>` instead of naming a type for it. The
33
- // member occupies a real slot and contributes its own size and alignment, but carries no `<type>`,
34
- // so it has to be admitted as a field whose layout comes from its own children.
35
31
  const anonymousMemberFromNode = (node: RawNode, isUnion: boolean, context: ParseContext): GirField => ({
36
32
  name: nameAttr(node),
37
33
  doc: getDoc(node),
@@ -4,6 +4,13 @@ import { existsSync } from "node:fs";
4
4
 
5
5
  const SYSTEM_GIR_PATH = "/usr/share/gir-1.0";
6
6
 
7
+ /**
8
+ * The directories to search for `.gir` files, in precedence order: the config's own `girPath`, then
9
+ * `GTKX_GIR_PATH`, then `/usr/share/gir-1.0`, then the girdir pkg-config reports for
10
+ * gobject-introspection-1.0. Duplicates are dropped, and the last two are included only when they exist.
11
+ *
12
+ * @throws If pkg-config is installed but fails while being queried.
13
+ */
7
14
  const resolveGirPath = (configGirPath: string[] | undefined): string[] => {
8
15
  const paths: string[] = [];
9
16
 
@@ -2,13 +2,22 @@ import { sortStrings } from "@gtkx/utils";
2
2
  import { readdirSync } from "node:fs";
3
3
 
4
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. */
5
6
  type LibrarySelection = typeof LIBRARIES_WILDCARD | string[] | undefined;
6
7
 
8
+ /** The `libraries` value that stands for every GIR library installed on the search path. */
7
9
  const LIBRARIES_WILDCARD = "*";
8
10
  const GIR_LIBRARY_PATTERN = /^[A-Za-z][A-Za-z0-9]*-\d+(?:\.\d+)*$/;
9
11
  const DEFAULT_LIBRARIES: string[] = ["Gtk-4.0"];
10
12
  const GIR_FILE_SUFFIX = ".gir";
11
13
 
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
+ */
12
21
  const resolveLibraries = (libraries: LibrarySelection, girPath: string[]): string[] => {
13
22
  if (libraries === undefined) {
14
23
  return [...DEFAULT_LIBRARIES];
@@ -74,6 +83,10 @@ const collectDirNamespaces = (highestByName: Map<string, GirNamespace>, dir: str
74
83
  }
75
84
  };
76
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
+ */
77
90
  const discoverGirNamespaces = (girPath: string[]): string[] => {
78
91
  const highestByName: Map<string, GirNamespace> = new Map();
79
92
 
@@ -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,23 +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";
29
- export { mergeOmitProps, type OmittedProps } from "./store/jsx/omitted-props.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,70 +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 { mergeOmitProps, type OmittedProps } from "./store/jsx/omitted-props.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";
11
13
  import { generateJsxFiles } from "./store/jsx/pipeline.js";
12
14
 
13
15
  type RunJsxCodegenOptions = {
14
16
  getLibrary: () => Library;
15
- jsx: JsxStoreOptions;
17
+ jsx: StoreOptions;
16
18
  giStoreDir: string;
17
19
  reactSubexports: string[];
18
20
  userComponents: Record<string, ModuleExport>;
19
21
  userLazyElements: string[];
20
22
  userProps: Record<string, ModuleExport>;
21
- userOmitProps: OmittedProps;
22
- giRegenerated: boolean;
23
- force: boolean;
23
+ userOmittedProps: OmittedProps;
24
+ isGiRegenerated: boolean;
25
+ isForced: boolean;
24
26
  };
25
27
 
26
28
  type RunJsxCodegenResult = {
27
- regenerated: boolean;
29
+ isRegenerated: boolean;
28
30
  intrinsicElementCount: number;
29
31
  };
30
32
 
31
- /**
32
- * Generates the `@gtkx/jsx` store, reading the framework's built-in element config from the freshly
33
- * linked `@gtkx/react` and layering the project's own element config over it. This is the react-importing
34
- * half of codegen: it must run only after the gi store has been written and linked.
35
- */
36
33
  const runJsxCodegen = async (options: RunJsxCodegenOptions): Promise<RunJsxCodegenResult> => {
37
34
  const builtin = await readBuiltinElements(options.reactSubexports, options.giStoreDir);
38
35
  const components = { ...builtin.components, ...options.userComponents };
39
36
  const lazyElements = [...builtin.lazyElements, ...options.userLazyElements];
40
37
  const props = { ...builtin.props, ...options.userProps };
41
- const omitProps = mergeOmitProps(builtin.omitProps, options.userOmitProps);
38
+ const omittedProps = mergeOmittedProps(builtin.omittedProps, options.userOmittedProps);
42
39
 
43
40
  const fingerprintInput: JsxFingerprintInput = {
44
41
  reactVersion: options.jsx.version,
45
42
  components,
46
43
  lazyElements,
47
44
  props,
48
- omitProps,
45
+ omittedProps,
49
46
  };
50
47
 
51
- if (!options.force && !options.giRegenerated) {
52
- const { fresh, intrinsicElementCount } = jsxStoreFreshness(options.jsx.storeDir, fingerprintInput);
48
+ if (!options.isForced && !options.isGiRegenerated) {
49
+ const { isFresh, intrinsicElementCount } = jsxStoreFreshness(options.jsx.storeDir, fingerprintInput);
53
50
 
54
- if (fresh) {
55
- return { regenerated: false, intrinsicElementCount };
51
+ if (isFresh) {
52
+ return { isRegenerated: false, intrinsicElementCount };
56
53
  }
57
54
  }
58
55
 
59
- const { namespaces, metadata, intrinsicElementCount } = generateJsxFiles(options.getLibrary(), {
56
+ const { namespaces, metadata, intrinsicElementCount, elements } = generateJsxFiles(options.getLibrary(), {
60
57
  reactSubexports: options.reactSubexports,
61
58
  components,
62
59
  lazyElements,
63
60
  props,
64
- omitProps,
61
+ omittedProps,
65
62
  });
66
63
 
67
- writeJsxStore(options.jsx, namespaces, metadata, {
68
- relativePath: FINGERPRINT_FILENAME,
69
- content: `${JSON.stringify(computeJsxFingerprint(fingerprintInput, intrinsicElementCount), null, 2)}\n`,
70
- });
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
+ ]);
71
71
 
72
- return { regenerated: true, intrinsicElementCount };
72
+ return { isRegenerated: true, intrinsicElementCount };
73
73
  };
74
74
 
75
- 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