@gtkx/codegen 1.2.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/README.md +2 -1
  2. package/dist/analysis/descriptor-render.d.ts +7 -1
  3. package/dist/analysis/descriptor-render.d.ts.map +1 -1
  4. package/dist/analysis/descriptor-render.js +36 -15
  5. package/dist/analysis/descriptor-render.js.map +1 -1
  6. package/dist/analysis/descriptor.d.ts +4 -1
  7. package/dist/analysis/descriptor.d.ts.map +1 -1
  8. package/dist/analysis/descriptor.js +11 -2
  9. package/dist/analysis/descriptor.js.map +1 -1
  10. package/dist/analysis/param-capability.d.ts +5 -2
  11. package/dist/analysis/param-capability.d.ts.map +1 -1
  12. package/dist/analysis/param-capability.js +36 -4
  13. package/dist/analysis/param-capability.js.map +1 -1
  14. package/dist/analysis/param-structure.d.ts +1 -1
  15. package/dist/analysis/param-structure.d.ts.map +1 -1
  16. package/dist/analysis/param-structure.js.map +1 -1
  17. package/dist/analysis/ts-type.d.ts +1 -1
  18. package/dist/analysis/ts-type.d.ts.map +1 -1
  19. package/dist/analysis/ts-type.js +28 -10
  20. package/dist/analysis/ts-type.js.map +1 -1
  21. package/dist/compile.js +1 -1
  22. package/dist/compile.js.map +1 -1
  23. package/dist/docs/api-reference.d.ts +6 -0
  24. package/dist/docs/api-reference.d.ts.map +1 -1
  25. package/dist/docs/api-reference.js +11 -2
  26. package/dist/docs/api-reference.js.map +1 -1
  27. package/dist/docs/pipeline.d.ts +3 -0
  28. package/dist/docs/pipeline.d.ts.map +1 -1
  29. package/dist/docs/pipeline.js +10 -1
  30. package/dist/docs/pipeline.js.map +1 -1
  31. package/dist/fingerprint.d.ts +5 -0
  32. package/dist/fingerprint.d.ts.map +1 -1
  33. package/dist/fingerprint.js +107 -15
  34. package/dist/fingerprint.js.map +1 -1
  35. package/dist/gi.d.ts +3 -0
  36. package/dist/gi.d.ts.map +1 -1
  37. package/dist/gi.js +29 -7
  38. package/dist/gi.js.map +1 -1
  39. package/dist/gir/external-namespaces.d.ts +8 -0
  40. package/dist/gir/external-namespaces.d.ts.map +1 -0
  41. package/dist/gir/external-namespaces.js +4 -0
  42. package/dist/gir/external-namespaces.js.map +1 -0
  43. package/dist/gir/finish-overrides.d.ts +3 -0
  44. package/dist/gir/finish-overrides.d.ts.map +1 -0
  45. package/dist/gir/finish-overrides.js +5 -0
  46. package/dist/gir/finish-overrides.js.map +1 -0
  47. package/dist/gir/function.d.ts +5 -2
  48. package/dist/gir/function.d.ts.map +1 -1
  49. package/dist/gir/function.js +34 -5
  50. package/dist/gir/function.js.map +1 -1
  51. package/dist/gir/hidden-symbols.d.ts +3 -0
  52. package/dist/gir/hidden-symbols.d.ts.map +1 -0
  53. package/dist/gir/hidden-symbols.js +39 -0
  54. package/dist/gir/hidden-symbols.js.map +1 -0
  55. package/dist/gir/library.d.ts +22 -2
  56. package/dist/gir/library.d.ts.map +1 -1
  57. package/dist/gir/library.js +21 -3
  58. package/dist/gir/library.js.map +1 -1
  59. package/dist/gir/ucs4-overrides.d.ts +3 -0
  60. package/dist/gir/ucs4-overrides.d.ts.map +1 -0
  61. package/dist/gir/ucs4-overrides.js +7 -0
  62. package/dist/gir/ucs4-overrides.js.map +1 -0
  63. package/dist/jsx.d.ts.map +1 -1
  64. package/dist/jsx.js +27 -8
  65. package/dist/jsx.js.map +1 -1
  66. package/dist/runner.d.ts +8 -0
  67. package/dist/runner.d.ts.map +1 -1
  68. package/dist/runner.js +9 -3
  69. package/dist/runner.js.map +1 -1
  70. package/dist/store/external-package-links.d.ts +6 -0
  71. package/dist/store/external-package-links.d.ts.map +1 -0
  72. package/dist/store/external-package-links.js +158 -0
  73. package/dist/store/external-package-links.js.map +1 -0
  74. package/dist/store/gi/callable-doc.d.ts.map +1 -1
  75. package/dist/store/gi/callable-doc.js +4 -4
  76. package/dist/store/gi/callable-doc.js.map +1 -1
  77. package/dist/store/gi/callables.d.ts +1 -1
  78. package/dist/store/gi/callables.d.ts.map +1 -1
  79. package/dist/store/gi/callables.js +4 -4
  80. package/dist/store/gi/callables.js.map +1 -1
  81. package/dist/store/gi/class.d.ts.map +1 -1
  82. package/dist/store/gi/class.js +25 -15
  83. package/dist/store/gi/class.js.map +1 -1
  84. package/dist/store/gi/constructor-props.js +1 -1
  85. package/dist/store/gi/constructor-props.js.map +1 -1
  86. package/dist/store/gi/function.d.ts.map +1 -1
  87. package/dist/store/gi/function.js +2 -1
  88. package/dist/store/gi/function.js.map +1 -1
  89. package/dist/store/gi/gtype-binding.d.ts +2 -2
  90. package/dist/store/gi/gtype-binding.d.ts.map +1 -1
  91. package/dist/store/gi/gtype-binding.js +6 -13
  92. package/dist/store/gi/gtype-binding.js.map +1 -1
  93. package/dist/store/gi/interface.js +2 -2
  94. package/dist/store/gi/interface.js.map +1 -1
  95. package/dist/store/gi/method.d.ts +7 -2
  96. package/dist/store/gi/method.d.ts.map +1 -1
  97. package/dist/store/gi/method.js +126 -30
  98. package/dist/store/gi/method.js.map +1 -1
  99. package/dist/store/gi/param-marshal.d.ts +8 -1
  100. package/dist/store/gi/param-marshal.d.ts.map +1 -1
  101. package/dist/store/gi/param-marshal.js +52 -4
  102. package/dist/store/gi/param-marshal.js.map +1 -1
  103. package/dist/store/gi/record-constructor.d.ts.map +1 -1
  104. package/dist/store/gi/record-constructor.js +2 -3
  105. package/dist/store/gi/record-constructor.js.map +1 -1
  106. package/dist/store/gi/record-field-accessor.d.ts +2 -1
  107. package/dist/store/gi/record-field-accessor.d.ts.map +1 -1
  108. package/dist/store/gi/record-field-accessor.js +142 -16
  109. package/dist/store/gi/record-field-accessor.js.map +1 -1
  110. package/dist/store/gi/record-layout.d.ts +5 -2
  111. package/dist/store/gi/record-layout.d.ts.map +1 -1
  112. package/dist/store/gi/record-layout.js +2 -1
  113. package/dist/store/gi/record-layout.js.map +1 -1
  114. package/dist/store/gi/record.d.ts.map +1 -1
  115. package/dist/store/gi/record.js +9 -5
  116. package/dist/store/gi/record.js.map +1 -1
  117. package/dist/store/gi/runtime-override.js +1 -1
  118. package/dist/store/gi/runtime-override.js.map +1 -1
  119. package/dist/store/gi/signal.js +2 -2
  120. package/dist/store/gi/signal.js.map +1 -1
  121. package/dist/store/gi/vtable.d.ts.map +1 -1
  122. package/dist/store/gi/vtable.js +82 -12
  123. package/dist/store/gi/vtable.js.map +1 -1
  124. package/dist/store/gi-store.d.ts +7 -2
  125. package/dist/store/gi-store.d.ts.map +1 -1
  126. package/dist/store/gi-store.js +19 -4
  127. package/dist/store/gi-store.js.map +1 -1
  128. package/dist/store/jsx/jsx.d.ts.map +1 -1
  129. package/dist/store/jsx/jsx.js +3 -1
  130. package/dist/store/jsx/jsx.js.map +1 -1
  131. package/dist/store/jsx-store.d.ts +8 -1
  132. package/dist/store/jsx-store.d.ts.map +1 -1
  133. package/dist/store/jsx-store.js +9 -2
  134. package/dist/store/jsx-store.js.map +1 -1
  135. package/dist/store/resolve-store.d.ts +2 -1
  136. package/dist/store/resolve-store.d.ts.map +1 -1
  137. package/dist/store/resolve-store.js +2 -1
  138. package/dist/store/resolve-store.js.map +1 -1
  139. package/dist/store/store-fs.d.ts +2 -1
  140. package/dist/store/store-fs.d.ts.map +1 -1
  141. package/dist/store/store-fs.js +8 -3
  142. package/dist/store/store-fs.js.map +1 -1
  143. package/dist/writer/context.d.ts.map +1 -1
  144. package/dist/writer/context.js +8 -0
  145. package/dist/writer/context.js.map +1 -1
  146. package/dist/writer/gtk-doc.d.ts.map +1 -1
  147. package/dist/writer/gtk-doc.js +27 -1
  148. package/dist/writer/gtk-doc.js.map +1 -1
  149. package/overrides/gdk/rgba.ts.ejs +15 -1
  150. package/overrides/glib/index.ts.ejs +3 -0
  151. package/overrides/glib/regex.ts.ejs +66 -0
  152. package/overrides/gobject/index.ts.ejs +3 -0
  153. package/overrides/gobject/object-class.ts.ejs +27 -0
  154. package/overrides/gobject/param-spec-getters.ts.ejs +57 -0
  155. package/overrides/gobject/param-spec.ts.ejs +21 -0
  156. package/overrides/gobject/value.ts.ejs +6 -1
  157. package/overrides/graphene/structs.ts.ejs +38 -3
  158. package/overrides/gtk/index.ts.ejs +2 -0
  159. package/overrides/gtk/widget-class.ts.ejs +28 -0
  160. package/package.json +6 -5
  161. package/src/analysis/descriptor-render.ts +59 -16
  162. package/src/analysis/descriptor.ts +15 -3
  163. package/src/analysis/param-capability.ts +68 -5
  164. package/src/analysis/param-structure.ts +1 -1
  165. package/src/analysis/ts-type.ts +45 -11
  166. package/src/compile.ts +1 -1
  167. package/src/docs/api-reference.ts +20 -2
  168. package/src/docs/pipeline.ts +15 -1
  169. package/src/fingerprint.ts +144 -16
  170. package/src/gi.ts +44 -9
  171. package/src/gir/external-namespaces.ts +8 -0
  172. package/src/gir/finish-overrides.ts +5 -0
  173. package/src/gir/function.ts +52 -14
  174. package/src/gir/hidden-symbols.ts +39 -0
  175. package/src/gir/library.ts +36 -3
  176. package/src/gir/ucs4-overrides.ts +7 -0
  177. package/src/jsx.ts +33 -8
  178. package/src/runner.ts +17 -3
  179. package/src/store/external-package-links.ts +226 -0
  180. package/src/store/gi/callable-doc.ts +8 -4
  181. package/src/store/gi/callables.ts +5 -5
  182. package/src/store/gi/class.ts +42 -32
  183. package/src/store/gi/constructor-props.ts +1 -1
  184. package/src/store/gi/function.ts +2 -1
  185. package/src/store/gi/gtype-binding.ts +7 -15
  186. package/src/store/gi/interface.ts +2 -2
  187. package/src/store/gi/method.ts +189 -36
  188. package/src/store/gi/param-marshal.ts +67 -4
  189. package/src/store/gi/record-constructor.ts +8 -3
  190. package/src/store/gi/record-field-accessor.ts +209 -16
  191. package/src/store/gi/record-layout.ts +11 -1
  192. package/src/store/gi/record.ts +17 -13
  193. package/src/store/gi/runtime-override.ts +1 -1
  194. package/src/store/gi/signal.ts +2 -2
  195. package/src/store/gi/vtable.ts +118 -11
  196. package/src/store/gi-store.ts +33 -3
  197. package/src/store/jsx/jsx.ts +3 -1
  198. package/src/store/jsx-store.ts +23 -7
  199. package/src/store/resolve-store.ts +2 -1
  200. package/src/store/store-fs.ts +10 -2
  201. package/src/writer/context.ts +11 -0
  202. package/src/writer/gtk-doc.ts +38 -1
  203. package/overrides/cairo/context.ts.ejs +0 -1269
  204. package/overrides/cairo/font-face.ts.ejs +0 -151
  205. package/overrides/cairo/font-options.ts.ejs +0 -199
  206. package/overrides/cairo/image-surface.ts.ejs +0 -132
  207. package/overrides/cairo/index.ts.ejs +0 -22
  208. package/overrides/cairo/matrix.ts.ejs +0 -171
  209. package/overrides/cairo/pattern.ts.ejs +0 -476
  210. package/overrides/cairo/recording-surface.ts.ejs +0 -102
  211. package/overrides/cairo/region.ts.ejs +0 -237
  212. package/overrides/cairo/scaled-font.ts.ejs +0 -330
  213. package/overrides/cairo/surface.ts.ejs +0 -296
