@gtkx/codegen 1.0.0 → 1.2.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 (347) 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 +59 -38
  5. package/dist/analysis/descriptor-render.js.map +1 -1
  6. package/dist/analysis/descriptor.d.ts +25 -10
  7. package/dist/analysis/descriptor.d.ts.map +1 -1
  8. package/dist/analysis/descriptor.js +37 -9
  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 +25 -0
  15. package/dist/analysis/interface-conflicts.d.ts.map +1 -0
  16. package/dist/analysis/interface-conflicts.js +139 -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 +3 -2
  24. package/dist/analysis/ts-type.d.ts.map +1 -1
  25. package/dist/analysis/ts-type.js +26 -26
  26. package/dist/analysis/ts-type.js.map +1 -1
  27. package/dist/analysis/type-key.d.ts +5 -0
  28. package/dist/analysis/type-key.d.ts.map +1 -0
  29. package/dist/analysis/type-key.js +9 -0
  30. package/dist/analysis/type-key.js.map +1 -0
  31. package/dist/analysis/type-shape.d.ts +3 -2
  32. package/dist/analysis/type-shape.d.ts.map +1 -1
  33. package/dist/analysis/type-shape.js +2 -1
  34. package/dist/analysis/type-shape.js.map +1 -1
  35. package/dist/compile.d.ts +14 -6
  36. package/dist/compile.d.ts.map +1 -1
  37. package/dist/compile.js +125 -24
  38. package/dist/compile.js.map +1 -1
  39. package/dist/docs/api-reference.d.ts +2 -0
  40. package/dist/docs/api-reference.d.ts.map +1 -1
  41. package/dist/docs/api-reference.js +11 -10
  42. package/dist/docs/api-reference.js.map +1 -1
  43. package/dist/docs/element-page.d.ts.map +1 -1
  44. package/dist/docs/element-page.js +5 -3
  45. package/dist/docs/element-page.js.map +1 -1
  46. package/dist/docs/pipeline.d.ts +1 -0
  47. package/dist/docs/pipeline.d.ts.map +1 -1
  48. package/dist/docs/pipeline.js +93 -19
  49. package/dist/docs/pipeline.js.map +1 -1
  50. package/dist/docs/render.d.ts +2 -1
  51. package/dist/docs/render.d.ts.map +1 -1
  52. package/dist/docs/render.js +5 -4
  53. package/dist/docs/render.js.map +1 -1
  54. package/dist/docs/symbol-page.d.ts.map +1 -1
  55. package/dist/docs/symbol-page.js +10 -9
  56. package/dist/docs/symbol-page.js.map +1 -1
  57. package/dist/fingerprint.d.ts +20 -3
  58. package/dist/fingerprint.d.ts.map +1 -1
  59. package/dist/fingerprint.js +56 -37
  60. package/dist/fingerprint.js.map +1 -1
  61. package/dist/gi.d.ts +1 -0
  62. package/dist/gi.d.ts.map +1 -1
  63. package/dist/gi.js +8 -2
  64. package/dist/gi.js.map +1 -1
  65. package/dist/gir/ancestry.d.ts +7 -1
  66. package/dist/gir/ancestry.d.ts.map +1 -1
  67. package/dist/gir/ancestry.js +9 -1
  68. package/dist/gir/ancestry.js.map +1 -1
  69. package/dist/gir/annotations.d.ts +1 -2
  70. package/dist/gir/annotations.d.ts.map +1 -1
  71. package/dist/gir/annotations.js +1 -1
  72. package/dist/gir/annotations.js.map +1 -1
  73. package/dist/gir/cursor-overrides.d.ts +8 -0
  74. package/dist/gir/cursor-overrides.d.ts.map +1 -0
  75. package/dist/gir/cursor-overrides.js +6 -0
  76. package/dist/gir/cursor-overrides.js.map +1 -0
  77. package/dist/gir/emittable.d.ts +7 -0
  78. package/dist/gir/emittable.d.ts.map +1 -0
  79. package/dist/gir/emittable.js +3 -0
  80. package/dist/gir/emittable.js.map +1 -0
  81. package/dist/gir/function.d.ts.map +1 -1
  82. package/dist/gir/function.js +28 -2
  83. package/dist/gir/function.js.map +1 -1
  84. package/dist/gir/gir-path.d.ts +1 -1
  85. package/dist/gir/gir-path.js +1 -1
  86. package/dist/gir/gir-path.js.map +1 -1
  87. package/dist/gir/library.d.ts +5 -1
  88. package/dist/gir/library.d.ts.map +1 -1
  89. package/dist/gir/library.js +9 -2
  90. package/dist/gir/library.js.map +1 -1
  91. package/dist/gir/namespace.d.ts +5 -1
  92. package/dist/gir/namespace.d.ts.map +1 -1
  93. package/dist/gir/namespace.js +4 -2
  94. package/dist/gir/namespace.js.map +1 -1
  95. package/dist/gir/parameter.d.ts +13 -1
  96. package/dist/gir/parameter.d.ts.map +1 -1
  97. package/dist/gir/parameter.js +1 -0
  98. package/dist/gir/parameter.js.map +1 -1
  99. package/dist/gir/parse.d.ts.map +1 -1
  100. package/dist/gir/parse.js +6 -6
  101. package/dist/gir/parse.js.map +1 -1
  102. package/dist/gir/primitives.js +1 -1
  103. package/dist/gir/primitives.js.map +1 -1
  104. package/dist/guards.d.ts +16 -0
  105. package/dist/guards.d.ts.map +1 -0
  106. package/dist/guards.js +11 -0
  107. package/dist/guards.js.map +1 -0
  108. package/dist/internal.d.ts +2 -0
  109. package/dist/internal.d.ts.map +1 -1
  110. package/dist/internal.js +2 -0
  111. package/dist/internal.js.map +1 -1
  112. package/dist/json.d.ts +3 -0
  113. package/dist/json.d.ts.map +1 -0
  114. package/dist/json.js +11 -0
  115. package/dist/json.js.map +1 -0
  116. package/dist/khronos/args.d.ts.map +1 -1
  117. package/dist/khronos/args.js +8 -6
  118. package/dist/khronos/args.js.map +1 -1
  119. package/dist/khronos/modules.d.ts.map +1 -1
  120. package/dist/khronos/modules.js +22 -7
  121. package/dist/khronos/modules.js.map +1 -1
  122. package/dist/khronos/parse.d.ts.map +1 -1
  123. package/dist/khronos/parse.js +3 -4
  124. package/dist/khronos/parse.js.map +1 -1
  125. package/dist/khronos/pipeline.d.ts +1 -1
  126. package/dist/khronos/pipeline.d.ts.map +1 -1
  127. package/dist/khronos/pipeline.js.map +1 -1
  128. package/dist/khronos/plan.d.ts +1 -7
  129. package/dist/khronos/plan.d.ts.map +1 -1
  130. package/dist/khronos/plan.js +1 -1
  131. package/dist/khronos/plan.js.map +1 -1
  132. package/dist/khronos/render.d.ts.map +1 -1
  133. package/dist/khronos/render.js +8 -4
  134. package/dist/khronos/render.js.map +1 -1
  135. package/dist/runner.d.ts +7 -1
  136. package/dist/runner.d.ts.map +1 -1
  137. package/dist/runner.js +21 -3
  138. package/dist/runner.js.map +1 -1
  139. package/dist/staging.d.ts +5 -0
  140. package/dist/staging.d.ts.map +1 -0
  141. package/dist/staging.js +57 -0
  142. package/dist/staging.js.map +1 -0
  143. package/dist/store/compile-store.d.ts +0 -1
  144. package/dist/store/compile-store.d.ts.map +1 -1
  145. package/dist/store/compile-store.js +7 -32
  146. package/dist/store/compile-store.js.map +1 -1
  147. package/dist/store/gi/callables.d.ts +6 -3
  148. package/dist/store/gi/callables.d.ts.map +1 -1
  149. package/dist/store/gi/callables.js +40 -30
  150. package/dist/store/gi/callables.js.map +1 -1
  151. package/dist/store/gi/callback.d.ts.map +1 -1
  152. package/dist/store/gi/callback.js +9 -5
  153. package/dist/store/gi/callback.js.map +1 -1
  154. package/dist/store/gi/class.d.ts.map +1 -1
  155. package/dist/store/gi/class.js +104 -44
  156. package/dist/store/gi/class.js.map +1 -1
  157. package/dist/store/gi/companion.d.ts.map +1 -1
  158. package/dist/store/gi/companion.js +6 -6
  159. package/dist/store/gi/companion.js.map +1 -1
  160. package/dist/store/gi/constant.d.ts.map +1 -1
  161. package/dist/store/gi/constant.js +11 -3
  162. package/dist/store/gi/constant.js.map +1 -1
  163. package/dist/store/gi/constructor-props.js +1 -1
  164. package/dist/store/gi/constructor-props.js.map +1 -1
  165. package/dist/store/gi/enum.d.ts.map +1 -1
  166. package/dist/store/gi/enum.js +29 -12
  167. package/dist/store/gi/enum.js.map +1 -1
  168. package/dist/store/gi/function.d.ts +1 -3
  169. package/dist/store/gi/function.d.ts.map +1 -1
  170. package/dist/store/gi/function.js +24 -18
  171. package/dist/store/gi/function.js.map +1 -1
  172. package/dist/store/gi/gtype-binding.d.ts.map +1 -1
  173. package/dist/store/gi/gtype-binding.js +4 -1
  174. package/dist/store/gi/gtype-binding.js.map +1 -1
  175. package/dist/store/gi/interface.d.ts.map +1 -1
  176. package/dist/store/gi/interface.js +34 -19
  177. package/dist/store/gi/interface.js.map +1 -1
  178. package/dist/store/gi/method.d.ts +7 -6
  179. package/dist/store/gi/method.d.ts.map +1 -1
  180. package/dist/store/gi/method.js +13 -24
  181. package/dist/store/gi/method.js.map +1 -1
  182. package/dist/store/gi/param-marshal.d.ts +3 -2
  183. package/dist/store/gi/param-marshal.d.ts.map +1 -1
  184. package/dist/store/gi/param-marshal.js +50 -5
  185. package/dist/store/gi/param-marshal.js.map +1 -1
  186. package/dist/store/gi/pipeline.d.ts.map +1 -1
  187. package/dist/store/gi/pipeline.js +21 -10
  188. package/dist/store/gi/pipeline.js.map +1 -1
  189. package/dist/store/gi/properties.d.ts +2 -1
  190. package/dist/store/gi/properties.d.ts.map +1 -1
  191. package/dist/store/gi/properties.js +6 -3
  192. package/dist/store/gi/properties.js.map +1 -1
  193. package/dist/store/gi/property-accessor.d.ts +10 -8
  194. package/dist/store/gi/property-accessor.d.ts.map +1 -1
  195. package/dist/store/gi/property-accessor.js +49 -91
  196. package/dist/store/gi/property-accessor.js.map +1 -1
  197. package/dist/store/gi/record-constructor.d.ts +8 -1
  198. package/dist/store/gi/record-constructor.d.ts.map +1 -1
  199. package/dist/store/gi/record-constructor.js +34 -13
  200. package/dist/store/gi/record-constructor.js.map +1 -1
  201. package/dist/store/gi/record-field-accessor.d.ts.map +1 -1
  202. package/dist/store/gi/record-field-accessor.js +20 -4
  203. package/dist/store/gi/record-field-accessor.js.map +1 -1
  204. package/dist/store/gi/record-layout.d.ts +6 -1
  205. package/dist/store/gi/record-layout.d.ts.map +1 -1
  206. package/dist/store/gi/record-layout.js +8 -1
  207. package/dist/store/gi/record-layout.js.map +1 -1
  208. package/dist/store/gi/record.d.ts.map +1 -1
  209. package/dist/store/gi/record.js +19 -8
  210. package/dist/store/gi/record.js.map +1 -1
  211. package/dist/store/gi/registration.js +2 -2
  212. package/dist/store/gi/registration.js.map +1 -1
  213. package/dist/store/gi/return-wrap.js +1 -1
  214. package/dist/store/gi/return-wrap.js.map +1 -1
  215. package/dist/store/gi/signal.d.ts +2 -1
  216. package/dist/store/gi/signal.d.ts.map +1 -1
  217. package/dist/store/gi/signal.js +55 -28
  218. package/dist/store/gi/signal.js.map +1 -1
  219. package/dist/store/gi/value-marshalable.d.ts.map +1 -1
  220. package/dist/store/gi/value-marshalable.js +2 -1
  221. package/dist/store/gi/value-marshalable.js.map +1 -1
  222. package/dist/store/gi/vtable.d.ts +4 -1
  223. package/dist/store/gi/vtable.d.ts.map +1 -1
  224. package/dist/store/gi/vtable.js +60 -17
  225. package/dist/store/gi/vtable.js.map +1 -1
  226. package/dist/store/gi-store.d.ts +1 -0
  227. package/dist/store/gi-store.d.ts.map +1 -1
  228. package/dist/store/gi-store.js +15 -20
  229. package/dist/store/gi-store.js.map +1 -1
  230. package/dist/store/jsx/generated-elements.d.ts +2 -1
  231. package/dist/store/jsx/generated-elements.d.ts.map +1 -1
  232. package/dist/store/jsx/generated-elements.js +13 -7
  233. package/dist/store/jsx/generated-elements.js.map +1 -1
  234. package/dist/store/jsx/jsx.js +3 -3
  235. package/dist/store/jsx/jsx.js.map +1 -1
  236. package/dist/store/jsx/metadata.d.ts.map +1 -1
  237. package/dist/store/jsx/metadata.js +3 -1
  238. package/dist/store/jsx/metadata.js.map +1 -1
  239. package/dist/store/jsx-store.d.ts.map +1 -1
  240. package/dist/store/jsx-store.js +3 -4
  241. package/dist/store/jsx-store.js.map +1 -1
  242. package/dist/store/resolve-store.d.ts +14 -3
  243. package/dist/store/resolve-store.d.ts.map +1 -1
  244. package/dist/store/resolve-store.js +98 -15
  245. package/dist/store/resolve-store.js.map +1 -1
  246. package/dist/store/store-fs.d.ts +9 -7
  247. package/dist/store/store-fs.d.ts.map +1 -1
  248. package/dist/store/store-fs.js +54 -25
  249. package/dist/store/store-fs.js.map +1 -1
  250. package/dist/store/store-links.d.ts +3 -0
  251. package/dist/store/store-links.d.ts.map +1 -0
  252. package/dist/store/store-links.js +39 -0
  253. package/dist/store/store-links.js.map +1 -0
  254. package/dist/writer/comparison-context.d.ts +4 -0
  255. package/dist/writer/comparison-context.d.ts.map +1 -0
  256. package/dist/writer/comparison-context.js +13 -0
  257. package/dist/writer/comparison-context.js.map +1 -0
  258. package/dist/writer/context.d.ts +3 -3
  259. package/dist/writer/context.d.ts.map +1 -1
  260. package/dist/writer/context.js +11 -6
  261. package/dist/writer/context.js.map +1 -1
  262. package/dist/writer/module.d.ts +13 -5
  263. package/dist/writer/module.d.ts.map +1 -1
  264. package/dist/writer/module.js +68 -11
  265. package/dist/writer/module.js.map +1 -1
  266. package/dist/xml.d.ts +8 -1
  267. package/dist/xml.d.ts.map +1 -1
  268. package/dist/xml.js +70 -1
  269. package/dist/xml.js.map +1 -1
  270. package/overrides/gobject/object.ts.ejs +2 -0
  271. package/package.json +14 -3
  272. package/src/analysis/descriptor-render.ts +106 -52
  273. package/src/analysis/descriptor.ts +76 -15
  274. package/src/analysis/inheritance.ts +134 -44
  275. package/src/analysis/interface-conflicts.ts +235 -0
  276. package/src/analysis/param-capability.ts +3 -6
  277. package/src/analysis/param-structure.ts +2 -2
  278. package/src/analysis/ts-type.ts +43 -28
  279. package/src/analysis/type-key.ts +14 -0
  280. package/src/analysis/type-shape.ts +5 -2
  281. package/src/compile.ts +192 -27
  282. package/src/docs/api-reference.ts +13 -10
  283. package/src/docs/element-page.ts +5 -2
  284. package/src/docs/pipeline.ts +140 -24
  285. package/src/docs/render.ts +7 -3
  286. package/src/docs/symbol-page.ts +12 -11
  287. package/src/fingerprint.ts +95 -47
  288. package/src/gi.ts +10 -2
  289. package/src/gir/ancestry.ts +17 -1
  290. package/src/gir/annotations.ts +1 -1
  291. package/src/gir/cursor-overrides.ts +12 -0
  292. package/src/gir/emittable.ts +8 -0
  293. package/src/gir/function.ts +45 -9
  294. package/src/gir/gir-path.ts +1 -1
  295. package/src/gir/library.ts +10 -2
  296. package/src/gir/namespace.ts +8 -2
  297. package/src/gir/parameter.ts +15 -0
  298. package/src/gir/parse.ts +10 -7
  299. package/src/gir/primitives.ts +1 -1
  300. package/src/guards.ts +23 -0
  301. package/src/internal.ts +2 -0
  302. package/src/json.ts +11 -0
  303. package/src/khronos/args.ts +9 -6
  304. package/src/khronos/modules.ts +25 -9
  305. package/src/khronos/parse.ts +3 -4
  306. package/src/khronos/pipeline.ts +1 -1
  307. package/src/khronos/plan.ts +0 -1
  308. package/src/khronos/render.ts +8 -6
  309. package/src/runner.ts +26 -4
  310. package/src/staging.ts +67 -0
  311. package/src/store/compile-store.ts +7 -38
  312. package/src/store/gi/callables.ts +60 -33
  313. package/src/store/gi/callback.ts +9 -9
  314. package/src/store/gi/class.ts +140 -53
  315. package/src/store/gi/companion.ts +7 -6
  316. package/src/store/gi/constant.ts +13 -3
  317. package/src/store/gi/constructor-props.ts +1 -1
  318. package/src/store/gi/enum.ts +36 -26
  319. package/src/store/gi/function.ts +30 -24
  320. package/src/store/gi/gtype-binding.ts +7 -2
  321. package/src/store/gi/interface.ts +39 -20
  322. package/src/store/gi/method.ts +26 -32
  323. package/src/store/gi/param-marshal.ts +77 -6
  324. package/src/store/gi/pipeline.ts +25 -15
  325. package/src/store/gi/properties.ts +8 -4
  326. package/src/store/gi/property-accessor.ts +73 -161
  327. package/src/store/gi/record-constructor.ts +53 -21
  328. package/src/store/gi/record-field-accessor.ts +26 -4
  329. package/src/store/gi/record-layout.ts +11 -1
  330. package/src/store/gi/record.ts +20 -12
  331. package/src/store/gi/registration.ts +2 -2
  332. package/src/store/gi/return-wrap.ts +1 -1
  333. package/src/store/gi/signal.ts +66 -42
  334. package/src/store/gi/value-marshalable.ts +3 -1
  335. package/src/store/gi/vtable.ts +97 -20
  336. package/src/store/gi-store.ts +26 -31
  337. package/src/store/jsx/generated-elements.ts +17 -8
  338. package/src/store/jsx/jsx.ts +3 -3
  339. package/src/store/jsx/metadata.ts +4 -1
  340. package/src/store/jsx-store.ts +3 -4
  341. package/src/store/resolve-store.ts +133 -18
  342. package/src/store/store-fs.ts +82 -35
  343. package/src/store/store-links.ts +49 -0
  344. package/src/writer/comparison-context.ts +18 -0
  345. package/src/writer/context.ts +12 -6
  346. package/src/writer/module.ts +101 -14
  347. package/src/xml.ts +103 -1
