@ts-for-gir/generator-json 4.0.0-rc.1 → 4.0.0-rc.12

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ts-for-gir/generator-json",
3
- "version": "4.0.0-rc.1",
3
+ "version": "4.0.0-rc.12",
4
4
  "description": "JSON generator for ts-for-gir",
5
5
  "main": "src/index.ts",
6
6
  "module": "src/index.ts",
@@ -36,17 +36,17 @@
36
36
  "json"
37
37
  ],
38
38
  "devDependencies": {
39
- "@ts-for-gir/tsconfig": "^4.0.0-rc.1",
40
- "@types/node": "^24.12.2",
41
- "typescript": "^6.0.2"
39
+ "@ts-for-gir/tsconfig": "^4.0.0-rc.12",
40
+ "@types/node": "^25.6.0",
41
+ "typescript": "^6.0.3"
42
42
  },
43
43
  "dependencies": {
44
- "@gi.ts/parser": "^4.0.0-rc.1",
45
- "@ts-for-gir/generator-base": "^4.0.0-rc.1",
46
- "@ts-for-gir/generator-typescript": "^4.0.0-rc.1",
47
- "@ts-for-gir/gir-module-metadata": "^4.0.0-rc.1",
48
- "@ts-for-gir/lib": "^4.0.0-rc.1",
49
- "@ts-for-gir/reporter": "^4.0.0-rc.1",
50
- "typedoc": "^0.28.18"
44
+ "@gi.ts/parser": "^4.0.0-rc.12",
45
+ "@ts-for-gir/generator-base": "^4.0.0-rc.12",
46
+ "@ts-for-gir/generator-typescript": "^4.0.0-rc.12",
47
+ "@ts-for-gir/gir-module-metadata": "^4.0.0-rc.12",
48
+ "@ts-for-gir/lib": "^4.0.0-rc.12",
49
+ "@ts-for-gir/reporter": "^4.0.0-rc.12",
50
+ "typedoc": "^0.28.19"
51
51
  }
52
52
  }
@@ -115,6 +115,8 @@ export interface GirNamespaceMetadata {
115
115
  description?: string;
116
116
  /** Logo/icon URL */
117
117
  logoUrl?: string;
118
+ /** Icon filename from refs/library-icons (e.g. "librsvg-r.svg") */
119
+ iconFile?: string;
118
120
  /** Project website URL */
119
121
  websiteUrl?: string;
120
122
  /** URL to upstream C API documentation */
@@ -16,9 +16,11 @@ import {
16
16
  type ProjectReflection,
17
17
  ReferenceReflection,
18
18
  ReflectionCategory,
19
+ ReflectionKind,
19
20
  Serializer,
20
21
  TSConfigReader,
21
22
  type TypeDocOptions,
23
+ type Reflection as TypeDocReflection,
22
24
  } from "typedoc";
23
25
  import { GirMetadataDeserializer } from "./gir-metadata-deserializer.ts";
24
26
  import { buildGirLookupIndex } from "./gir-metadata-index.ts";
@@ -128,6 +130,15 @@ export class TypeDocPipeline {
128
130
  result.project.packageVersion = module.libraryVersion.toString();
129
131
 
130
132
  this.registerGirMetadata(result.app, module);
133
+
134
+ // Attach metadata directly to module reflections for HTML rendering.
135
+ // registerGirMetadata only hooks into the serializer (for JSON export);
136
+ // the theme needs metadata on the reflections themselves.
137
+ const nsMeta = this.buildNamespaceMetadata(module);
138
+ for (const child of result.project.children ?? []) {
139
+ (child as unknown as { girNamespaceMetadata?: GirNamespaceMetadata }).girNamespaceMetadata ??= nsMeta;
140
+ }
141
+
131
142
  return result;
132
143
  }
133
144
 
@@ -215,6 +226,7 @@ export class TypeDocPipeline {
215
226
  [new TSConfigReader()],
216
227
  );
217
228
  this.fixExportImportReferences(result.project);
229
+ this.enrichModuleReflections(result.project);
218
230
  return result;
219
231
  }
