@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
@@ -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,
@@ -24,21 +26,14 @@ type TsTypeTarget = {
24
26
  renderGtype: () => string;
25
27
  };
26
28
 
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
- }
29
+ const willEmitEntity = (type: EntityType): boolean => isEmittableEntity(type.value);
30
+
31
+ const referenceName = (library: Library, ref: TypeId): ReferenceName | undefined => {
32
+ const name = library.nameFor(ref);
33
+
34
+ return name === undefined
35
+ ? undefined
36
+ : { namespaceName: name.namespaceName, typeName: sanitizeTypeIdentifier(name.typeName) };
42
37
  };
43
38
 
44
39
  const renderPrimitiveType = (target: TsTypeTarget, type: Extract<GirType, { kind: "primitive" }>): string =>
@@ -56,12 +51,13 @@ const renderBaseType = (library: Library, target: TsTypeTarget, ref: TypeId | un
56
51
  }
57
52
 
58
53
  const type = library.typeFor(ref);
59
- const name = library.nameFor(ref);
60
54
 
61
55
  if (type === undefined) {
62
- return renderNamedType(target, undefined, name);
56
+ return renderNamedType(target, undefined, undefined);
63
57
  }
64
58
 
59
+ const name = referenceName(library, ref);
60
+
65
61
  switch (type.kind) {
66
62
  case "primitive": {
67
63
  return renderPrimitiveType(target, type);
@@ -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 };
package/src/compile.ts CHANGED
@@ -1,20 +1,37 @@
1
- import { existsSync, mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
1
+ import { 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
17
  type CompileProjectParams = {
12
18
  projectDir: string;
13
- fileNames: string[];
19
+ files: ProjectFile[];
14
20
  compilerOptions: Record<string, unknown>;
15
21
  label: string;
16
22
  };
17
23
 
24
+ type DiagnosedFile = {
25
+ fileName: string;
26
+ text: string;
27
+ };
28
+
29
+ type FailedProjectInput = {
30
+ projectDir: string;
31
+ keepAt: string;
32
+ error: unknown;
33
+ };
34
+
18
35
  const BASE_COMPILER_OPTIONS = {
19
36
  module: "esnext",
20
37
  moduleResolution: "bundler",
@@ -43,6 +60,10 @@ const CHECK_OPTIONS = {
43
60
  noEmit: true,
44
61
  };
45
62
 
63
+ const CHECK_DIR = ".gtkx-check";
64
+ const FAILED_CHECK_DIR = `${CHECK_DIR}.failed`;
65
+ const LEGACY_CHECK_PREFIX = `${CHECK_DIR}-`;
66
+
46
67
  const FORMAT_HOST: ts.FormatDiagnosticsHost = {
47
68
  getCanonicalFileName: (fileName) => fileName,
48
69
  getCurrentDirectory: () => ts.sys.getCurrentDirectory(),
@@ -72,54 +93,107 @@ const linkToolingModules = (projectDir: string): (() => void) => {
72
93
  const isProjectFile = (rel: string): boolean =>
73
94
  !rel.startsWith("..") && !isAbsolute(rel) && !rel.split(/[/\\]/).includes("node_modules");
74
95
 
75
- const projectDiagnosticLine = (diagnostic: ts.Diagnostic, projectDir: string): string | undefined => {
96
+ const projectDiagnosticFile = (diagnostic: ts.Diagnostic, projectDir: string): DiagnosedFile | undefined => {
76
97
  const { file, start } = diagnostic;
77
98
 
78
99
  if (file === undefined || start === undefined) {
79
100
  return undefined;
80
101
  }
81
102
 
82
- const filePath = relative(projectDir, file.fileName);
103
+ const fileName = relative(projectDir, file.fileName);
83
104
 
84
- if (!isProjectFile(filePath)) {
105
+ if (!isProjectFile(fileName)) {
85
106
  return undefined;
86
107
  }
87
108
 
88
109
  const { line, character } = file.getLineAndCharacterOfPosition(start);
89
110
  const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
90
111
 
91
- return `${filePath}:${String(line + 1)}:${String(character + 1)} - ${message} (TS${String(diagnostic.code)})`;
112
+ return {
113
+ fileName,
114
+ text: `${fileName}:${String(line + 1)}:${String(character + 1)} - ${message} (TS${String(diagnostic.code)})`,
115
+ };
92
116
  };
93
117
 
94
- const projectDiagnosticLines = (diagnostics: ts.Diagnostic[], projectDir: string): string[] => {
95
- const lines: string[] = [];
118
+ const projectDiagnosticFiles = (diagnostics: ts.Diagnostic[], projectDir: string): DiagnosedFile[] => {
119
+ const diagnosed: DiagnosedFile[] = [];
96
120
 
97
121
  for (const diagnostic of diagnostics) {
98
- const line = projectDiagnosticLine(diagnostic, projectDir);
122
+ const entry = projectDiagnosticFile(diagnostic, projectDir);
123
+
124
+ if (entry !== undefined) {
125
+ diagnosed.push(entry);
126
+ }
127
+ }
128
+
129
+ return diagnosed;
130
+ };
131
+
132
+ const collectOrigins = (files: ProjectFile[]): Map<string, string> => {
133
+ const origins: Map<string, string> = new Map();
134
+
135
+ for (const { fileName, origin } of files) {
136
+ if (origin !== undefined) {
137
+ origins.set(fileName, origin);
138
+ }
139
+ }
99
140
 
100
- if (line !== undefined) {
101
- lines.push(line);
141
+ return origins;
142
+ };
143
+
144
+ const groupByOrigin = (diagnosed: DiagnosedFile[], origins: Map<string, string>): Map<string, Set<string>> => {
145
+ const grouped: Map<string, Set<string>> = new Map();
146
+
147
+ for (const { fileName } of diagnosed) {
148
+ const origin = origins.get(fileName);
149
+
150
+ if (origin !== undefined) {
151
+ grouped.set(origin, (grouped.get(origin) ?? new Set<string>()).add(fileName));
102
152
  }
103
153
  }
104
154
 
105
- return lines;
155
+ return grouped;
106
156
  };
107
157
 
108
- const diagnosticError = (label: string, projectDir: string, diagnostics: ts.Diagnostic[]): Error => {
109
- const lines = projectDiagnosticLines(diagnostics, projectDir);
158
+ const originLines = (diagnosed: DiagnosedFile[], files: ProjectFile[]): string[] =>
159
+ [...groupByOrigin(diagnosed, collectOrigins(files))].map(
160
+ ([origin, generated]) => `Generated from ${origin}: ${[...generated].join(", ")}`,
161
+ );
162
+
163
+ const diagnosticError = (params: CompileProjectParams, diagnostics: ts.Diagnostic[]): Error => {
164
+ const diagnosed = projectDiagnosticFiles(diagnostics, params.projectDir);
165
+ const { label } = params;
110
166
 
111
- if (lines.length > 0) {
112
- return new Error(`Type checking ${label} found ${String(lines.length)} error(s):\n${lines.join("\n")}`);
167
+ if (diagnosed.length === 0) {
168
+ return new Error(`Type checking ${label} failed:\n${ts.formatDiagnostics(diagnostics, FORMAT_HOST).trim()}`);
113
169
  }
114
170
 
115
- return new Error(`Type checking ${label} failed:\n${ts.formatDiagnostics(diagnostics, FORMAT_HOST).trim()}`);
171
+ const lines = [...diagnosed.map((entry) => entry.text), ...originLines(diagnosed, params.files)];
172
+
173
+ return new Error(`Type checking ${label} found ${String(diagnosed.length)} error(s):\n${lines.join("\n")}`);
174
+ };
175
+
176
+ const keepFailedProject = (input: FailedProjectInput): Error => {
177
+ const { projectDir, keepAt, error } = input;
178
+
179
+ if (!existsSync(projectDir)) {
180
+ return normalizeError(error);
181
+ }
182
+
183
+ rmSync(keepAt, { recursive: true, force: true });
184
+ renameSync(projectDir, keepAt);
185
+ const rebased = errorMessage(error).split(projectDir).join(keepAt);
186
+
187
+ return new Error(`${rebased}\nThe generated sources are kept at ${keepAt}, where every path above resolves.`, {
188
+ cause: error,
189
+ });
116
190
  };
117
191
 
118
192
  const runProgram = (params: CompileProjectParams): ts.Diagnostic[] => {
119
193
  const parsed = ts.parseJsonConfigFileContent(
120
194
  {
121
195
  compilerOptions: { ...BASE_COMPILER_OPTIONS, ...params.compilerOptions },
122
- files: params.fileNames.map((name) => `./${name}`),
196
+ files: params.files.map((file) => `./${file.fileName}`),
123
197
  },
124
198
  ts.sys,
125
199
  params.projectDir,
@@ -147,17 +221,24 @@ const compileProject = (params: CompileProjectParams): void => {
147
221
  const diagnostics = runProgram(params);
148
222
 
149
223
  if (diagnostics.length > 0) {
150
- throw diagnosticError(params.label, params.projectDir, diagnostics);
224
+ throw diagnosticError(params, diagnostics);
151
225
  }
152
226
  } finally {
153
227
  unlinkToolingModules();
154
228
  }
155
229
  };
156
230
 
231
+ const stageCheckProject = (checkRoot: string): string => {
232
+ const projectDir = createStagingDir(join(checkRoot, CHECK_DIR));
233
+ sweepStrandedDirs(checkRoot, LEGACY_CHECK_PREFIX);
234
+
235
+ return projectDir;
236
+ };
237
+
157
238
  const checkModules = (params: { modules: SourceModule[]; resolveFrom: string; label: string }): void => {
158
239
  const checkRoot = join(params.resolveFrom, "node_modules");
159
- mkdirSync(checkRoot, { recursive: true });
160
- const projectDir = mkdtempSync(join(checkRoot, ".gtkx-check-"));
240
+ const projectDir = stageCheckProject(checkRoot);
241
+ const keepAt = join(checkRoot, FAILED_CHECK_DIR);
161
242
 
162
243
  try {
163
244
  for (const module of params.modules) {
@@ -168,13 +249,16 @@ const checkModules = (params: { modules: SourceModule[]; resolveFrom: string; la
168
249
 
169
250
  compileProject({
170
251
  projectDir,
171
- fileNames: params.modules.map((module) => module.fileName),
252
+ files: params.modules,
172
253
  compilerOptions: CHECK_OPTIONS,
173
254
  label: params.label,
174
255
  });
175
- } finally {
176
- rmSync(projectDir, { recursive: true, force: true });
256
+ } catch (error) {
257
+ throw keepFailedProject({ projectDir, keepAt, error });
177
258
  }
259
+
260
+ rmSync(projectDir, { recursive: true, force: true });
261
+ rmSync(keepAt, { recursive: true, force: true });
178
262
  };
179
263
 
180
- export { compileProject, checkModules, type SourceModule };
264
+ export { compileProject, checkModules, keepFailedProject, type ProjectFile, 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";
@@ -214,13 +215,13 @@ const functionEntry = (
214
215
  };
215
216
 
216
217
  const classEntry = (namespace: GirNamespace, klass: GirClass): GiSymbolEntry | undefined => {
217
- if (!klass.introspectable || klass.name.length === 0) {
218
+ if (!isEmittableEntity(klass)) {
218
219
  return undefined;
219
220
  }
220
221
 
221
222
  const kind = klass.isInterface ? "interface" : "class";
222
223
 
223
- return { kind, namespace, name: pascalCase(klass.name), doc: klass.doc, klass };
224
+ return { kind, namespace, name: sanitizeTypeIdentifier(klass.name), doc: klass.doc, klass };
224
225
  };
225
226
 
226
227
  const classEntries = (namespace: GirNamespace): GiSymbolEntry[] => {
@@ -238,11 +239,11 @@ const classEntries = (namespace: GirNamespace): GiSymbolEntry[] => {
238
239
  };
239
240
 
240
241
  const recordEntry = (namespace: GirNamespace, record: GirRecord): GiSymbolEntry | undefined => {
241
- if (!record.introspectable || record.isVtable || record.name.length === 0) {
242
+ if (record.isVtable || !isEmittableEntity(record)) {
242
243
  return undefined;
243
244
  }
244
245
 
245
- return { kind: "record", namespace, name: record.name, doc: record.doc, record };
246
+ return { kind: "record", namespace, name: sanitizeTypeIdentifier(record.name), doc: record.doc, record };
246
247
  };
247
248
 
248
249
  const recordEntries = (namespace: GirNamespace): GiSymbolEntry[] => {
@@ -265,7 +266,7 @@ const valueEntries = (namespace: GirNamespace): GiSymbolEntry[] => [
265
266
  .map<GiSymbolEntry>((enumeration) => ({
266
267
  kind: "enum",
267
268
  namespace,
268
- name: enumeration.name,
269
+ name: sanitizeTypeIdentifier(enumeration.name),
269
270
  doc: enumeration.doc,
270
271
  enumeration,
271
272
  })),
@@ -274,21 +275,21 @@ const valueEntries = (namespace: GirNamespace): GiSymbolEntry[] => [
274
275
  .map<GiSymbolEntry>((callback) => ({
275
276
  kind: "callback",
276
277
  namespace,
277
- name: callback.name,
278
+ name: sanitizeTypeIdentifier(callback.name),
278
279
  doc: callback.doc,
279
280
  callback,
280
281
  })),
281
282
  ...namespace.aliases.map<GiSymbolEntry>((alias) => ({
282
283
  kind: "alias",
283
284
  namespace,
284
- name: alias.name,
285
+ name: sanitizeTypeIdentifier(alias.name),
285
286
  doc: alias.doc,
286
287
  alias,
287
288
  })),
288
289
  ...namespace.constants.map<GiSymbolEntry>((constant) => ({
289
290
  kind: "constant",
290
291
  namespace,
291
- name: constant.name,
292
+ name: sanitizeIdentifier(constant.name),
292
293
  doc: constant.doc,
293
294
  constant,
294
295
  })),
@@ -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),
@@ -1,9 +1,16 @@
1
1
  import { sortStringsBy } from "@gtkx/utils";
2
- import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2
+ import { mkdirSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
3
3
  import { dirname, join } from "node:path";
4
- import { computeGiFingerprint, FINGERPRINT_FILENAME, isGiStoreFresh } from "../fingerprint.js";
4
+ import {
5
+ computeDocsFingerprint,
6
+ type DocsFingerprintInput,
7
+ FINGERPRINT_FILENAME,
8
+ isDocsOutputFresh,
9
+ } from "../fingerprint.js";
5
10
  import { Library } from "../gir/library.js";
6
11
  import { namespaceDirectory } from "../gir/namespace.js";
12
+ import { arrayGuard, hasFields, isString } from "../guards.js";
13
+ import { readJsonFile } from "../json.js";
7
14
  import { type ElementProps, setElementProps } from "../store/jsx/element-prop-imports.js";
8
15
  import { collectIntrinsicElementClasses, type GlibNamedClass } from "../store/jsx/intrinsic-elements.js";
9
16
  import { type OmittedProps, setOmittedProps } from "../store/jsx/omitted-props.js";
@@ -33,6 +40,7 @@ type DocsOptions = {
33
40
  };
34
41
 
35
42
  type DocsManifest = {
43
+ generator: string;
36
44
  namespaces: DocsNamespace[];
37
45
  };
38
46
 
@@ -50,6 +58,9 @@ type DocsResult = {
50
58
  };
51
59
 
52
60
  const MANIFEST_FILENAME = "manifest.json";
61
+ const MANIFEST_GENERATOR = "gtkx-docs";
62
+ const ROOT_INDEX_FILENAME = "index.md";
63
+ const DEFAULT_BASE_PATH = "/reference";
53
64
 
54
65
  const namespaceIndexPage = (namespace: DocsNamespace, elements: GlibNamedClass[]): string => {
55
66
  const rows = elements.map((entry, index) => {
@@ -144,6 +155,28 @@ const buildElementLinks = (elements: GlibNamedClass[], basePath: string): Map<st
144
155
  return linkByGlibName;
145
156
  };
146
157
 
158
+ const isEntryInsideOutDir = (value: string): boolean =>
159
+ value.length > 0 && value !== "." && value !== ".." && !value.includes("/") && !value.includes("\\");
160
+
161
+ const isChildEntry = (value: unknown): value is string => isString(value) && isEntryInsideOutDir(value);
162
+
163
+ const ownedEntry = (entry: string, source: string): string => {
164
+ if (isEntryInsideOutDir(entry)) {
165
+ return entry;
166
+ }
167
+
168
+ throw new Error(
169
+ `Refusing to generate documentation outside the output directory: ${source} maps to \`${entry}\`, ` +
170
+ "which is not an entry inside it. The GIR that declares it is malformed.",
171
+ );
172
+ };
173
+
174
+ const elementPagePath = (directory: string, entry: GlibNamedClass): string => {
175
+ const slug = ownedEntry(elementSlug(entry.klass.name), `the element ${entry.glibName}`);
176
+
177
+ return `${directory}/${slug}.md`;
178
+ };
179
+
147
180
  const namespacePages = (input: {
148
181
  name: string;
149
182
  elements: GlibNamedClass[];
@@ -152,7 +185,7 @@ const namespacePages = (input: {
152
185
  pageContext: ElementPageContext;
153
186
  }): NamespacePages => {
154
187
  const { name, elements, basePath, linkByGlibName, pageContext } = input;
155
- const directory = name.toLowerCase();
188
+ const directory = ownedEntry(namespaceDirectory({ name }), `the GIR namespace ${name}`);
156
189
 
157
190
  const docs: DocsNamespace = {
158
191
  name,
@@ -162,7 +195,7 @@ const namespacePages = (input: {
162
195
  };
163
196
 
164
197
  const pages: Page[] = elements.map((entry) => ({
165
- path: `${directory}/${elementSlug(entry.klass.name)}.md`,
198
+ path: elementPagePath(directory, entry),
166
199
  content: renderElementPage(entry, pageContext),
167
200
  }));
168
201
 
@@ -187,21 +220,90 @@ const generatePages = (options: DocsOptions, basePath: string, library: Library)
187
220
  namespaces.push(result.docs);
188
221
  }
189
222
 
190
- pages.push({ path: "index.md", content: rootIndexPage(namespaces, options.libraries) });
223
+ pages.push({ path: ROOT_INDEX_FILENAME, content: rootIndexPage(namespaces, options.libraries) });
191
224
 
192
225
  return { pages, namespaces };
193
226
  };
194
227
 
195
- const cachedDocsResult = (options: DocsOptions, manifestPath: string): DocsResult | undefined => {
196
- if (options.isForced === true || !isGiStoreFresh(options.outDir, options.libraries, options.girPath)) {
197
- return undefined;
228
+ const isGeneratorTag = (value: unknown): value is string => value === MANIFEST_GENERATOR;
229
+
230
+ const isDocsElementLink = (value: unknown): value is DocsElementLink =>
231
+ hasFields<DocsElementLink>(value, { text: isString, link: isString });
232
+
233
+ const isDocsNamespace = (value: unknown): value is DocsNamespace =>
234
+ hasFields<DocsNamespace>(value, {
235
+ name: isString,
236
+ directory: isChildEntry,
237
+ link: isString,
238
+ elements: arrayGuard(isDocsElementLink),
239
+ });
240
+
241
+ const isDocsManifest = (value: unknown): value is DocsManifest =>
242
+ hasFields<DocsManifest>(value, { generator: isGeneratorTag, namespaces: arrayGuard(isDocsNamespace) });
243
+
244
+ const readDocsManifest = (manifestPath: string): DocsManifest | undefined => {
245
+ const parsed = readJsonFile(manifestPath);
246
+
247
+ return isDocsManifest(parsed) ? parsed : undefined;
248
+ };
249
+
250
+ const outDirRefusal = (outDir: string, reason: string): Error =>
251
+ new Error(
252
+ `Refusing to generate documentation into ${outDir}: ${reason}. Point the output directory at an ` +
253
+ "empty directory or at one gtkx generated, or remove it yourself first.",
254
+ );
255
+
256
+ const assertOwnedOutDir = (options: DocsOptions, manifest: DocsManifest | undefined): void => {
257
+ const stats = statSync(options.outDir, { throwIfNoEntry: false });
258
+
259
+ if (stats === undefined) {
260
+ return;
261
+ }
262
+
263
+ if (!stats.isDirectory()) {
264
+ throw outDirRefusal(options.outDir, "it already exists and is not a directory");
265
+ }
266
+
267
+ if (manifest !== undefined || readdirSync(options.outDir).length === 0) {
268
+ return;
269
+ }
270
+
271
+ throw outDirRefusal(
272
+ options.outDir,
273
+ `it is not empty and holds no ${MANIFEST_FILENAME} written by \`gtkx docs\`, ` +
274
+ "so its contents are not gtkx's to replace",
275
+ );
276
+ };
277
+
278
+ const clearOutDir = (options: DocsOptions, manifest: DocsManifest | undefined): void => {
279
+ if (manifest === undefined) {
280
+ return;
198
281
  }
199
282
 
200
- if (!existsSync(manifestPath)) {
283
+ const entries = [
284
+ ...manifest.namespaces.map((namespace) => namespace.directory),
285
+ ROOT_INDEX_FILENAME,
286
+ MANIFEST_FILENAME,
287
+ FINGERPRINT_FILENAME,
288
+ ];
289
+
290
+ for (const entry of entries) {
291
+ rmSync(join(options.outDir, entry), { recursive: true, force: true });
292
+ }
293
+ };
294
+
295
+ const cachedDocsResult = (
296
+ options: DocsOptions,
297
+ manifest: DocsManifest | undefined,
298
+ input: DocsFingerprintInput,
299
+ ): DocsResult | undefined => {
300
+ if (manifest === undefined || options.isForced === true) {
201
301
  return undefined;
202
302
  }
203
303
 
204
- const manifest = JSON.parse(readFileSync(manifestPath, "utf8")) as DocsManifest;
304
+ if (!isDocsOutputFresh(options.outDir, options.libraries, options.girPath, input)) {
305
+ return undefined;
306
+ }
205
307
 
206
308
  return { isRegenerated: false, namespaces: manifest.namespaces };
207
309
  };
@@ -214,28 +316,36 @@ const writePages = (outDir: string, pages: Page[]): void => {
214
316
  }
215
317
  };
216
318
 
319
+ const docsFingerprintInput = (options: DocsOptions): DocsFingerprintInput => ({
320
+ basePath: options.basePath ?? DEFAULT_BASE_PATH,
321
+ props: options.props ?? {},
322
+ omittedProps: options.omittedProps ?? {},
323
+ });
324
+
217
325
  const writeDocs = (options: DocsOptions): DocsResult => {
218
- setElementProps(options.props ?? {});
219
- setOmittedProps(options.omittedProps ?? {});
220
- const basePath = options.basePath ?? "/reference";
326
+ const input = docsFingerprintInput(options);
327
+ setElementProps(input.props);
328
+ setOmittedProps(input.omittedProps);
221
329
  const manifestPath = join(options.outDir, MANIFEST_FILENAME);
222
- const cached = cachedDocsResult(options, manifestPath);
330
+ const previous = readDocsManifest(manifestPath);
331
+ const cached = cachedDocsResult(options, previous, input);
223
332
 
224
333
  if (cached !== undefined) {
225
334
  return cached;
226
335
  }
227
336
 
337
+ assertOwnedOutDir(options, previous);
228
338
  const library = Library.load(options.libraries, options.girPath);
229
- const { pages, namespaces } = generatePages(options, basePath, library);
230
- rmSync(options.outDir, { recursive: true, force: true });
339
+ const { pages, namespaces } = generatePages(options, input.basePath, library);
340
+ clearOutDir(options, previous);
231
341
  mkdirSync(options.outDir, { recursive: true });
232
- writePages(options.outDir, pages);
233
- const manifest: DocsManifest = { namespaces };
342
+ const manifest: DocsManifest = { generator: MANIFEST_GENERATOR, namespaces };
234
343
  writeFileSync(manifestPath, JSON.stringify(manifest));
344
+ writePages(options.outDir, pages);
235
345
 
236
346
  writeFileSync(
237
347
  join(options.outDir, FINGERPRINT_FILENAME),
238
- JSON.stringify(computeGiFingerprint(library.girFiles, options.libraries, options.girPath)),
348
+ JSON.stringify(computeDocsFingerprint(library.girFiles, options.libraries, options.girPath, input)),
239
349
  );
240
350
 
241
351
  return { isRegenerated: true, namespaces };
@@ -1,4 +1,4 @@
1
- import { pascalCase, sortStringsBy } from "@gtkx/utils";
1
+ import { sanitizeTypeIdentifier, sortStringsBy } from "@gtkx/utils";
2
2
  import type { GirAnnotations } from "../gir/annotations.js";
3
3
  import type { GirClass } from "../gir/class.js";
4
4
  import type { GirFunction } from "../gir/function.js";
@@ -286,10 +286,13 @@ const originSignatureBlocks = (entries: OriginSignatureEntry[]): string[] =>
286
286
  signatureEntryBlock(item, item.origin === undefined ? [] : [`From \`${item.origin}\`.`]),
287
287
  );
288
288
 
289
+ const qualifiedClassName = (namespaceName: string, className: string): string =>
290
+ `${namespaceName}.${sanitizeTypeIdentifier(className)}`;
291
+
289
292
  const classMethodEntries = (library: Library, namespace: GirNamespace, klass: GirClass): SignatureEntry[] => {
290
293
  const realContext = new ModuleContext(namespace, library);
291
294
  const signatureContext = docsSignatureContext(namespace, library);
292
- const className = pascalCase(klass.name);
295
+ const className = sanitizeTypeIdentifier(klass.name);
293
296
  const inherited = collectInheritedMethods(realContext, klass);
294
297
 
295
298
  return instanceMethodEntries(signatureContext, klass, (method) =>
@@ -307,7 +310,7 @@ const instanceMethodEntries = (
307
310
  ): SignatureEntry[] => {
308
311
  const deduped = dedupeCallables(klass.methods);
309
312
 
310
- const scope = instanceScope(pascalCase(klass.name), {
313
+ const scope = instanceScope(sanitizeTypeIdentifier(klass.name), {
311
314
  constructors: dedupeCallables(klass.constructors),
312
315
  functions: dedupeCallables(klass.functions),
313
316
  methods: deduped,
@@ -362,6 +365,7 @@ export {
362
365
  originSignatureBlocks,
363
366
  classMethodEntries,
364
367
  methodsSectionBlocks,
368
+ qualifiedClassName,
365
369
  tagNotes,
366
370
  type MetaDocEntry,
367
371
  type SignatureEntry,