@@ -0,0 +1,226 @@
1
+ import { existsSync, readFileSync, realpathSync, rmSync } from "node:fs";
2
+ import { createRequire } from "node:module";
3
+ import { dirname, join } from "node:path";
4
+ import { EXTERNAL_NAMESPACES, type ExternalNamespace } from "../gir/external-namespaces.js";
5
+ import { nodeModulesChain } from "./resolve-store.js";
6
+ import { type StoreLink, symlinkRelative } from "./store-fs.js";
7
+
8
+ type ExternalPackageSource = "store" | "hoisted" | "codegen";
9
+
10
+ type ExternalPackageResolution = {
11
+ packageName: string;
12
+ directory: string;
13
+ dir: string;
14
+ source: ExternalPackageSource;
15
+ };
16
+
17
+ const DEPENDENCY_FIELDS = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"];
18
+ const codegenRequire = createRequire(import.meta.url);
19
+ const codegenPackageDirs: Map<string, string | undefined> = new Map();
20
+ const ensuredStores: Set<string> = new Set();
21
+
22
+ const storeAnchor = (link: StoreLink): string => dirname(dirname(link.linkDir));
23
+ const namespaceShimDirectory = (entry: ExternalNamespace): string => entry.namespace.toLowerCase();
24
+
25
+ const resolveFromStore = (link: StoreLink, packageName: string): string | undefined => {
26
+ const chain = nodeModulesChain(dirname(storeAnchor(link)));
27
+
28
+ for (const nodeModules of chain) {
29
+ const manifest = join(nodeModules, packageName, "package.json");
30
+
31
+ if (existsSync(manifest)) {
32
+ return dirname(realpathSync(manifest));
33
+ }
34
+ }
35
+
36
+ return undefined;
37
+ };
38
+
39
+ const projectManifestPath = (link: StoreLink): string => join(dirname(storeAnchor(link)), "package.json");
40
+
41
+ const readManifest = (manifestPath: string): Record<string, unknown> | undefined => {
42
+ try {
43
+ return JSON.parse(readFileSync(manifestPath, "utf8")) as Record<string, unknown>;
44
+ } catch {
45
+ return undefined;
46
+ }
47
+ };
48
+
49
+ const sectionNames = (section: unknown): string[] =>
50
+ typeof section === "object" && section !== null ? Object.keys(section) : [];
51
+
52
+ const declaredDependencies = (manifest: Record<string, unknown>): Set<string> =>
53
+ new Set(DEPENDENCY_FIELDS.flatMap((field) => sectionNames(manifest[field])));
54
+
55
+ const isDeclaredByProject = (link: StoreLink, packageName: string): boolean => {
56
+ const manifest = readManifest(projectManifestPath(link));
57
+
58
+ return manifest === undefined || declaredDependencies(manifest).has(packageName);
59
+ };
60
+
61
+ const resolveFromCodegen = (packageName: string): string | undefined => {
62
+ if (codegenPackageDirs.has(packageName)) {
63
+ return codegenPackageDirs.get(packageName);
64
+ }
65
+
66
+ let dir: string | undefined;
67
+
68
+ try {
69
+ dir = dirname(realpathSync(codegenRequire.resolve(`${packageName}/package.json`)));
70
+ } catch {
71
+ dir = undefined;
72
+ }
73
+
74
+ codegenPackageDirs.set(packageName, dir);
75
+
76
+ return dir;
77
+ };
78
+
79
+ const resolveEntry = (link: StoreLink, entry: ExternalNamespace): ExternalPackageResolution | undefined => {
80
+ const directory = namespaceShimDirectory(entry);
81
+ const chainResolved = resolveFromStore(link, entry.packageName);
82
+
83
+ if (chainResolved !== undefined) {
84
+ const source = isDeclaredByProject(link, entry.packageName) ? "store" : "hoisted";
85
+
86
+ return { packageName: entry.packageName, directory, dir: chainResolved, source };
87
+ }
88
+
89
+ const codegenDir = resolveFromCodegen(entry.packageName);
90
+
91
+ if (codegenDir !== undefined) {
92
+ return { packageName: entry.packageName, directory, dir: codegenDir, source: "codegen" };
93
+ }
94
+
95
+ return undefined;
96
+ };
97
+
98
+ const resolveExternalPackages = (link: StoreLink): ExternalPackageResolution[] => {
99
+ const resolutions: ExternalPackageResolution[] = [];
100
+
101
+ for (const entry of EXTERNAL_NAMESPACES) {
102
+ const resolution = resolveEntry(link, entry);
103
+
104
+ if (resolution !== undefined) {
105
+ resolutions.push(resolution);
106
+ }
107
+ }
108
+
109
+ return resolutions;
110
+ };
111
+
112
+ const isLinkedTo = (linkPath: string, dir: string): boolean => {
113
+ try {
114
+ return realpathSync(linkPath) === realpathSync(dir);
115
+ } catch {
116
+ return false;
117
+ }
118
+ };
119
+
120
+ const applyLink = (storeDir: string, resolution: ExternalPackageResolution): void => {
121
+ const linkPath = join(storeDir, "node_modules", resolution.packageName);
122
+
123
+ if (resolution.source === "codegen") {
124
+ if (!isLinkedTo(linkPath, resolution.dir)) {
125
+ symlinkRelative(linkPath, resolution.dir);
126
+ }
127
+
128
+ return;
129
+ }
130
+
131
+ rmSync(linkPath, { recursive: true, force: true });
132
+ };
133
+
134
+ const tryApplyLink = (storeDir: string, resolution: ExternalPackageResolution): void => {
135
+ try {
136
+ applyLink(storeDir, resolution);
137
+ } catch {
138
+ return;
139
+ }
140
+ };
141
+
142
+ const ensureExternalPackageLinks = (link: StoreLink): void => {
143
+ if (ensuredStores.has(link.storeDir)) {
144
+ return;
145
+ }
146
+
147
+ if (!existsSync(join(link.storeDir, "package.json"))) {
148
+ return;
149
+ }
150
+
151
+ for (const resolution of resolveExternalPackages(link)) {
152
+ tryApplyLink(link.storeDir, resolution);
153
+ }
154
+
155
+ ensuredStores.add(link.storeDir);
156
+ };
157
+
158
+ const resetExternalPackageLinks = (storeDir: string): void => {
159
+ ensuredStores.delete(storeDir);
160
+ };
161
+
162
+ const externalPackageNotice = (resolution: ExternalPackageResolution): string =>
163
+ `${resolution.packageName} is not installed in this project, so the copy @gtkx/codegen depends on was ` +
164
+ `linked into the generated store; add ${resolution.packageName} to your dependencies, because GTKX 2.0 ` +
165
+ "stops doing this.";
166
+
167
+ const hoistedPackageNotice = (resolution: ExternalPackageResolution): string =>
168
+ `${resolution.packageName} is not declared in this project's package.json and only resolves because ` +
169
+ `your package manager hoisted it; add ${resolution.packageName} to your dependencies, because GTKX 2.0 ` +
170
+ "requires the direct dependency.";
171
+
172
+ const hasShim = (storeDir: string, entry: ExternalNamespace): boolean =>
173
+ existsSync(join(storeDir, namespaceShimDirectory(entry), "index.js"));
174
+
175
+ const hasStoreLocalLink = (storeDir: string, packageName: string): boolean =>
176
+ existsSync(join(storeDir, "node_modules", packageName, "package.json"));
177
+
178
+ const unresolvableMessage = (link: StoreLink, entry: ExternalNamespace): string =>
179
+ `Cannot resolve ${entry.packageName} from ${storeAnchor(link)} or from @gtkx/codegen; ` +
180
+ "install it next to @gtkx/runtime.";
181
+
182
+ const linkFailedMessage = (link: StoreLink, entry: ExternalNamespace): string =>
183
+ `Cannot link ${entry.packageName} into the generated store at ${link.storeDir}; ` +
184
+ `install ${entry.packageName} next to @gtkx/runtime.`;
185
+
186
+ const entryNotice = (link: StoreLink, entry: ExternalNamespace): string | undefined => {
187
+ if (!hasShim(link.storeDir, entry)) {
188
+ return undefined;
189
+ }
190
+
191
+ const resolution = resolveEntry(link, entry);
192
+
193
+ if (resolution === undefined) {
194
+ throw new Error(unresolvableMessage(link, entry));
195
+ }
196
+
197
+ if (resolution.source === "store") {
198
+ return undefined;
199
+ }
200
+
201
+ if (resolution.source === "hoisted") {
202
+ return hoistedPackageNotice(resolution);
203
+ }
204
+
205
+ if (!hasStoreLocalLink(link.storeDir, resolution.packageName)) {
206
+ throw new Error(linkFailedMessage(link, entry));
207
+ }
208
+
209
+ return externalPackageNotice(resolution);
210
+ };
211
+
212
+ const externalPackageNotices = (link: StoreLink): string[] => {
213
+ const notices: string[] = [];
214
+
215
+ for (const entry of EXTERNAL_NAMESPACES) {
216
+ const notice = entryNotice(link, entry);
217
+
218
+ if (notice !== undefined) {
219
+ notices.push(notice);
220
+ }
221
+ }
222
+
223
+ return notices;
224
+ };
225
+
226
+ export { ensureExternalPackageLinks, externalPackageNotices, resetExternalPackageLinks };
@@ -12,7 +12,7 @@ import {
12
12
  } from "../../analysis/param-structure.js";
