@gtkx/codegen 1.0.0 → 1.1.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 (316) hide show
  1. package/README.md +1 -1
  2. package/dist/analysis/descriptor-render.d.ts +12 -15
  3. package/dist/analysis/descriptor-render.d.ts.map +1 -1
  4. package/dist/analysis/descriptor-render.js +48 -31
  5. package/dist/analysis/descriptor-render.js.map +1 -1
  6. package/dist/analysis/descriptor.d.ts +16 -7
  7. package/dist/analysis/descriptor.d.ts.map +1 -1
  8. package/dist/analysis/descriptor.js +15 -3
  9. package/dist/analysis/descriptor.js.map +1 -1
  10. package/dist/analysis/inheritance.d.ts +4 -2
  11. package/dist/analysis/inheritance.d.ts.map +1 -1
  12. package/dist/analysis/inheritance.js +80 -38
  13. package/dist/analysis/inheritance.js.map +1 -1
  14. package/dist/analysis/interface-conflicts.d.ts +23 -0
  15. package/dist/analysis/interface-conflicts.d.ts.map +1 -0
  16. package/dist/analysis/interface-conflicts.js +144 -0
  17. package/dist/analysis/interface-conflicts.js.map +1 -0
  18. package/dist/analysis/param-capability.d.ts.map +1 -1
  19. package/dist/analysis/param-capability.js +3 -4
  20. package/dist/analysis/param-capability.js.map +1 -1
  21. package/dist/analysis/param-structure.js +2 -2
  22. package/dist/analysis/param-structure.js.map +1 -1
  23. package/dist/analysis/ts-type.d.ts.map +1 -1
  24. package/dist/analysis/ts-type.js +10 -17
  25. package/dist/analysis/ts-type.js.map +1 -1
  26. package/dist/analysis/type-key.d.ts +5 -0
  27. package/dist/analysis/type-key.d.ts.map +1 -0
  28. package/dist/analysis/type-key.js +9 -0
  29. package/dist/analysis/type-key.js.map +1 -0
  30. package/dist/compile.d.ts +12 -3
  31. package/dist/compile.d.ts.map +1 -1
  32. package/dist/compile.js +73 -24
  33. package/dist/compile.js.map +1 -1
  34. package/dist/docs/api-reference.d.ts.map +1 -1
  35. package/dist/docs/api-reference.js +10 -9
  36. package/dist/docs/api-reference.js.map +1 -1
  37. package/dist/docs/element-page.d.ts.map +1 -1
  38. package/dist/docs/element-page.js +5 -3
  39. package/dist/docs/element-page.js.map +1 -1
  40. package/dist/docs/pipeline.d.ts.map +1 -1
  41. package/dist/docs/pipeline.js +85 -18
  42. package/dist/docs/pipeline.js.map +1 -1
  43. package/dist/docs/render.d.ts +2 -1
  44. package/dist/docs/render.d.ts.map +1 -1
  45. package/dist/docs/render.js +5 -4
  46. package/dist/docs/render.js.map +1 -1
  47. package/dist/docs/symbol-page.d.ts.map +1 -1
  48. package/dist/docs/symbol-page.js +9 -6
  49. package/dist/docs/symbol-page.js.map +1 -1
  50. package/dist/fingerprint.d.ts +12 -1
  51. package/dist/fingerprint.d.ts.map +1 -1
  52. package/dist/fingerprint.js +44 -28
  53. package/dist/fingerprint.js.map +1 -1
  54. package/dist/gi.d.ts.map +1 -1
  55. package/dist/gi.js +1 -0
  56. package/dist/gi.js.map +1 -1
  57. package/dist/gir/ancestry.d.ts +7 -1
  58. package/dist/gir/ancestry.d.ts.map +1 -1
  59. package/dist/gir/ancestry.js +9 -1
  60. package/dist/gir/ancestry.js.map +1 -1
  61. package/dist/gir/annotations.d.ts +1 -2
  62. package/dist/gir/annotations.d.ts.map +1 -1
  63. package/dist/gir/annotations.js +1 -1
  64. package/dist/gir/annotations.js.map +1 -1
  65. package/dist/gir/cursor-overrides.d.ts +8 -0
  66. package/dist/gir/cursor-overrides.d.ts.map +1 -0
  67. package/dist/gir/cursor-overrides.js +6 -0
  68. package/dist/gir/cursor-overrides.js.map +1 -0
  69. package/dist/gir/emittable.d.ts +7 -0
  70. package/dist/gir/emittable.d.ts.map +1 -0
  71. package/dist/gir/emittable.js +3 -0
  72. package/dist/gir/emittable.js.map +1 -0
  73. package/dist/gir/function.d.ts.map +1 -1
  74. package/dist/gir/function.js +28 -2
  75. package/dist/gir/function.js.map +1 -1
  76. package/dist/gir/library.js +1 -1
  77. package/dist/gir/library.js.map +1 -1
  78. package/dist/gir/namespace.d.ts +5 -1
  79. package/dist/gir/namespace.d.ts.map +1 -1
  80. package/dist/gir/namespace.js +4 -2
  81. package/dist/gir/namespace.js.map +1 -1
  82. package/dist/gir/parameter.d.ts +13 -1
  83. package/dist/gir/parameter.d.ts.map +1 -1
  84. package/dist/gir/parameter.js +1 -0
  85. package/dist/gir/parameter.js.map +1 -1
  86. package/dist/gir/parse.d.ts.map +1 -1
  87. package/dist/gir/parse.js +3 -6
  88. package/dist/gir/parse.js.map +1 -1
  89. package/dist/guards.d.ts +16 -0
  90. package/dist/guards.d.ts.map +1 -0
  91. package/dist/guards.js +11 -0
  92. package/dist/guards.js.map +1 -0
  93. package/dist/internal.d.ts +2 -0
  94. package/dist/internal.d.ts.map +1 -1
  95. package/dist/internal.js +2 -0
  96. package/dist/internal.js.map +1 -1
  97. package/dist/json.d.ts +3 -0
  98. package/dist/json.d.ts.map +1 -0
  99. package/dist/json.js +11 -0
  100. package/dist/json.js.map +1 -0
  101. package/dist/khronos/modules.d.ts.map +1 -1
  102. package/dist/khronos/modules.js +22 -7
  103. package/dist/khronos/modules.js.map +1 -1
  104. package/dist/khronos/parse.d.ts.map +1 -1
  105. package/dist/khronos/parse.js +3 -4
  106. package/dist/khronos/parse.js.map +1 -1
  107. package/dist/khronos/pipeline.d.ts +1 -1
  108. package/dist/khronos/pipeline.d.ts.map +1 -1
  109. package/dist/khronos/pipeline.js.map +1 -1
  110. package/dist/khronos/plan.d.ts +1 -7
  111. package/dist/khronos/plan.d.ts.map +1 -1
  112. package/dist/khronos/plan.js +1 -1
  113. package/dist/khronos/plan.js.map +1 -1
  114. package/dist/runner.d.ts +5 -1
  115. package/dist/runner.d.ts.map +1 -1
  116. package/dist/runner.js +16 -0
  117. package/dist/runner.js.map +1 -1
  118. package/dist/staging.d.ts +5 -0
  119. package/dist/staging.d.ts.map +1 -0
  120. package/dist/staging.js +57 -0
  121. package/dist/staging.js.map +1 -0
  122. package/dist/store/compile-store.d.ts.map +1 -1
  123. package/dist/store/compile-store.js +4 -2
  124. package/dist/store/compile-store.js.map +1 -1
  125. package/dist/store/gi/callables.d.ts +7 -2
  126. package/dist/store/gi/callables.d.ts.map +1 -1
  127. package/dist/store/gi/callables.js +25 -30
  128. package/dist/store/gi/callables.js.map +1 -1
  129. package/dist/store/gi/callback.d.ts.map +1 -1
  130. package/dist/store/gi/callback.js +9 -5
  131. package/dist/store/gi/callback.js.map +1 -1
  132. package/dist/store/gi/class.d.ts.map +1 -1
  133. package/dist/store/gi/class.js +59 -38
  134. package/dist/store/gi/class.js.map +1 -1
  135. package/dist/store/gi/companion.d.ts.map +1 -1
  136. package/dist/store/gi/companion.js +6 -6
  137. package/dist/store/gi/companion.js.map +1 -1
  138. package/dist/store/gi/constant.d.ts.map +1 -1
  139. package/dist/store/gi/constant.js +10 -2
  140. package/dist/store/gi/constant.js.map +1 -1
  141. package/dist/store/gi/constructor-props.js +1 -1
  142. package/dist/store/gi/constructor-props.js.map +1 -1
  143. package/dist/store/gi/enum.d.ts.map +1 -1
  144. package/dist/store/gi/enum.js +28 -8
  145. package/dist/store/gi/enum.js.map +1 -1
  146. package/dist/store/gi/function.d.ts +1 -3
  147. package/dist/store/gi/function.d.ts.map +1 -1
  148. package/dist/store/gi/function.js +24 -18
  149. package/dist/store/gi/function.js.map +1 -1
  150. package/dist/store/gi/gtype-binding.d.ts.map +1 -1
  151. package/dist/store/gi/gtype-binding.js +4 -1
  152. package/dist/store/gi/gtype-binding.js.map +1 -1
  153. package/dist/store/gi/interface.d.ts.map +1 -1
  154. package/dist/store/gi/interface.js +32 -17
  155. package/dist/store/gi/interface.js.map +1 -1
  156. package/dist/store/gi/method.d.ts +7 -6
  157. package/dist/store/gi/method.d.ts.map +1 -1
  158. package/dist/store/gi/method.js +13 -21
  159. package/dist/store/gi/method.js.map +1 -1
  160. package/dist/store/gi/param-marshal.d.ts +3 -2
  161. package/dist/store/gi/param-marshal.d.ts.map +1 -1
  162. package/dist/store/gi/param-marshal.js +50 -5
  163. package/dist/store/gi/param-marshal.js.map +1 -1
  164. package/dist/store/gi/pipeline.d.ts.map +1 -1
  165. package/dist/store/gi/pipeline.js +21 -10
  166. package/dist/store/gi/pipeline.js.map +1 -1
  167. package/dist/store/gi/properties.d.ts +2 -1
  168. package/dist/store/gi/properties.d.ts.map +1 -1
  169. package/dist/store/gi/properties.js +6 -3
  170. package/dist/store/gi/properties.js.map +1 -1
  171. package/dist/store/gi/property-accessor.d.ts +10 -5
  172. package/dist/store/gi/property-accessor.d.ts.map +1 -1
  173. package/dist/store/gi/property-accessor.js +95 -44
  174. package/dist/store/gi/property-accessor.js.map +1 -1
  175. package/dist/store/gi/record-constructor.d.ts +8 -1
  176. package/dist/store/gi/record-constructor.d.ts.map +1 -1
  177. package/dist/store/gi/record-constructor.js +31 -10
  178. package/dist/store/gi/record-constructor.js.map +1 -1
  179. package/dist/store/gi/record-field-accessor.d.ts.map +1 -1
  180. package/dist/store/gi/record-field-accessor.js +5 -1
  181. package/dist/store/gi/record-field-accessor.js.map +1 -1
  182. package/dist/store/gi/record-layout.d.ts +6 -1
  183. package/dist/store/gi/record-layout.d.ts.map +1 -1
  184. package/dist/store/gi/record-layout.js +8 -1
  185. package/dist/store/gi/record-layout.js.map +1 -1
  186. package/dist/store/gi/record.d.ts.map +1 -1
  187. package/dist/store/gi/record.js +19 -8
  188. package/dist/store/gi/record.js.map +1 -1
  189. package/dist/store/gi/registration.js +2 -2
  190. package/dist/store/gi/registration.js.map +1 -1
  191. package/dist/store/gi/signal.d.ts +2 -1
  192. package/dist/store/gi/signal.d.ts.map +1 -1
  193. package/dist/store/gi/signal.js +30 -24
  194. package/dist/store/gi/signal.js.map +1 -1
  195. package/dist/store/gi/value-marshalable.d.ts.map +1 -1
  196. package/dist/store/gi/value-marshalable.js +2 -1
  197. package/dist/store/gi/value-marshalable.js.map +1 -1
  198. package/dist/store/gi/vtable.d.ts +4 -1
  199. package/dist/store/gi/vtable.d.ts.map +1 -1
  200. package/dist/store/gi/vtable.js +60 -17
  201. package/dist/store/gi/vtable.js.map +1 -1
  202. package/dist/store/gi-store.d.ts +1 -0
  203. package/dist/store/gi-store.d.ts.map +1 -1
  204. package/dist/store/gi-store.js +15 -20
  205. package/dist/store/gi-store.js.map +1 -1
  206. package/dist/store/jsx/generated-elements.d.ts +2 -1
  207. package/dist/store/jsx/generated-elements.d.ts.map +1 -1
  208. package/dist/store/jsx/generated-elements.js +13 -7
  209. package/dist/store/jsx/generated-elements.js.map +1 -1
  210. package/dist/store/jsx/jsx.js +3 -3
  211. package/dist/store/jsx/jsx.js.map +1 -1
  212. package/dist/store/jsx/metadata.d.ts.map +1 -1
  213. package/dist/store/jsx/metadata.js +3 -1
  214. package/dist/store/jsx/metadata.js.map +1 -1
  215. package/dist/store/jsx-store.d.ts.map +1 -1
  216. package/dist/store/jsx-store.js +3 -3
  217. package/dist/store/jsx-store.js.map +1 -1
  218. package/dist/store/resolve-store.d.ts +14 -3
  219. package/dist/store/resolve-store.d.ts.map +1 -1
  220. package/dist/store/resolve-store.js +98 -15
  221. package/dist/store/resolve-store.js.map +1 -1
  222. package/dist/store/store-fs.d.ts +9 -6
  223. package/dist/store/store-fs.d.ts.map +1 -1
  224. package/dist/store/store-fs.js +59 -25
  225. package/dist/store/store-fs.js.map +1 -1
  226. package/dist/store/store-links.d.ts +3 -0
  227. package/dist/store/store-links.d.ts.map +1 -0
  228. package/dist/store/store-links.js +39 -0
  229. package/dist/store/store-links.js.map +1 -0
  230. package/dist/writer/comparison-context.d.ts +4 -0
  231. package/dist/writer/comparison-context.d.ts.map +1 -0
  232. package/dist/writer/comparison-context.js +13 -0
  233. package/dist/writer/comparison-context.js.map +1 -0
  234. package/dist/writer/context.d.ts +3 -3
  235. package/dist/writer/context.d.ts.map +1 -1
  236. package/dist/writer/context.js +11 -6
  237. package/dist/writer/context.js.map +1 -1
  238. package/dist/writer/module.d.ts +13 -5
  239. package/dist/writer/module.d.ts.map +1 -1
  240. package/dist/writer/module.js +68 -11
  241. package/dist/writer/module.js.map +1 -1
  242. package/dist/xml.d.ts +7 -1
  243. package/dist/xml.d.ts.map +1 -1
  244. package/dist/xml.js +43 -1
  245. package/dist/xml.js.map +1 -1
  246. package/package.json +14 -3
  247. package/src/analysis/descriptor-render.ts +90 -45
  248. package/src/analysis/descriptor.ts +35 -8
  249. package/src/analysis/inheritance.ts +134 -44
  250. package/src/analysis/interface-conflicts.ts +237 -0
  251. package/src/analysis/param-capability.ts +3 -6
  252. package/src/analysis/param-structure.ts +2 -2
  253. package/src/analysis/ts-type.ts +13 -17
  254. package/src/analysis/type-key.ts +14 -0
  255. package/src/compile.ts +110 -26
  256. package/src/docs/api-reference.ts +10 -9
  257. package/src/docs/element-page.ts +5 -2
  258. package/src/docs/pipeline.ts +129 -19
  259. package/src/docs/render.ts +7 -3
  260. package/src/docs/symbol-page.ts +12 -7
  261. package/src/fingerprint.ts +86 -31
  262. package/src/gi.ts +1 -0
  263. package/src/gir/ancestry.ts +17 -1
  264. package/src/gir/annotations.ts +1 -1
  265. package/src/gir/cursor-overrides.ts +12 -0
  266. package/src/gir/emittable.ts +8 -0
  267. package/src/gir/function.ts +45 -9
  268. package/src/gir/library.ts +1 -1
  269. package/src/gir/namespace.ts +8 -2
  270. package/src/gir/parameter.ts +15 -0
  271. package/src/gir/parse.ts +5 -7
  272. package/src/guards.ts +23 -0
  273. package/src/internal.ts +2 -0
  274. package/src/json.ts +11 -0
  275. package/src/khronos/modules.ts +25 -9
  276. package/src/khronos/parse.ts +3 -4
  277. package/src/khronos/pipeline.ts +1 -1
  278. package/src/khronos/plan.ts +0 -1
  279. package/src/runner.ts +19 -1
  280. package/src/staging.ts +69 -0
  281. package/src/store/compile-store.ts +6 -4
  282. package/src/store/gi/callables.ts +41 -33
  283. package/src/store/gi/callback.ts +9 -9
  284. package/src/store/gi/class.ts +79 -48
  285. package/src/store/gi/companion.ts +7 -6
  286. package/src/store/gi/constant.ts +12 -2
  287. package/src/store/gi/constructor-props.ts +1 -1
  288. package/src/store/gi/enum.ts +35 -21
  289. package/src/store/gi/function.ts +30 -24
  290. package/src/store/gi/gtype-binding.ts +7 -2
  291. package/src/store/gi/interface.ts +37 -18
  292. package/src/store/gi/method.ts +28 -29
  293. package/src/store/gi/param-marshal.ts +77 -6
  294. package/src/store/gi/pipeline.ts +25 -15
  295. package/src/store/gi/properties.ts +8 -4
  296. package/src/store/gi/property-accessor.ts +156 -73
  297. package/src/store/gi/record-constructor.ts +50 -18
  298. package/src/store/gi/record-field-accessor.ts +8 -1
  299. package/src/store/gi/record-layout.ts +11 -1
  300. package/src/store/gi/record.ts +20 -12
  301. package/src/store/gi/registration.ts +2 -2
  302. package/src/store/gi/signal.ts +36 -38
  303. package/src/store/gi/value-marshalable.ts +3 -1
  304. package/src/store/gi/vtable.ts +97 -20
  305. package/src/store/gi-store.ts +26 -31
  306. package/src/store/jsx/generated-elements.ts +17 -8
  307. package/src/store/jsx/jsx.ts +3 -3
  308. package/src/store/jsx/metadata.ts +4 -1
  309. package/src/store/jsx-store.ts +3 -3
  310. package/src/store/resolve-store.ts +133 -18
  311. package/src/store/store-fs.ts +87 -34
  312. package/src/store/store-links.ts +49 -0
  313. package/src/writer/comparison-context.ts +18 -0
  314. package/src/writer/context.ts +12 -6
  315. package/src/writer/module.ts +101 -14
  316. package/src/xml.ts +61 -1