@@ -1,6 +1,8 @@
1
+ import { sanitizeTypeIdentifier } from "@gtkx/utils";
1
2
  import type { Library } from "../gir/library.js";
2
3
  import type { EntityType, GirType } from "../gir/type.js";
3
4
  import type { ModuleContext } from "../writer/context.js";
5
+ import { isEmittableEntity } from "../gir/emittable.js";
4
6
  import { PRIMITIVE_TS_TYPE } from "../gir/primitives.js";
5
7
  import {
6
8
  type CArrayType,
@@ -10,6 +12,7 @@ import {
10
12
  type TypeId,
11
13
  } from "../gir/type-id.js";
12
14
  import { gtypeTsType } from "../store/gi/gtype-binding.js";
15
+ import { isByteSequence } from "./type-shape.js";
13
16
 
14
17
  type ReferenceName = {
15
18
  namespaceName: string;
@@ -19,26 +22,23 @@ type ReferenceName = {
19
22
  type TsTypeTarget = {
20
23
  containerStyle: "map" | "record";
21
24
  callbackType: string;
22
- shouldRenderByteArrayAsNumber: boolean;
25
+ byteArrayType: string;
23
26
  renderNamed: (resolved: GirType | undefined, name: ReferenceName) => string;
24
27
  renderGtype: () => string;
25
28
  };
26
29
 
27
- const willEmitEntity = (type: EntityType): boolean => {
28
- switch (type.kind) {
29
- case "callback": {
30
- return type.value.introspectable && type.value.name.length > 0;
31
- }
32
- case "record": {
33
- return type.value.introspectable && type.value.name.length > 0;
34
- }
35
- case "alias":
36
- case "class":
37
- case "enum":
38
- case "interface": {
39
- return true;
40
- }
41
- }
30
+ const BYTE_ARRAY_TYPE = "Uint8Array";
31
+ const BYTE_ARRAY_INPUT_TYPE = "Uint8Array | number[]";
32
+ const NUMBER_ARRAY_TYPE = "number[]";
33
+
34
+ const willEmitEntity = (type: EntityType): boolean => isEmittableEntity(type.value);
35
+
36
+ const referenceName = (library: Library, ref: TypeId): ReferenceName | undefined => {
37
+ const name = library.nameFor(ref);
38
+
39
+ return name === undefined
40
+ ? undefined
41
+ : { namespaceName: name.namespaceName, typeName: sanitizeTypeIdentifier(name.typeName) };
42
42
  };
43
43
 
44
44
  const renderPrimitiveType = (target: TsTypeTarget, type: Extract<GirType, { kind: "primitive" }>): string =>
@@ -56,12 +56,13 @@ const renderBaseType = (library: Library, target: TsTypeTarget, ref: TypeId | un
56
56
  }
57
57
 
58
58
  const type = library.typeFor(ref);
59
- const name = library.nameFor(ref);
60
59
 
61
60
  if (type === undefined) {
62
- return renderNamedType(target, undefined, name);
61
+ return renderNamedType(target, undefined, undefined);
63
62
  }
64
63
 
64
+ const name = referenceName(library, ref);
65
+
65
66
  switch (type.kind) {
66
67
  case "primitive": {
67
68
  return renderPrimitiveType(target, type);
@@ -101,14 +102,14 @@ const renderContainerType = (
101
102
  };
102
103
 
103
104
  const renderSequenceType = (library: Library, target: TsTypeTarget, type: CArrayType | ListType): string => {
104
- if (type.kind === "list" && type.flavor === "gbytearray" && target.shouldRenderByteArrayAsNumber) {
105
- return "number[]";
106
- }
107
-
108
105
  if (type.kind === "carray" && hasUnknownArrayLength(type)) {
109
106
  return "number";
110
107
  }
111
108
 
109
+ if (isByteSequence(library, type)) {
110
+ return target.byteArrayType;
111
+ }
112
+
112
113
  return `${renderBaseType(library, target, type.element)}[]`;
113
114
  };
114
115
 
@@ -124,20 +125,34 @@ const renderNamedType = (
124
125
  return target.renderNamed(resolved, name);
125
126
  };
126
127
 
127
- const moduleTarget = (context: ModuleContext): TsTypeTarget => ({
128
+ const getByteArrayType = (library: Library): string =>
129
+ library.isByteArrayTyped ? BYTE_ARRAY_TYPE : NUMBER_ARRAY_TYPE;
130
+
131
+ const moduleTarget = (context: ModuleContext, byteArrayType: string): TsTypeTarget => ({
128
132
  containerStyle: "map",
129
133
  callbackType: "((...args: any[]) => any)",
130
- shouldRenderByteArrayAsNumber: true,
134
+ byteArrayType,
131
135
  renderNamed: (_resolved, name) => context.qualify(name.namespaceName, name.typeName),
132
136
  renderGtype: () => gtypeTsType(context),
133
137
  });
134
138
 
135
- const renderTsType = (context: ModuleContext, ref: TypeId | undefined, isNullable = false): string => {
136
- const base = renderBaseType(context.library, moduleTarget(context), ref);
139
+ const renderModuleType = (
140
+ context: ModuleContext,
141
+ ref: TypeId | undefined,
142
+ isNullable: boolean,
143
+ byteArrayType: string,
144
+ ): string => {
145
+ const base = renderBaseType(context.library, moduleTarget(context, byteArrayType), ref);
137
146
 
138
147
  return isNullable ? `${base} | null` : base;
139
148
  };
140
149
 
150
+ const renderTsType = (context: ModuleContext, ref: TypeId | undefined, isNullable = false): string =>
151
+ renderModuleType(context, ref, isNullable, getByteArrayType(context.library));
152
+
153
+ const renderParameterTsType = (context: ModuleContext, ref: TypeId | undefined, isNullable = false): string =>
154
+ renderModuleType(context, ref, isNullable, BYTE_ARRAY_INPUT_TYPE);
155
+
141
156
  const recordTypeTarget = (
142
157
  library: Library,
143
158
  renderNamedRef: (name: ReferenceName) => string,
@@ -146,7 +161,7 @@ const recordTypeTarget = (
146
161
  const target: TsTypeTarget = {
147
162
  containerStyle: "record",
148
163
  callbackType: "((...args: unknown[]) => unknown)",
149
- shouldRenderByteArrayAsNumber: false,
164
+ byteArrayType: getByteArrayType(library),
150
165
  renderNamed: (resolved, name) => {
151
166
  if (resolved?.kind === "alias") {
152
167
  return resolved.value.target === undefined
@@ -162,4 +177,4 @@ const recordTypeTarget = (
162
177
  return target;
163
178
  };
164
179
 
165
- export { renderBaseType, renderTsType, recordTypeTarget, type TsTypeTarget };
180
+ export { renderBaseType, renderParameterTsType, renderTsType, recordTypeTarget, type TsTypeTarget };
@@ -0,0 +1,14 @@
1
+ import type { Library } from "../gir/library.js";
2
+ import type { TypeId } from "../gir/type-id.js";
3
+
4
+ const typeKey = (library: Library, ref: TypeId | undefined): string => {
5
+ if (ref === undefined) {
6
+ return "void";
7
+ }
8
+
9
+ const type = library.typeFor(ref);
10
+
11
+ return type?.kind === "primitive" && type.category === "void" ? "void" : `${String(ref.nsId)}.${String(ref.id)}`;
12
+ };
13
+
14
+ export { typeKey };
@@ -1,6 +1,6 @@
1
1
  import type { Library } from "../gir/library.js";
2
2
  import type { PrimitiveCategory } from "../gir/primitives.js";
3
- import type { CArrayType, TypeId } from "../gir/type-id.js";
3
+ import type { CArrayType, ListType, TypeId } from "../gir/type-id.js";
4
4
  import type { GirType } from "../gir/type.js";
5
5
 
6
6
  const resolvedTypeFor = (library: Library, ref: TypeId | undefined): GirType | undefined =>
@@ -21,4 +21,7 @@ const primitiveCategoryFor = (library: Library, ref: TypeId | undefined): Primit
21
21
  const isUnboundedArray = (type: CArrayType): boolean =>
22
22
  type.isZeroTerminated && type.lengthParameterIndex === undefined && type.fixedSize === undefined;
23
23
 
24
- export { carrayFor, isUnboundedArray, primitiveCategoryFor };
24
+ const isByteSequence = (library: Library, type: CArrayType | ListType): boolean =>
25
+ type.kind === "list" ? type.flavor === "gbytearray" : primitiveCategoryFor(library, type.element) === "uint8";
26
+
27
+ export { carrayFor, isByteSequence, isUnboundedArray, primitiveCategoryFor };
package/src/compile.ts CHANGED
@@ -1,20 +1,46 @@
1
- import { existsSync, mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
1
+ import { errorCode, errorMessage, normalizeError } from "@gtkx/utils";
2
+ import { existsSync, mkdirSync, renameSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
2
3
  import { dirname, isAbsolute, join, relative } from "node:path";
3
4
  import { fileURLToPath } from "node:url";
4
5
  import ts from "typescript";
6
+ import { createStagingDir, sweepStrandedDirs } from "./staging.js";
5
7
 
6
- type SourceModule = {
8
+ type ProjectFile = {
7
9
  fileName: string;
10
+ origin?: string | undefined;
11
+ };
12
+
13
+ type SourceModule = ProjectFile & {
8
14
  source: string;
9
15
  };
10
16
 
11
- type CompileProjectParams = {
17
+ type ProjectContext = {
12
18
  projectDir: string;
13
- fileNames: string[];
19
+ files: ProjectFile[];
20
+ label: string;
21
+ };
22
+
23
+ type CompileProjectParams = ProjectContext & {
14
24
  compilerOptions: Record<string, unknown>;
25
+ };
26
+
27
+ type EmitModulesParams = {
28
+ projectDir: string;
29
+ files: SourceModule[];
15
30
  label: string;
16
31
  };
17
32
 
33
+ type DiagnosedFile = {
34
+ fileName: string;
35
+ text: string;
36
+ };
37
+
38
+ type FailedProjectInput = {
39
+ projectDir: string;
40
+ keepAt: string;
41
+ error: unknown;
42
+ };
43
+
18
44
  const BASE_COMPILER_OPTIONS = {
19
45
  module: "esnext",
20
46
  moduleResolution: "bundler",
@@ -43,6 +69,34 @@ const CHECK_OPTIONS = {
43
69
  noEmit: true,
44
70
  };
45
71
 
72
+ const DECLARATION_EMIT = {
73
+ declaration: true,
74
+ isolatedDeclarations: true,
75
+ removeComments: false,
76
+ };
77
+
78
+ const MODULE_EMIT = {
79
+ removeComments: false,
80
+ };
81
+
82
+ const DECLARATION_OPTIONS = ts.convertCompilerOptionsFromJson(
83
+ { ...BASE_COMPILER_OPTIONS, ...DECLARATION_EMIT },
84
+ ".",
85
+ ).options;
86
+
87
+ const MODULE_OPTIONS = ts.convertCompilerOptionsFromJson(
88
+ { ...BASE_COMPILER_OPTIONS, ...MODULE_EMIT },
89
+ ".",
90
+ ).options;
91
+
92
+ const TS_EXTENSION_PATTERN = /\.tsx?$/;
93
+ const DECLARATION_EXTENSION = ".d.ts";
94
+ const JAVASCRIPT_EXTENSION = ".js";
95
+ const CHECK_DIR = ".gtkx-check";
96
+ const FAILED_CHECK_DIR = `${CHECK_DIR}.failed`;
97
+ const LEGACY_CHECK_PREFIX = `${CHECK_DIR}-`;
98
+ const ESM_SCOPE_MANIFEST = `${JSON.stringify({ type: "module" }, null, 4)}\n`;
99
+
46
100
  const FORMAT_HOST: ts.FormatDiagnosticsHost = {
47
101
  getCanonicalFileName: (fileName) => fileName,
48
102
  getCurrentDirectory: () => ts.sys.getCurrentDirectory(),
@@ -69,57 +123,120 @@ const linkToolingModules = (projectDir: string): (() => void) => {
69
123
  };
70
124
  };
71
125
 
126
+ const ensureModuleScope = (projectDir: string): void => {
127
+ try {
128
+ writeFileSync(join(projectDir, "package.json"), ESM_SCOPE_MANIFEST, { flag: "wx" });
129
+ } catch (error) {
130
+ if (errorCode(error) !== "EEXIST") {
131
+ throw error;
132
+ }
133
+ }
134
+ };
135
+
72
136
  const isProjectFile = (rel: string): boolean =>
73
137
  !rel.startsWith("..") && !isAbsolute(rel) && !rel.split(/[/\\]/).includes("node_modules");
74
138
 
75
- const projectDiagnosticLine = (diagnostic: ts.Diagnostic, projectDir: string): string | undefined => {
139
+ const projectDiagnosticFile = (diagnostic: ts.Diagnostic, projectDir: string): DiagnosedFile | undefined => {
76
140
  const { file, start } = diagnostic;
77
141
 
78
142
  if (file === undefined || start === undefined) {
79
143
  return undefined;
80
144
  }
81
145
 
82
- const filePath = relative(projectDir, file.fileName);
146
+ const fileName = relative(projectDir, file.fileName);
83
147
 
84
- if (!isProjectFile(filePath)) {
148
+ if (!isProjectFile(fileName)) {
85
149
  return undefined;
86
150
  }
87
151
 
88
152
  const { line, character } = file.getLineAndCharacterOfPosition(start);
89
153
  const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
90
154
 
91
- return `${filePath}:${String(line + 1)}:${String(character + 1)} - ${message} (TS${String(diagnostic.code)})`;
155
+ return {
156
+ fileName,
157
+ text: `${fileName}:${String(line + 1)}:${String(character + 1)} - ${message} (TS${String(diagnostic.code)})`,
158
+ };
92
159
  };
93
160
 
94
- const projectDiagnosticLines = (diagnostics: ts.Diagnostic[], projectDir: string): string[] => {
95
- const lines: string[] = [];
161
+ const projectDiagnosticFiles = (diagnostics: ts.Diagnostic[], projectDir: string): DiagnosedFile[] => {
162
+ const diagnosed: DiagnosedFile[] = [];
96
163
 
97
164
  for (const diagnostic of diagnostics) {
98
- const line = projectDiagnosticLine(diagnostic, projectDir);
165
+ const entry = projectDiagnosticFile(diagnostic, projectDir);
99
166
 
100
- if (line !== undefined) {
101
- lines.push(line);
167
+ if (entry !== undefined) {
168
+ diagnosed.push(entry);
102
169
  }
103
170
  }
104
171
 
105
- return lines;
172
+ return diagnosed;
106
173
  };
107
174
 
108
- const diagnosticError = (label: string, projectDir: string, diagnostics: ts.Diagnostic[]): Error => {
109
- const lines = projectDiagnosticLines(diagnostics, projectDir);
175
+ const collectOrigins = (files: ProjectFile[]): Map<string, string> => {
176
+ const origins: Map<string, string> = new Map();
110
177
 
111
- if (lines.length > 0) {
112
- return new Error(`Type checking ${label} found ${String(lines.length)} error(s):\n${lines.join("\n")}`);
178
+ for (const { fileName, origin } of files) {
179
+ if (origin !== undefined) {
180
+ origins.set(fileName, origin);
181
+ }
182
+ }
183
+
184
+ return origins;
185
+ };
186
+
187
+ const groupByOrigin = (diagnosed: DiagnosedFile[], origins: Map<string, string>): Map<string, Set<string>> => {
188
+ const grouped: Map<string, Set<string>> = new Map();
189
+
190
+ for (const { fileName } of diagnosed) {
191
+ const origin = origins.get(fileName);
192
+
193
+ if (origin !== undefined) {
194
+ grouped.set(origin, (grouped.get(origin) ?? new Set<string>()).add(fileName));
195
+ }
113
196
  }
114
197
 
115
- return new Error(`Type checking ${label} failed:\n${ts.formatDiagnostics(diagnostics, FORMAT_HOST).trim()}`);
198
+ return grouped;
199
+ };
200
+
201
+ const originLines = (diagnosed: DiagnosedFile[], files: ProjectFile[]): string[] =>
202
+ [...groupByOrigin(diagnosed, collectOrigins(files))].map(
203
+ ([origin, generated]) => `Generated from ${origin}: ${[...generated].join(", ")}`,
204
+ );
205
+
206
+ const diagnosticError = (params: ProjectContext, diagnostics: ts.Diagnostic[]): Error => {
207
+ const diagnosed = projectDiagnosticFiles(diagnostics, params.projectDir);
208
+ const { label } = params;
209
+
210
+ if (diagnosed.length === 0) {
211
+ return new Error(`Compiling ${label} failed:\n${ts.formatDiagnostics(diagnostics, FORMAT_HOST).trim()}`);
212
+ }
213
+
214
+ const lines = [...diagnosed.map((entry) => entry.text), ...originLines(diagnosed, params.files)];
215
+
216
+ return new Error(`Compiling ${label} found ${String(diagnosed.length)} error(s):\n${lines.join("\n")}`);
217
+ };
218
+
219
+ const keepFailedProject = (input: FailedProjectInput): Error => {
220
+ const { projectDir, keepAt, error } = input;
221
+
222
+ if (!existsSync(projectDir)) {
223
+ return normalizeError(error);
224
+ }
225
+
226
+ rmSync(keepAt, { recursive: true, force: true });
227
+ renameSync(projectDir, keepAt);
228
+ const rebased = errorMessage(error).split(projectDir).join(keepAt);
229
+
230
+ return new Error(`${rebased}\nThe generated sources are kept at ${keepAt}, where every path above resolves.`, {
231
+ cause: error,
232
+ });
116
233
  };
117
234
 
118
235
  const runProgram = (params: CompileProjectParams): ts.Diagnostic[] => {
119
236
  const parsed = ts.parseJsonConfigFileContent(
120
237
  {
121
238
  compilerOptions: { ...BASE_COMPILER_OPTIONS, ...params.compilerOptions },
122
- files: params.fileNames.map((name) => `./${name}`),
239
+ files: params.files.map((file) => `./${file.fileName}`),
123
240
  },
124
241
  ts.sys,
125
242
  params.projectDir,
@@ -140,24 +257,69 @@ const runProgram = (params: CompileProjectParams): ts.Diagnostic[] => {
140
257
  return [...program.emit().diagnostics];
141
258
  };
142
259
 
260
+ const replaceExtension = (fileName: string, extension: string): string =>
261
+ `${fileName.replace(TS_EXTENSION_PATTERN, "")}${extension}`;
262
+
263
+ const transpileOptions = (compilerOptions: ts.CompilerOptions, fileName: string): ts.TranspileOptions => ({
264
+ compilerOptions,
265
+ fileName,
266
+ reportDiagnostics: true,
267
+ });
268
+
269
+ const emitModule = (module: SourceModule, projectDir: string): ts.Diagnostic[] => {
270
+ const fileName = join(projectDir, module.fileName);
271
+ const declaration = ts.transpileDeclaration(module.source, transpileOptions(DECLARATION_OPTIONS, fileName));
272
+ const javascript = ts.transpileModule(module.source, transpileOptions(MODULE_OPTIONS, fileName));
273
+ const diagnostics = [...declaration.diagnostics ?? [], ...javascript.diagnostics ?? []];
274
+
275
+ if (diagnostics.length > 0) {
276
+ return diagnostics;
277
+ }
278
+
279
+ writeFileSync(replaceExtension(fileName, DECLARATION_EXTENSION), declaration.outputText);
280
+ writeFileSync(replaceExtension(fileName, JAVASCRIPT_EXTENSION), javascript.outputText);
281
+
282
+ return [];
283
+ };
284
+
285
+ const emitModules = (params: EmitModulesParams): void => {
286
+ const diagnostics: ts.Diagnostic[] = [];
287
+
288
+ for (const module of params.files) {
289
+ diagnostics.push(...emitModule(module, params.projectDir));
290
+ }
291
+
292
+ if (diagnostics.length > 0) {
293
+ throw diagnosticError(params, diagnostics);
294
+ }
295
+ };
296
+
143
297
  const compileProject = (params: CompileProjectParams): void => {
298
+ ensureModuleScope(params.projectDir);
144
299
  const unlinkToolingModules = linkToolingModules(params.projectDir);
145
300
 
146
301
  try {
147
302
  const diagnostics = runProgram(params);
148
303
 
149
304
  if (diagnostics.length > 0) {
150
- throw diagnosticError(params.label, params.projectDir, diagnostics);
305
+ throw diagnosticError(params, diagnostics);
151
306
  }
152
307
  } finally {
153
308
  unlinkToolingModules();
154
309
  }
155
310
  };
156
311
 
312
+ const stageCheckProject = (checkRoot: string): string => {
313
+ const projectDir = createStagingDir(join(checkRoot, CHECK_DIR));
314
+ sweepStrandedDirs(checkRoot, LEGACY_CHECK_PREFIX);
315
+
316
+ return projectDir;
317
+ };
318
+
157
319
  const checkModules = (params: { modules: SourceModule[]; resolveFrom: string; label: string }): void => {
158
320
  const checkRoot = join(params.resolveFrom, "node_modules");
159
- mkdirSync(checkRoot, { recursive: true });
160
- const projectDir = mkdtempSync(join(checkRoot, ".gtkx-check-"));
321
+ const projectDir = stageCheckProject(checkRoot);
322
+ const keepAt = join(checkRoot, FAILED_CHECK_DIR);
161
323
 
162
324
  try {
163
325
  for (const module of params.modules) {
@@ -168,13 +330,16 @@ const checkModules = (params: { modules: SourceModule[]; resolveFrom: string; la
168
330
 
169
331
  compileProject({
170
332
  projectDir,
171
- fileNames: params.modules.map((module) => module.fileName),
333
+ files: params.modules,
172
334
  compilerOptions: CHECK_OPTIONS,
173
335
  label: params.label,
174
336
  });
175
- } finally {
176
- rmSync(projectDir, { recursive: true, force: true });
337
+ } catch (error) {
338
+ throw keepFailedProject({ projectDir, keepAt, error });
177
339
  }
340
+
341
+ rmSync(projectDir, { recursive: true, force: true });
342
+ rmSync(keepAt, { recursive: true, force: true });
178
343
  };
179
344
 
180
- export { compileProject, checkModules, type SourceModule };
345
+ export { checkModules, emitModules, keepFailedProject, type SourceModule };
@@ -1,7 +1,8 @@
1
- import { pascalCase, sortStrings, sortStringsBy } from "@gtkx/utils";
1
+ import { sanitizeIdentifier, sanitizeTypeIdentifier, sortStrings, sortStringsBy } 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 { GirRecord } from "../gir/record.js";
5
+ import { isEmittableEntity } from "../gir/emittable.js";
5
6
  import { Library } from "../gir/library.js";
6
7
  import { type GirNamespace, namespaceDirectory } from "../gir/namespace.js";
7
8
  import { dedupeCallables, isEmittableCallable } from "../store/gi/callables.js";
@@ -23,6 +24,8 @@ type ApiReferenceOptions = {
23
24
  props?: ElementProps;
24
25
  /** GObject properties the project omits from generated props; without it pages show props that do not exist. */
25
26
  omittedProps?: OmittedProps;
27
+ /** Describes GIR byte sequences as `Uint8Array` rather than `number[]`; defaults to false. */
28
+ isByteArrayTyped?: boolean;
26
29
  };
27
30
 
28
31
  /** Narrows an `ApiReference.symbols` enumeration. */
@@ -214,13 +217,13 @@ const functionEntry = (
214
217
  };
215
218
 
216
219
  const classEntry = (namespace: GirNamespace, klass: GirClass): GiSymbolEntry | undefined => {
217
- if (!klass.introspectable || klass.name.length === 0) {
220
+ if (!isEmittableEntity(klass)) {
218
221
  return undefined;
219
222
  }
220
223
 
221
224
  const kind = klass.isInterface ? "interface" : "class";
222
225
 
223
- return { kind, namespace, name: pascalCase(klass.name), doc: klass.doc, klass };
226
+ return { kind, namespace, name: sanitizeTypeIdentifier(klass.name), doc: klass.doc, klass };
224
227
  };
225
228
 
226
229
  const classEntries = (namespace: GirNamespace): GiSymbolEntry[] => {
@@ -238,11 +241,11 @@ const classEntries = (namespace: GirNamespace): GiSymbolEntry[] => {
238
241
  };
239
242
 
240
243
  const recordEntry = (namespace: GirNamespace, record: GirRecord): GiSymbolEntry | undefined => {
241
- if (!record.introspectable || record.isVtable || record.name.length === 0) {
244
+ if (record.isVtable || !isEmittableEntity(record)) {
242
245
  return undefined;
243
246
  }
244
247
 
245
- return { kind: "record", namespace, name: record.name, doc: record.doc, record };
248
+ return { kind: "record", namespace, name: sanitizeTypeIdentifier(record.name), doc: record.doc, record };
246
249
  };
247
250
 
248
251
  const recordEntries = (namespace: GirNamespace): GiSymbolEntry[] => {
@@ -265,7 +268,7 @@ const valueEntries = (namespace: GirNamespace): GiSymbolEntry[] => [
265
268
  .map<GiSymbolEntry>((enumeration) => ({
266
269
  kind: "enum",
267
270
  namespace,
268
- name: enumeration.name,
271
+ name: sanitizeTypeIdentifier(enumeration.name),
269
272
  doc: enumeration.doc,
270
273
  enumeration,
271
274
  })),
@@ -274,21 +277,21 @@ const valueEntries = (namespace: GirNamespace): GiSymbolEntry[] => [
274
277
  .map<GiSymbolEntry>((callback) => ({
275
278
  kind: "callback",
276
279
  namespace,
277
- name: callback.name,
280
+ name: sanitizeTypeIdentifier(callback.name),
278
281
  doc: callback.doc,
279
282
  callback,
280
283
  })),
281
284
  ...namespace.aliases.map<GiSymbolEntry>((alias) => ({
282
285
  kind: "alias",
283
286
  namespace,
284
- name: alias.name,
287
+ name: sanitizeTypeIdentifier(alias.name),
285
288
  doc: alias.doc,
286
289
  alias,
287
290
  })),
288
291
  ...namespace.constants.map<GiSymbolEntry>((constant) => ({
289
292
  kind: "constant",
290
293
  namespace,
291
- name: constant.name,
294
+ name: sanitizeIdentifier(constant.name),
292
295
  doc: constant.doc,
293
296
  constant,
294
297
  })),
@@ -370,7 +373,7 @@ class ApiReference {
370
373
  this.libraries = options.libraries;
371
374
  this.props = options.props ?? {};
372
375
  this.omittedProps = options.omittedProps ?? {};
373
- this.library = Library.load(options.libraries, options.girPath);
376
+ this.library = Library.load(options.libraries, options.girPath, options.isByteArrayTyped === true);
374
377
  this.elementContext = { library: this.library, linkFor: (): string | undefined => undefined };
375
378
  this.buildIndex();
376
379
  }
@@ -29,6 +29,7 @@ import {
29
29
  originSignatureBlocks,
30
30
  type OriginSignatureEntry,
31
31
  propertyMetaLine,
32
+ qualifiedClassName,
32
33
  renderDocsSignalSignature,
33
34
  renderDocsType,
34
35
  signalTags,
@@ -76,7 +77,9 @@ const hierarchySection = (entry: GlibNamedClass, context: ElementPageContext): s
76
77
  const parts = ancestors.map((ancestor) => {
77
78
  const glib = getGlibName(ancestor.klass);
78
79
 
79
- return glib === undefined ? `\`${ancestor.namespaceName}.${ancestor.klass.name}\`` : glibLabel(context, glib);
80
+ return glib === undefined
81
+ ? `\`${qualifiedClassName(ancestor.namespaceName, ancestor.klass.name)}\``
82
+ : glibLabel(context, glib);
80
83
  });
81
84
 
82
85
  parts.push(`**${entry.glibName}**`);
@@ -265,7 +268,7 @@ const methodsSection = (entry: GlibNamedClass, context: ElementPageContext, self
265
268
  };
266
269
 
267
270
  const renderElementPage = (entry: GlibNamedClass, context: ElementPageContext): string => {
268
- const selfType = `${entry.namespace.name}.${entry.klass.name}`;
271
+ const selfType = qualifiedClassName(entry.namespace.name, entry.klass.name);
269
272
 
270
273
  return joinSections([
271
274
  frontmatter(entry),