13
13
  import { renderJsDoc } from "../../writer/doc.js";
14
14
  import { annotationSpec, THROWS_TEXT } from "./doc-spec.js";
15
- import { isCallbackParameter, returnedOutParameters } from "./method.js";
15
+ import { isCallbackParameter, returnedOutParameters, shouldTrimFinishBoolean } from "./method.js";
16
16
 
17
17
  type CallableDocOptions = {
18
18
  finishFn?: GirFunction | undefined;
@@ -53,9 +53,9 @@ const tupleReturnsText = (primary: string | undefined, outs: InputParameter[]):
53
53
  return bullets.length === 0 ? undefined : `Tuple of:\n\n${bullets.join("\n")}`;
54
54
  };
55
55
 
56
- const returnsText = (context: ModuleContext, fn: GirFunction): string | undefined => {
56
+ const returnsText = (context: ModuleContext, fn: GirFunction, isPrimaryTrimmed: boolean): string | undefined => {
57
57
  const outs = returnedOutParameters(context, fn);
58
- const isPrimaryOmitted = shouldOmitPrimaryReturn(context.library, fn.returnValue);
58
+ const isPrimaryOmitted = isPrimaryTrimmed || shouldOmitPrimaryReturn(context.library, fn.returnValue);
59
59
  const primary = isPrimaryOmitted ? undefined : fn.returnValue.doc;
60
60
 
61
61
  if (outs.length === 0) {
@@ -92,7 +92,11 @@ const callableSpec = (context: ModuleContext, callable: GirFunction, options: Ca
92
92
  (parameter) => options.finishFn !== undefined && isCallbackParameter(context, parameter),
93
93
  options.renames,
94
94
  ),
95
- returns: returnsText(context, options.finishFn ?? callable),
95
+ returns: returnsText(
96
+ context,
97
+ options.finishFn ?? callable,
98
+ options.finishFn !== undefined && shouldTrimFinishBoolean(context, options.finishFn),
99
+ ),
96
100
  throws: canCallableThrow(callable, options.finishFn) ? THROWS_TEXT : undefined,
97
101
  });
98
102
 
@@ -7,7 +7,7 @@ import { renderBlock } from "../../writer/emit.js";
7
7
  import { matchAsyncFinish } from "./async.js";
8
8
  import { callableDoc, callableSpec } from "./callable-doc.js";
9
9
  import { renderFnExpression } from "./function.js";
10
- import { gtypeMemberDeclaration, gtypeStaticMember } from "./gtype-binding.js";
10
+ import { gtypeMemberDeclaration } from "./gtype-binding.js";
11
11
  import {
12
12
  finishCallExpression,
13
13
  memberName,
@@ -66,7 +66,7 @@ type PlainTypeMembersOptions = {
66
66
  context: ModuleContext;
67
67
  className: string;
68
68
  callables: Callables;
69
- gtypeExpr: string | undefined;
69
+ hasGtype: boolean;
70
70
  };
71
71
 
72
72
  const RUNTIME_OWNED_LIFETIME_METHODS: Set<string> = new Set([
@@ -358,7 +358,7 @@ const renderPromisifiedCallable = (
358
358
  const body = renderPromisifiedBody(
359
359
  context,
360
360
  callable,
361
- finishCallExpression(callable, finishFn, member.ownerName),
361
+ { fn: finishFn, expression: finishCallExpression(callable, finishFn, member.ownerName) },
362
362
  toCamelIdentifier(cIdentifier),
363
363
  );
364
364
 
@@ -514,11 +514,11 @@ const renderPlainInstanceMethods = (
514
514
  const renderPlainTypeMembers = (
515
515
  options: PlainTypeMembersOptions,
516
516
  ): { members: string[]; claimedNames: Set<string> } => {
517
- const { context, className, callables, gtypeExpr } = options;
517
+ const { context, className, callables, hasGtype } = options;
518
518
  const claimedNames: Set<string> = new Set();
519
519
 
520
520
  const members: string[] = [
521
- ...(gtypeExpr === undefined ? [] : [gtypeMemberDeclaration(context), gtypeStaticMember(context)]),
521
+ ...(hasGtype ? [gtypeMemberDeclaration(context)] : []),
522
522
  ...renderStaticHead(context, callables, className),
523
523
  ...renderPlainInstanceMethods(context, callables.methods, claimedNames),
524
524
  ];
@@ -34,7 +34,7 @@ import {
34
34
  } from "./callables.js";
35
35
  import { renderClassConstructor, renderConstructorPropsInterface } from "./constructor-props.js";
36
36
  import { getDoc } from "./doc-spec.js";
37
- import { gtypeMemberDeclaration, gtypeStaticMember, renderSourceGtype } from "./gtype-binding.js";
37
+ import { gtypeMemberDeclaration, renderSourceGtype } from "./gtype-binding.js";
38
38
  import { methodExportName } from "./method.js";
39
39
  import { renderPropertyDeclarations } from "./properties.js";
40
40
  import { renderResolvedPropertyAccessor, resolveAccessor, type ResolvedAccessor } from "./property-accessor.js";
@@ -60,14 +60,6 @@ type MemberDeclarationsOptions = {
60
60
 
61
61
  type ClassMembers = { members: string[]; accessors: ResolvedAccessor[] };
62
62
 
63
- type ClassMembersOptions = {
64
- context: ModuleContext;
65
- klass: GirClass;
66
- callables: Callables;
67
- gtypeExpr: string | undefined;
68
- hasParent: boolean;
69
- };
70
-
71
63
  type ImplementedRefOptions = {
72
64
  context: ModuleContext;
73
65
  klass: GirClass;
@@ -105,16 +97,7 @@ const generateClass = (context: ModuleContext, klass: GirClass): void => {
105
97
  const implemented = resolveImplementedRefs(context, klass);
106
98
  const typeRefs = implemented.map((ref) => omittedTypeRef(ref.typeRef, ref.conflicts));
107
99
  const implementsClause = typeRefs.length === 0 ? "" : ` implements ${typeRefs.join(", ")}`;
108
- const gtypeExpr = renderSourceGtype(context, klass);
109
-
110
- const { members, accessors } = renderClassMembers({
111
- context,
112
- klass,
113
- callables,
114
- gtypeExpr,
115
- hasParent: parentExpression !== undefined,
116
- });
117
-
100
+ const { members, accessors } = renderClassMembers(context, klass, callables, parentExpression !== undefined);
118
101
  const body = indentMembers(members);
119
102
  const doc = getDoc(klass);
120
103
  const modifier = klass.isAbstract ? "abstract " : "";
@@ -132,7 +115,7 @@ const generateClass = (context: ModuleContext, klass: GirClass): void => {
132
115
 
133
116
  appendMemberDeclarations({ context, klass, className, accessors, implemented });
134
117
  appendInstallMixins(context, className, implemented);
135
- appendClassRegistrations(context, klass, className, gtypeExpr);
118
+ appendClassRegistrations(context, klass, className);
136
119
  };
137
120
 
138
121
  const appendMemberDeclarations = (options: MemberDeclarationsOptions): void => {
@@ -167,14 +150,15 @@ const appendInterfaceMerge = (
167
150
  });
168
151
  };
169
152
 
170
- const renderClassMembers = (options: ClassMembersOptions): ClassMembers => {
171
- const { context, klass, callables, gtypeExpr } = options;
153
+ const renderClassMembers = (
154
+ context: ModuleContext,
155
+ klass: GirClass,
156
+ callables: Callables,
157
+ hasParent: boolean,
158
+ ): ClassMembers => {
172
159
  const className = sanitizeTypeIdentifier(klass.name);
173
-
174
- const members: string[] =
175
- gtypeExpr === undefined ? [] : [gtypeMemberDeclaration(context), gtypeStaticMember(context)];
176
-
177
- const constructorBlock = renderClassConstructor(context, klass, className, options.hasParent);
160
+ const members: string[] = [gtypeMemberDeclaration(context)];
161
+ const constructorBlock = renderClassConstructor(context, klass, className, hasParent);
178
162
 
179
163
  if (constructorBlock !== undefined) {
180
164
  members.push(constructorBlock);
@@ -255,17 +239,43 @@ const appendInstallMixins = (context: ModuleContext, className: string, implemen
255
239
  ]);
256
240
  };
257
241
 
258
- const appendClassRegistrations = (
242
+ const appendClassRegistrations = (context: ModuleContext, klass: GirClass, className: string): void => {
243
+ const gtypeExpr = renderSourceGtype(context, klass);
244
+
245
+ appendWrapperClassRegistration(context, {
246
+ className,
247
+ gtypeExpr,
248
+ vfuncs: renderVfuncMetadata(context, klass),
249
+ });
250
+
251
+ appendClassStructRegistration(context, klass, className, gtypeExpr);
252
+ };
253
+
254
+ const appendClassStructRegistration = (
259
255
  context: ModuleContext,
260
256
  klass: GirClass,
261
257
  className: string,
262
258
  gtypeExpr: string | undefined,
263
259
  ): void => {
264
- appendWrapperClassRegistration(context, {
260
+ const typeStruct = klass.glibTypeStruct;
261
+
262
+ if (gtypeExpr === undefined || typeStruct === undefined) {
263
+ return;
264
+ }
265
+
266
+ const resolved = context.library.resolveType(context.namespace.name, typeStruct);
267
+
268
+ if (resolved?.kind !== "record" || !isEmittableEntity(resolved.value)) {
269
+ return;
270
+ }
271
+
272
+ const structName = sanitizeTypeIdentifier(resolved.value.name);
273
+ context.addRuntimeImport("registerClassStruct");
274
+
275
+ context.module.appendRegistration(`registerClassStruct(${className}, ${structName});`, [
265
276
  className,
266
- gtypeExpr,
267
- vfuncs: renderVfuncMetadata(context, klass),
268
- });
277
+ structName,
278
+ ]);
269
279
  };
270
280
 
271
281
  const addAncestorInterfaceKeys = (context: ModuleContext, ancestor: ResolvedAncestor, keys: Set<string>): void => {
@@ -76,7 +76,7 @@ const renderRootConstructor = (context: ModuleContext): string => {
76
76
  context.addRuntimeTypeImport("AnyClass");
77
77
  context.addRuntimeImport("getClassType");
78
78
  context.addRuntimeImport("newObjectWithProperties");
79
- const body = "newObjectWithProperties(getClassType(this.constructor as AnyClass), props, this);";
79
+ const body = "return newObjectWithProperties(getClassType(this.constructor as AnyClass), props, this);";
80
80
 
81
81
  return renderBlock("constructor(props: object = {})", body);
82
82
  };
@@ -48,6 +48,7 @@ const renderFnExpression = (context: ModuleContext, fn: GirFunction): string | u
48
48
  args: arrayLiteral(params),
49
49
  returns: returnPlan.descriptor,
50
50
  isReturnSkipped: returnPlan.isSkipped,
51
+ isReturnUnpacked: returnPlan.isUnpacked,
51
52
  canThrow: fn.throws,
52
53
  });
53
54
  };
@@ -132,7 +133,7 @@ const matchNamespaceFinish = (context: ModuleContext, fn: GirFunction): Namespac
132
133
  const renderPromisifiedNamespaceFunction = (options: NamespaceFunctionOptions, finish: NamespaceFinish): string => {
133
134
  const { context, fn, exportName, bindingName } = options;
134
135
  const { signature, returnType } = renderPromisifiedSignature(context, fn, finish.fn);
135
- const body = renderPromisifiedBody(context, fn, finish.exportName, bindingName);
136
+ const body = renderPromisifiedBody(context, fn, { fn: finish.fn, expression: finish.exportName }, bindingName);
136
137
 
137
138
  return renderBlock(`export function ${exportName}(${signature}): ${returnType}`, body);
138
139
  };
@@ -1,32 +1,24 @@
1
1
  import { sourceStringLiteral } from "@gtkx/utils";
2
2
  import type { ModuleContext } from "../../writer/context.js";
3
3
  import { PRIMITIVE_TS_TYPE } from "../../gir/primitives.js";
4
- import { renderJsDoc } from "../../writer/doc.js";
5
- import { renderBlock } from "../../writer/emit.js";
6
4
 
7
5
  type TypeSource = {
8
6
  glibGetType: string | undefined;
9
7
  glibTypeName: string | undefined;
10
8
  };
11
9
 
12
- const GTYPE_NOTE = [
13
- "The GType this class is registered under, read off the class it is accessed on rather than",
14
- "inherited, so a subclass `registerClass` created reports its own type and one that never went",
15
- "through `registerClass` reports the invalid type.",
16
- ].join("\n");
17
-
18
10
  const gtypeTsType = (context: ModuleContext): string =>
19
11
  context.namespace.name === "GObject" ? "Type" : PRIMITIVE_TS_TYPE.gtype;
20
12
 
21
- const gtypeMemberDeclaration = (context: ModuleContext): string => `declare __type__: ${gtypeTsType(context)};`;
22
-
23
- const gtypeStaticMember = (context: ModuleContext): string => {
24
- context.addRuntimeImport("getClassType");
25
- const block = renderBlock(`static get __gtype__(): ${gtypeTsType(context)}`, "return getClassType(this);");
13
+ const gtypeParamTsType = (context: ModuleContext): string => {
14
+ context.addRuntimeTypeImport("AnyClass");
15
+ context.addRuntimeTypeImport("TypedClass");
26
16
 
27
- return `${renderJsDoc(undefined, GTYPE_NOTE)}${block}`;
17
+ return `${gtypeTsType(context)} | AnyClass<TypedClass>`;
28
18
  };
29
19
 
20
+ const gtypeMemberDeclaration = (context: ModuleContext): string => `declare __type__: ${gtypeTsType(context)};`;
21
+
30
22
  const renderInternGtype = (context: ModuleContext, typeName: string | undefined): string | undefined => {
31
23
  if (typeName === undefined) {
32
24
  return undefined;
@@ -63,4 +55,4 @@ const renderSourceGtype = (context: ModuleContext, source: TypeSource): string |
63
55
  ? undefined
64
56
  : renderGtypeExpression(context, source.glibGetType, source.glibTypeName);
65
57
 
66
- export { gtypeTsType, gtypeMemberDeclaration, gtypeStaticMember, renderSourceGtype };
58
+ export { gtypeTsType, gtypeParamTsType, gtypeMemberDeclaration, renderSourceGtype };
@@ -21,7 +21,7 @@ import {
21
21
  renderStaticHead,
22
22
  } from "./callables.js";
23
23
  import { annotationSpec, getDoc } from "./doc-spec.js";
24
- import { gtypeStaticMember, renderSourceGtype } from "./gtype-binding.js";
24
+ import { gtypeMemberDeclaration, renderSourceGtype } from "./gtype-binding.js";
25
25
  import { methodExportName } from "./method.js";
26
26
  import {
27
27
  type PropertyAccessorArgs,
@@ -378,7 +378,7 @@ const renderInterfaceClass = (context: ModuleContext, options: InterfaceClassOpt
378
378
  const members: string[] = [];
379
379
 
380
380
  if (gtypeExpr !== undefined) {
381
- members.push(renderInterfaceHasInstance(context, className, gtypeExpr), gtypeStaticMember(context));
381
+ members.push(gtypeMemberDeclaration(context), renderInterfaceHasInstance(context, className, gtypeExpr));
382
382
  }
383
383
 
384
384
  members.push(...renderStaticHead(context, callables, className), renderInterfaceBrand(context, implRef));