package/src/runner.ts CHANGED
@@ -2,12 +2,13 @@ import { mkdirSync, writeFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import type { ModuleExport } from "./react/element-config.js";
4
4
  import type { OmittedProps } from "./store/jsx/omitted-props.js";
5
- import type { StoreOptions } from "./store/store-fs.js";
6
5
  import { checkModules } from "./compile.js";
7
6
  import { isGiStoreFresh } from "./fingerprint.js";
8
7
  import { runGiCodegen } from "./gi.js";
9
8
  import { Library } from "./gir/library.js";
10
9
  import { generateGlModules, type GlGenerationReport } from "./khronos/pipeline.js";
10
+ import { sweepStagingDirs } from "./staging.js";
11
+ import { ensureStoreLink, type StoreOptions } from "./store/store-fs.js";
11
12
 
12
13
  type GlCodegenOptions = {
13
14
  registryPath: string;
@@ -64,6 +65,10 @@ type StoreResult = {
64
65
  * store or the React element config changed, unless `options.isForced` is set. Pass the spread of
65
66
  * `resolveStore(projectRoot)` for everything but `libraries` and `girPath`.
66
67
  *
68
+ * Every store already on disk is linked at its `linkDir` before anything is generated, so a link an install
69
+ * pruned out of `node_modules` is restored without regenerating the store, and the gi store is reachable
70
+ * under its own specifier while the jsx store is type checked.
71
+ *
67
72
  * @param options What to generate and where to write it.
68
73
  * @returns A summary of what was regenerated and how long the run took.
69
74
  * @throws If `girPath` is empty, which would otherwise generate nothing and report success.
@@ -167,6 +172,17 @@ const emitStoresWithConfig = async (config: {
167
172
  return emitJsxStore({ options, jsx, gi, loadLibrary, isGiRegenerated, namespaces });
168
173
  };
169
174
 
175
+ const prepareStores = (stores: (StoreOptions | undefined)[]): void => {
176
+ for (const store of stores) {
177
+ if (store === undefined) {
178
+ continue;
179
+ }
180
+
181
+ sweepStagingDirs(store.storeDir);
182
+ ensureStoreLink(store);
183
+ }
184
+ };
185
+
170
186
  const emitStores = async (options: CodegenRunnerOptions): Promise<StoreResult> => {
171
187
  const { gi, jsx, libraries, girPath } = options;
172
188
 
@@ -174,6 +190,8 @@ const emitStores = async (options: CodegenRunnerOptions): Promise<StoreResult> =
174
190
  throw new Error("codegen needs at least one GIR search path; pass the result of resolveGirPath");
175
191
  }
176
192
 
193
+ prepareStores([gi, jsx]);
194
+
177
195
  return emitStoresWithConfig({ options, gi, jsx, libraries, girPath });
178
196
  };
179
197
 
package/src/staging.ts ADDED
@@ -0,0 +1,69 @@
1
+ import { mkdirSync, mkdtempSync, readdirSync, rmSync } from "node:fs";
2
+ import { basename, dirname, join } from "node:path";
3
+
4
+ const STAGING_SUFFIX = ".tmp-";
5
+ const OWNER_PATTERN = /^(?<pid>\d+)-/;
6
+
7
+ const errorCode = (error: unknown): string | undefined =>
8
+ error instanceof Error && "code" in error && typeof error.code === "string" ? error.code : undefined;
9
+
10
+ const isOwnerRunning = (pid: number): boolean => {
11
+ if (!Number.isSafeInteger(pid) || pid <= 0) {
12
+ return false;
13
+ }
14
+
15
+ try {
16
+ process.kill(pid, 0);
17
+
18
+ return true;
19
+ } catch (error) {
20
+ return errorCode(error) === "EPERM";
21
+ }
22
+ };
23
+
24
+ const isStranded = (entry: string, prefix: string): boolean => {
25
+ if (!entry.startsWith(prefix)) {
26
+ return false;
27
+ }
28
+
29
+ const owner = OWNER_PATTERN.exec(entry.slice(prefix.length))?.groups?.pid;
30
+
31
+ return owner === undefined || !isOwnerRunning(Number(owner));
32
+ };
33
+
34
+ const readEntries = (parentDir: string): string[] => {
35
+ try {
36
+ return readdirSync(parentDir);
37
+ } catch {
38
+ return [];
39
+ }
40
+ };
41
+
42
+ const removeStrandedDir = (path: string): void => {
43
+ try {
44
+ rmSync(path, { recursive: true, force: true });
45
+ } catch {
46
+ return;
47
+ }
48
+ };
49
+
50
+ const sweepStrandedDirs = (parentDir: string, prefix: string): void => {
51
+ for (const entry of readEntries(parentDir)) {
52
+ if (isStranded(entry, prefix)) {
53
+ removeStrandedDir(join(parentDir, entry));
54
+ }
55
+ }
56
+ };
57
+
58
+ const sweepStagingDirs = (target: string): void => {
59
+ sweepStrandedDirs(dirname(target), `${basename(target)}${STAGING_SUFFIX}`);
60
+ };
61
+
62
+ const createStagingDir = (target: string): string => {
63
+ mkdirSync(dirname(target), { recursive: true });
64
+ sweepStagingDirs(target);
65
+
66
+ return mkdtempSync(`${target}${STAGING_SUFFIX}${String(process.pid)}-`);
67
+ };
68
+
69
+ export { createStagingDir, sweepStagingDirs, sweepStrandedDirs };
@@ -1,6 +1,6 @@
1
1
  import { rmSync, writeFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
- import { compileProject, type SourceModule } from "../compile.js";
3
+ import { compileProject, type ProjectFile, type SourceModule } from "../compile.js";
4
4
 
5
5
  type CompileStoreParams = {
6
6
  storeDir: string;
@@ -29,16 +29,18 @@ const writeEnvReference = (storeDir: string): (() => void) => {
29
29
  };
30
30
 
31
31
  const compileStore = (params: CompileStoreParams): void => {
32
- const fileNames = params.files.map((file) => file.fileName);
33
-
34
32
  const removeEnvReference = params.requiresEnvReference === true
35
33
  ? writeEnvReference(params.storeDir)
36
34
  : (): void => undefined;
37
35
 
36
+ const files: ProjectFile[] = params.requiresEnvReference === true
37
+ ? [{ fileName: ENV_REFERENCE_FILE }, ...params.files]
38
+ : params.files;
39
+
38
40
  try {
39
41
  compileProject({
40
42
  projectDir: params.storeDir,
41
- fileNames: params.requiresEnvReference === true ? [ENV_REFERENCE_FILE, ...fileNames] : fileNames,
43
+ files,
42
44
  compilerOptions: EMIT_OPTIONS,
43
45
  label: `the generated ${params.packageName} store`,
44
46
  });
@@ -1,4 +1,4 @@
1
- import { camelCase, toCamelIdentifier, uniqBy } from "@gtkx/utils";
1
+ import { toCamelIdentifier, uniqBy } from "@gtkx/utils";
2
2
  import type { GirFunction } from "../../gir/function.js";
3
3
  import type { ModuleContext } from "../../writer/context.js";
4
4
  import type { JsDocSpec } from "../../writer/doc.js";
@@ -10,6 +10,7 @@ import { renderFnExpression } from "./function.js";
10
10
  import { gtypeMemberDeclaration } from "./gtype-binding.js";
11
11
  import {
12
12
  finishCallExpression,
13
+ memberName,
13
14
  methodExportName,
14
15
  renderMethodBody,
15
16
  renderMethodReturnType,
@@ -49,6 +50,11 @@ type ResolvedInstanceMember = {
49
50
  finishFn: GirFunction | undefined;
50
51
  };
51
52
 
53
+ type StaticMember = {
54
+ callable: GirFunction;
55
+ name: string;
56
+ };
57
+
52
58
  type InstanceMemberRenderer = (
53
59
  context: ModuleContext,
54
60
  callable: GirFunction,
@@ -99,15 +105,14 @@ const dedupeCallables = (callables: GirFunction[]): GirFunction[] =>
99
105
  (callable) => callable.cIdentifier,
100
106
  );
101
107
 
108
+ const getEmittableCIdentifier = (context: ModuleContext, callable: GirFunction): string | undefined =>
109
+ isEmittableCallable(context, callable) ? callable.cIdentifier : undefined;
110
+
102
111
  const renderBinding = (
103
112
  context: ModuleContext,
104
113
  callable: GirFunction,
105
114
  ): { text: string; cIdentifier: string } | undefined => {
106
- if (!isEmittableCallable(context, callable)) {
107
- return undefined;
108
- }
109
-
110
- const cIdentifier = callable.cIdentifier;
115
+ const cIdentifier = getEmittableCIdentifier(context, callable);
111
116
 
112
117
  if (cIdentifier === undefined) {
113
118
  return undefined;
@@ -139,11 +144,7 @@ const resolveCallableMember = (
139
144
  callable: GirFunction,
140
145
  resolveName: (callable: GirFunction) => string | undefined,
141
146
  ): { cIdentifier: string; name: string } | undefined => {
142
- if (!isEmittableCallable(context, callable)) {
143
- return undefined;
144
- }
145
-
146
- const cIdentifier = callable.cIdentifier;
147
+ const cIdentifier = getEmittableCIdentifier(context, callable);
147
148
 
148
149
  if (cIdentifier === undefined) {
149
150
  return undefined;
@@ -151,7 +152,7 @@ const resolveCallableMember = (
151
152
 
152
153
  const name = resolveName(callable);
153
154
 
154
- if (name === undefined || name === "constructor") {
155
+ if (name === undefined || !isEmittableMemberName(name)) {
155
156
  return undefined;
156
157
  }
157
158
 
@@ -218,7 +219,7 @@ const renderStaticEntry = (
218
219
  if (finishFn !== undefined) {
219
220
  const name = options.resolveName(callable);
220
221
 
221
- if (name === undefined || name === "constructor") {
222
+ if (name === undefined || !isEmittableMemberName(name)) {
222
223
  return undefined;
223
224
  }
224
225
 
@@ -247,6 +248,8 @@ const renderInstanceMethod = (
247
248
  canUseRuntimeOverride: true,
248
249
  });
249
250
 
251
+ const isEmittableMemberName = (name: string): boolean => name !== "constructor" && name.length > 0;
252
+
250
253
  const resolveInstanceMember = (
251
254
  context: ModuleContext,
252
255
  callable: GirFunction,
@@ -259,7 +262,7 @@ const resolveInstanceMember = (
259
262
 
260
263
  const name = nameOverride ?? methodExportName(callable);
261
264
 
262
- if (name === "constructor") {
265
+ if (!isEmittableMemberName(name)) {
263
266
  return undefined;
264
267
  }
265
268
 
@@ -373,13 +376,9 @@ const isEmittableCallable = (context: ModuleContext, callable: GirFunction): boo
373
376
  !hasUnmarshalableParam(context, callable);
374
377
 
375
378
  const constructorMemberName = (girName: string): string | undefined => {
376
- const camel = camelCase(girName);
379
+ const camel = memberName(girName);
377
380
 
378
- if (camel === "constructor") {
379
- return undefined;
380
- }
381
-
382
- return camel;
381
+ return isEmittableMemberName(camel) ? camel : undefined;
383
382
  };
384
383
 
385
384
  const renderStaticSignature = (
@@ -409,24 +408,32 @@ const renderStaticSignature = (
409
408
  };
410
409
  };
411
410
 
412
- const classConstructorMemberNames = (context: ModuleContext, callables: Callables): string[] => {
413
- const names: string[] = [];
414
-
415
- for (const callable of callables.constructors) {
416
- if (!isEmittableCallable(context, callable)) {
417
- continue;
418
- }
411
+ const collectStaticMembers = (
412
+ context: ModuleContext,
413
+ group: GirFunction[],
414
+ resolveName: (girName: string) => string | undefined,
415
+ ): StaticMember[] => {
416
+ const members: StaticMember[] = [];
419
417
 
420
- const member = constructorMemberName(callable.name);
418
+ for (const callable of group) {
419
+ const name = isEmittableCallable(context, callable) ? resolveName(callable.name) : undefined;
421
420
 
422
- if (member !== undefined) {
423
- names.push(member);
421
+ if (name !== undefined) {
422
+ members.push({ callable, name });
424
423
  }
425
424
  }
426
425
 
427
- return names;
426
+ return members;
428
427
  };
429
428
 
429
+ const staticMembers = (context: ModuleContext, callables: Callables): StaticMember[] => [
430
+ ...collectStaticMembers(context, callables.constructors, constructorMemberName),
431
+ ...collectStaticMembers(context, callables.functions, memberName),
432
+ ];
433
+
434
+ const constructorMemberNames = (context: ModuleContext, constructors: GirFunction[]): string[] =>
435
+ collectStaticMembers(context, constructors, constructorMemberName).map((member) => member.name);
436
+
430
437
  const collectStaticEntries = (
431
438
  context: ModuleContext,
432
439
  group: GirFunction[],
@@ -456,7 +463,7 @@ const renderStaticHead = (context: ModuleContext, callables: Callables, ownerCla
456
463
  returnTypeOverride: ownerClassName,
457
464
  }),
458
465
  ...collectStaticEntries(context, callables.functions, siblings, {
459
- resolveName: (member) => camelCase(member.name),
466
+ resolveName: (member) => memberName(member.name),
460
467
  ownerName: ownerClassName,
461
468
  }),
462
469
  ];
@@ -509,9 +516,10 @@ export {
509
516
  indexMethodsByName,
510
517
  isEmittableCallable,
511
518
  renderStaticSignature,
512
- classConstructorMemberNames,
519
+ constructorMemberNames,
513
520
  renderStaticHead,
514
521
  renderPlainTypeMembers,
522
+ staticMembers,
515
523
  type Callables,
516
524
  type InstanceMemberRenderer,
517
525
  type InstanceScope,
@@ -1,25 +1,25 @@
1
+ import { sanitizeTypeIdentifier } from "@gtkx/utils";
1
2
  import type { ModuleContext } from "../../writer/context.js";
2
3
  import { callbackAsFunction, type GirCallback } from "../../gir/callback.js";
4
+ import { isEmittableEntity } from "../../gir/emittable.js";
3
5
  import { callableDoc } from "./callable-doc.js";
4
6
  import { renderMethodReturnType, renderMethodSignature } from "./method.js";
5
7
 
6
8
  const generateCallback = (context: ModuleContext, callback: GirCallback): void => {
7
- if (!callback.introspectable) {
8
- return;
9
- }
10
-
11
- if (callback.name.length === 0) {
9
+ if (!isEmittableEntity(callback)) {
12
10
  return;
13
11
  }
14
12
 
15
13
  const fn = callbackAsFunction(callback);
16
14
  const signature = renderMethodSignature(context, fn);
17
15
  const returnType = renderMethodReturnType(context, fn);
16
+ const name = sanitizeTypeIdentifier(callback.name);
18
17
 
19
- context.module.appendDeclaration(
20
- `${callableDoc(context, fn)}export type ${callback.name} = (${signature}) => ${returnType};`,
21
- context.declaredType(callback.name),
22
- );
18
+ context.declare({
19
+ name,
20
+ code: `${callableDoc(context, fn)}export type ${name} = (${signature}) => ${returnType};`,
21
+ owner: callback.name,
22
+ });
23
23
  };
24
24
 
25
25
  export { generateCallback };
@@ -1,20 +1,28 @@
1
- import { pascalCase, toCamelIdentifier } from "@gtkx/utils";
1
+ import { sanitizeTypeIdentifier, toCamelIdentifier } from "@gtkx/utils";
2
2
  import type { GirClass } from "../../gir/class.js";
3
3
  import type { GirFunction } from "../../gir/function.js";
4
4
  import type { ModuleContext } from "../../writer/context.js";
5
5
  import {
6
+ ancestorClassMethodNames,
6
7
  collectInheritedMethods,
7
8
  collectInheritedPropertyTypes,
8
9
  collectInterfaceMergeOmissions,
9
10
  conflictRename,
10
11
  type InheritedMethods,
11
12
  } from "../../analysis/inheritance.js";
12
- import { ancestorChain, type ResolvedAncestor } from "../../gir/ancestry.js";
13
- import { splitOptionalNamespace } from "../../gir/type-ref.js";
13
+ import {
14
+ type ClaimedMembers,
15
+ claimInterfaceMembers,
16
+ inheritedMembers,
17
+ interfaceConflicts,
18
+ omittedTypeRef,
19
+ } from "../../analysis/interface-conflicts.js";
20
+ import { ancestorChain, getParentRef, type ResolvedAncestor } from "../../gir/ancestry.js";
21
+ import { isEmittableEntity } from "../../gir/emittable.js";
14
22
  import { indentMembers } from "../../writer/emit.js";
15
23
  import {
16
24
  type Callables,
17
- classConstructorMemberNames,
25
+ constructorMemberNames,
18
26
  dedupeCallables,
19
27
  generateBindings,
20
28
  type InstanceScope,
@@ -37,6 +45,7 @@ type ImplementedRef = {
37
45
  makerRef: string;
38
46
  interfaceKlass: GirClass;
39
47
  interfaceNamespace: string;
48
+ conflicts: string[];
40
49
  };
41
50
 
42
51
  type MemberDeclarationsOptions = {
@@ -49,6 +58,14 @@ type MemberDeclarationsOptions = {
49
58
 
50
59
  type ClassMembers = { members: string[]; accessors: ResolvedAccessor[] };
51
60
 
61
+ type ImplementedRefOptions = {
62
+ context: ModuleContext;
63
+ klass: GirClass;
64
+ name: string;
65
+ inherited: Set<string>;
66
+ claimed: ClaimedMembers;
67
+ };
68
+
52
69
  type AppendInstanceMethodsOptions = {
53
70
  context: ModuleContext;
54
71
  methods: GirFunction[];
@@ -60,15 +77,11 @@ type AppendInstanceMethodsOptions = {
60
77
  };
61
78
 
62
79
  const generateClass = (context: ModuleContext, klass: GirClass): void => {
63
- if (!klass.introspectable) {
64
- return;
65
- }
66
-
67
- if (klass.name.length === 0) {
80
+ if (!isEmittableEntity(klass)) {
68
81
  return;
69
82
  }
70
83
 
71
- const className = pascalCase(klass.name);
84
+ const className = sanitizeTypeIdentifier(klass.name);
72
85
 
73
86
  const callables: Callables = {
74
87
  constructors: dedupeCallables(klass.constructors),
@@ -80,18 +93,24 @@ const generateClass = (context: ModuleContext, klass: GirClass): void => {
80
93
  const parentExpression = resolveParent(context, klass);
81
94
  const extendsClause = renderExtendsClause(context, parentExpression, callables);
82
95
  const implemented = resolveImplementedRefs(context, klass);
83
- const typeRefs = implemented.map((ref) => ref.typeRef);
96
+ const typeRefs = implemented.map((ref) => omittedTypeRef(ref.typeRef, ref.conflicts));
84
97
  const implementsClause = typeRefs.length === 0 ? "" : ` implements ${typeRefs.join(", ")}`;
85
98
  const { members, accessors } = renderClassMembers(context, klass, callables, parentExpression !== undefined);
86
99
  const body = indentMembers(members);
87
100
  const doc = getDoc(klass);
101
+ const modifier = klass.isAbstract ? "abstract " : "";
102
+
103
+ context.declare({
104
+ name: className,
105
+ code: `${doc}export ${modifier}class ${className}${extendsClause}${implementsClause} {\n${body}\n}`,
106
+ owner: klass.name,
107
+ });
88
108
 
89
- context.module.appendDeclaration(
90
- `${doc}export class ${className}${extendsClause}${implementsClause} {\n${body}\n}`,
91
- context.declaredType(className),
92
- );
109
+ context.declare({
110
+ name: `${className}ConstructorProps`,
111
+ code: renderConstructorPropsInterface(context, klass, className),
112
+ });
93
113
 
94
- context.module.appendDeclaration(renderConstructorPropsInterface(context, klass, className));
95
114
  appendMemberDeclarations({ context, klass, className, accessors, implemented });
96
115
  appendInstallMixins(context, className, implemented);
97
116
  appendClassRegistrations(context, klass, className);
@@ -101,11 +120,11 @@ const appendMemberDeclarations = (options: MemberDeclarationsOptions): void => {
101
120
  const { context, klass, className, accessors, implemented } = options;
102
121
 
103
122
  for (const declaration of renderPropertyDeclarations(context, klass, className, accessors)) {
104
- context.module.appendDeclaration(declaration);
123
+ context.declare(declaration);
105
124
  }
106
125
 
107
126
  for (const declaration of renderSignalDeclarations(context, klass, className, false)) {
108
- context.module.appendDeclaration(declaration);
127
+ context.declare(declaration);
109
128
  }
110
129
 
111
130
  appendInterfaceMerge(context, klass, className, implemented);
@@ -122,7 +141,11 @@ const appendInterfaceMerge = (
122
141
  }
123
142
 
124
143
  const mergeRefs = implemented.map((ref) => interfaceMergeRef(context, klass, ref));
125
- context.module.appendDeclaration(`export interface ${className} extends ${mergeRefs.join(", ")} {}`);
144
+
145
+ context.declare({
146
+ name: className,
147
+ code: `export interface ${className} extends ${mergeRefs.join(", ")} {}`,
148
+ });
126
149
  };
127
150
 
128
151
  const renderClassMembers = (
@@ -131,7 +154,7 @@ const renderClassMembers = (
131
154
  callables: Callables,
132
155
  hasParent: boolean,
133
156
  ): ClassMembers => {
134
- const className = pascalCase(klass.name);
157
+ const className = sanitizeTypeIdentifier(klass.name);
135
158
  const members: string[] = [gtypeMemberDeclaration(context)];
136
159
  const constructorBlock = renderClassConstructor(context, klass, className, hasParent);
137
160
 
@@ -156,17 +179,19 @@ const renderClassMembers = (
156
179
 
157
180
  members.push(...renderVfuncMembers({ context, klass, mode: "implementation" }));
158
181
  const inheritedPropertyTypes = collectInheritedPropertyTypes(context, klass);
182
+ const inheritedNames = ancestorClassMethodNames(context, klass);
159
183
  const accessors: ResolvedAccessor[] = [];
160
184
 
161
185
  for (const property of klass.properties) {
162
- const inheritedType = inheritedPropertyTypes.get(toCamelIdentifier(property.name));
186
+ const inheritedTypes = inheritedPropertyTypes.get(toCamelIdentifier(property.name));
163
187
 
164
188
  const accessor = resolveAccessor({
165
189
  context,
166
190
  property,
167
191
  claimedNames,
168
192
  methodByName: scope.methodByName,
169
- inheritedType,
193
+ inheritedTypes,
194
+ inheritedNames,
170
195
  });
171
196
 
172
197
  if (accessor === undefined) {
@@ -204,8 +229,13 @@ const appendInstallMixins = (context: ModuleContext, className: string, implemen
204
229
  }
205
230
 
206
231
  context.addRuntimeImport("installMixins");
207
- const makers = implemented.map((ref) => ref.makerRef).join(", ");
208
- context.module.appendRegistration(`installMixins(${className}, [${makers}]);`);
232
+ const makerRefs = implemented.map((ref) => ref.makerRef);
233
+ const localRefs = makerRefs.filter((ref) => !ref.includes("."));
234
+
235
+ context.module.appendRegistration(`installMixins(${className}, [${makerRefs.join(", ")}]);`, [
236
+ className,
237
+ ...localRefs,
238
+ ]);
209
239
  };
210
240
 
211
241
  const appendClassRegistrations = (context: ModuleContext, klass: GirClass, className: string): void => {
@@ -254,23 +284,14 @@ const interfaceMergeRef = (context: ModuleContext, klass: GirClass, ref: Impleme
254
284
  namespaceName: ref.interfaceNamespace,
255
285
  });
256
286
 
257
- if (omissions.length === 0) {
258
- return ref.typeRef;
259
- }
260
-
261
- const keys = omissions.map((name) => JSON.stringify(name)).join(" | ");
262
-
263
- return `Omit<${ref.typeRef}, ${keys}>`;
287
+ return omittedTypeRef(ref.typeRef, [...omissions, ...ref.conflicts]);
264
288
  };
265
289
 
266
- const implementedRefFor = (
267
- context: ModuleContext,
268
- name: string,
269
- inherited: Set<string>,
270
- ): ImplementedRef | undefined => {
290
+ const implementedRefFor = (options: ImplementedRefOptions): ImplementedRef | undefined => {
291
+ const { context, klass, name, inherited } = options;
271
292
  const resolved = context.library.resolveType(context.namespace.name, name);
272
293
 
273
- if (resolved?.kind !== "interface") {
294
+ if (resolved?.kind !== "interface" || !isEmittableEntity(resolved.value)) {
274
295
  return undefined;
275
296
  }
276
297
 
@@ -278,22 +299,34 @@ const implementedRefFor = (
278
299
  return undefined;
279
300
  }
280
301
 
281
- const pascal = pascalCase(resolved.value.name);
302
+ const typeName = sanitizeTypeIdentifier(resolved.value.name);
303
+
304
+ const conflictOptions = {
305
+ context,
306
+ klass,
307
+ iface: resolved.value,
308
+ ifaceNamespace: resolved.namespace.name,
309
+ };
310
+
311
+ const conflicts = interfaceConflicts(conflictOptions, options.claimed);
312
+ claimInterfaceMembers(conflictOptions, options.claimed);
282
313
 
283
314
  return {
284
- typeRef: context.qualify(resolved.namespace.name, pascal),
285
- makerRef: context.qualify(resolved.namespace.name, `make${pascal}`),
315
+ typeRef: context.qualify(resolved.namespace.name, typeName),
316
+ makerRef: context.qualify(resolved.namespace.name, `make${typeName}`),
286
317
  interfaceKlass: resolved.value,
287
318
  interfaceNamespace: resolved.namespace.name,
319
+ conflicts,
288
320
  };
289
321
  };
290
322
 
291
323
  const resolveImplementedRefs = (context: ModuleContext, klass: GirClass): ImplementedRef[] => {
292
324
  const inherited = inheritedInterfaceKeys(context, klass);
325
+ const claimed = inheritedMembers(context, klass);
293
326
  const refs: ImplementedRef[] = [];
294
327
 
295
328
  for (const name of klass.implements) {
296
- const ref = implementedRefFor(context, name, inherited);
329
+ const ref = implementedRefFor({ context, klass, name, inherited, claimed });
297
330
 
298
331
  if (ref !== undefined) {
299
332
  refs.push(ref);
@@ -312,7 +345,7 @@ const renderExtendsClause = (
312
345
  return "";
313
346
  }
314
347
 
315
- const constructorNames = classConstructorMemberNames(context, callables);
348
+ const constructorNames = constructorMemberNames(context, callables.constructors);
316
349
 
317
350
  if (constructorNames.length === 0) {
318
351
  return ` extends ${parentExpression}`;
@@ -325,13 +358,11 @@ const renderExtendsClause = (
325
358
  };
326
359
 
327
360
  const resolveParent = (context: ModuleContext, klass: GirClass): string | undefined => {
328
- if (klass.parent === undefined) {
329
- return undefined;
330
- }
331
-
332
- const [namespace, typeName] = splitOptionalNamespace(klass.parent);
361
+ const parent = getParentRef(klass);
333
362
 
334
- return context.qualify(namespace ?? context.namespace.name, pascalCase(typeName));
363
+ return parent === undefined
364
+ ? undefined
365
+ : context.qualify(parent.namespaceName ?? context.namespace.name, sanitizeTypeIdentifier(parent.typeName));
335
366
  };
336
367
 
337
368
  export { generateClass };
@@ -1,16 +1,17 @@
1
- import { pascalCase } from "@gtkx/utils";
1
+ import { sanitizeTypeIdentifier } from "@gtkx/utils";
2
2
  import type { GirClass } from "../../gir/class.js";
3
3
  import type { ModuleContext } from "../../writer/context.js";
4
- import { splitOptionalNamespace } from "../../gir/type-ref.js";
4
+ import { getParentRef } from "../../gir/ancestry.js";
5
5
 
6
6
  const parentCompanionRef = (context: ModuleContext, klass: GirClass, suffix: string): string | undefined => {
7
- if (klass.parent === undefined) {
7
+ const parent = getParentRef(klass);
8
+
9
+ if (parent === undefined) {
8
10
  return undefined;
9
11
  }
10
12
 
11
- const [parentNamespace, typeName] = splitOptionalNamespace(klass.parent);
12
- const namespaceName = parentNamespace ?? context.namespace.name;
13
- const name = `${pascalCase(typeName)}${suffix}`;
13
+ const namespaceName = parent.namespaceName ?? context.namespace.name;
14
+ const name = `${sanitizeTypeIdentifier(parent.typeName)}${suffix}`;
14
15
 
15
16
  if (namespaceName === context.namespace.name) {
16
17
  return name;
@@ -1,16 +1,26 @@
1
- import { sourceStringLiteral } from "@gtkx/utils";
1
+ import { sanitizeIdentifier, sourceStringLiteral } from "@gtkx/utils";
2
2
  import type { GirConstant } from "../../gir/namespace.js";
3
3
  import type { PrimitiveCategory } from "../../gir/primitives.js";
4
4
  import type { TypeId } from "../../gir/type-id.js";
5
5
  import type { ModuleContext } from "../../writer/context.js";
6
+ import { isEmittableEntity } from "../../gir/emittable.js";
6
7
  import { getDoc } from "./doc-spec.js";
7
8
 
8
9
  const TRUE_VALUES: Set<string> = new Set(["true", "1"]);
9
10
  const BIGINT_CATEGORIES: Set<PrimitiveCategory> = new Set(["bigint64", "biguint64", "gtype"]);
10
11
 
11
12
  const generateConstant = (context: ModuleContext, constant: GirConstant): void => {
13
+ if (!isEmittableEntity(constant)) {
14
+ return;
15
+ }
16
+
12
17
  const doc = getDoc(constant);
13
- context.module.appendDeclaration(`${doc}export const ${constant.name} = ${constantLiteral(context, constant)};`);
18
+ const name = sanitizeIdentifier(constant.name);
19
+
20
+ context.declare({
21
+ name,
22
+ code: `${doc}export const ${name} = ${constantLiteral(context, constant)};`,
23
+ });
14
24
  };
15
25
 
16
26
  const constantLiteral = (context: ModuleContext, constant: GirConstant): string => {