220
232
 
@@ -271,7 +283,9 @@ export class TypeDocPipeline {
271
283
  ...existing,
272
284
  displayName: existing.displayName ?? meta.displayName,
273
285
  description: existing.description ?? meta.description,
274
- logoUrl: existing.logoUrl ?? meta.logoUrl,
286
+ logoUrl:
287
+ existing.logoUrl ?? meta.logoUrl ?? (meta.iconFile ? `assets/library-icons/${meta.iconFile}` : undefined),
288
+ iconFile: existing.iconFile ?? meta.iconFile,
275
289
  websiteUrl: existing.websiteUrl ?? meta.websiteUrl,
276
290
  cDocsUrl: existing.cDocsUrl ?? meta.cDocsUrl,
277
291
  license: existing.license ?? meta.license,
@@ -280,6 +294,33 @@ export class TypeDocPipeline {
280
294
  }
281
295
  }
282
296
 
297
+ /**
298
+ * Attach metadata to module reflections by matching against known GIR modules.
299
+ * Used in combined mode where modules are discovered via "packages" entry point strategy.
300
+ */
301
+ private enrichModuleReflections(project: ProjectReflection): void {
302
+ if (!project.children) return;
303
+
304
+ // Build lookup maps: by importName (e.g. "rsvg-2.0") and by packageName (e.g. "Rsvg-2.0")
305
+ const metaByImportName = new Map<string, GirNamespaceMetadata>();
306
+ for (const module of this.modules) {
307
+ metaByImportName.set(module.importName, this.buildNamespaceMetadata(module));
308
+ }
309
+
310
+ for (const child of project.children) {
311
+ const enriched = child as DeclarationReflection & { girNamespaceMetadata?: GirNamespaceMetadata };
312
+ if (enriched.girNamespaceMetadata?.category) continue;
313
+
314
+ // Module name may be scoped (e.g. "@girs/rsvg-2.0") — extract the importName part
315
+ const scopeMatch = child.name.match(/^@[^/]+\/(.+)$/);
316
+ const importName = scopeMatch ? scopeMatch[1] : child.name.toLowerCase();
317
+ const nsMeta = metaByImportName.get(importName);
318
+ if (nsMeta) {
319
+ enriched.girNamespaceMetadata ??= nsMeta;
320
+ }
321
+ }
322
+ }
323
+
283
324
  async cleanup(): Promise<void> {
284
325
  if (this.tempDir) {
285
326
  await rm(this.tempDir, { recursive: true, force: true });
@@ -509,25 +550,77 @@ export class TypeDocPipeline {
509
550
 
510
551
  /**
511
552
  * Extract a human-readable source name from an inherited member's `inheritedFrom`.
512
- * e.g. `"Window.accessible_role"` → looks up parent to get `"Gtk.Window"`.
553
+ *
554
+ * Two TypeDoc quirks are handled:
555
+ *
556
+ * 1. Per-class phantom inheritance chain. For `Window extends Widget extends
557
+ * InitiallyUnowned extends Object`, Window's `bind_property.inheritedFrom`
558
+ * points to `Widget.bind_property` (itself inherited from
559
+ * `InitiallyUnowned.bind_property`), not directly to the original definer.
560
+ * Walking the chain transitively yields the most-original visible source,
561
+ * matching gi-docgen's upstream documentation convention. When the chain
562
+ * crosses a package boundary the reference can't be resolved at runtime
563
+ * (target=-1), but the reference's `name` field still records the
564
+ * qualified original definer.
565
+ *
566
+ * 2. Accessor signatures. For an inherited accessor like Widget.cursor,
567
+ * `inheritedFrom.reflection` may be the get/set signature whose `parent`
568
+ * is the Accessor reflection (`Gtk.Widget.cursor`), not the class. Using
569
+ * that name verbatim creates a per-property "Inherited from
570
+ * Widget.cursor" section instead of a single "Inherited from Gtk.Widget"
571
+ * section. Walking up to the nearest containing class/interface fixes it.
513
572
  */
514
573
  private extractInheritedSourceName(child: DeclarationReflection): string | null {
515
574
  if (!child.inheritedFrom) return null;
516
575
 
517
- // Try to resolve via the referenced reflection's parent
518
- const target = child.inheritedFrom.reflection;
519
- if (target?.parent) {
520
- const parent = target.parent;
521
- // Get the full qualified name: "Gtk.Window" from the parent's path
522
- const fullName = parent.getFullName();
523
- // The full name format is "Module.Class" keep as-is
576
+ // 1. Follow `inheritedFrom` transitively to the original definer.
577
+ // Capture the *unresolved* boundary name if we hit one — TypeDoc's
578
+ // per-package conversion can't follow `inheritedFrom` across package
579
+ // boundaries (target=-1), but the reference's `name` field still
580
+ // records the original definer's qualified name.
581
+ let target = child.inheritedFrom.reflection as DeclarationReflection | undefined;
582
+ let unresolvedBoundaryName: string | undefined = target ? undefined : child.inheritedFrom.name;
583
+ const seen = new Set<number>();
584
+ while (target?.isDeclaration() && target.inheritedFrom) {
585
+ if (!target.inheritedFrom.reflection) {
586
+ unresolvedBoundaryName = target.inheritedFrom.name;
587
+ break;
588
+ }
589
+ if (seen.has(target.id)) break;
590
+ seen.add(target.id);
591
+ target = target.inheritedFrom.reflection as DeclarationReflection;
592
+ }
593
+
594
+ // 2. If the chain ended at a cross-package boundary, parse the original
595
+ // definer from the unresolved reference's `name` (e.g. for the gtk-4.0
596
+ // project, `Widget.bind_property.inheritedFrom.name` is
597
+ // "GObject.InitiallyUnowned.bind_property"). Strip the trailing member
598
+ // name to get the qualified defining class.
599
+ if (unresolvedBoundaryName) {
600
+ const lastDot = unresolvedBoundaryName.lastIndexOf(".");
601
+ if (lastDot > 0) return unresolvedBoundaryName.slice(0, lastDot);
602
+ }
603
+
604
+ // 3. The chain resolved fully within this project. Walk the target's
605
+ // parent chain to the containing class/interface so accessor signatures
606
+ // don't yield "Class.property" as the source.
607
+ if (target) {
608
+ let owner: TypeDocReflection | undefined = target.parent;
609
+ while (owner && !owner.kindOf(ReflectionKind.ClassOrInterface)) {
610
+ owner = owner.parent;
611
+ }
612
+ const fullName = owner?.getFullName();
524
613
  if (fullName) return fullName;
614
+ if (target.parent) {
615
+ const parentName = target.parent.getFullName();
616
+ if (parentName) return parentName;
617
+ }
525
618
  }
526
619
 
527
- // Fallback: extract from the name string (e.g. "Window.method" → "Window")
620
+ // Final fallback: parse the immediate `inheritedFrom.name`.
528
621
  const name = child.inheritedFrom.name;
529
- const dotIdx = name.indexOf(".");
530
- return dotIdx > 0 ? name.slice(0, dotIdx) : name;
622
+ const lastDot = name.lastIndexOf(".");
623
+ return lastDot > 0 ? name.slice(0, lastDot) : name;
531
624
  }
532
625
 
533
626
  /**
@@ -672,7 +765,8 @@ export class TypeDocPipeline {
672
765
  packageVersion: pkgJson?.version,
673
766
  displayName: meta?.displayName,
674
767
  description: meta?.description ?? pkgJson?.description,
675
- logoUrl: meta?.logoUrl,
768
+ logoUrl: meta?.logoUrl ?? (meta?.iconFile ? `assets/library-icons/${meta.iconFile}` : undefined),
769
+ iconFile: meta?.iconFile,
676
770
  websiteUrl: meta?.websiteUrl ?? pkgJson?.homepage,
677
771
  cDocsUrl: meta?.cDocsUrl,
678
772
  license: meta?.license ?? pkgJson?.license,