@ts-for-gir/generator-json 4.0.0-beta.44 → 4.0.0-rc.10
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 +11 -11
- package/src/gir-metadata-types.ts +2 -0
- package/src/typedoc-pipeline.ts +143 -12
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ts-for-gir/generator-json",
|
|
3
|
-
"version": "4.0.0-
|
|
3
|
+
"version": "4.0.0-rc.10",
|
|
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-
|
|
40
|
-
"@types/node": "^
|
|
41
|
-
"typescript": "^6.0.
|
|
39
|
+
"@ts-for-gir/tsconfig": "^4.0.0-rc.10",
|
|
40
|
+
"@types/node": "^25.6.0",
|
|
41
|
+
"typescript": "^6.0.3"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@gi.ts/parser": "^4.0.0-
|
|
45
|
-
"@ts-for-gir/generator-base": "^4.0.0-
|
|
46
|
-
"@ts-for-gir/generator-typescript": "^4.0.0-
|
|
47
|
-
"@ts-for-gir/gir-module-metadata": "^4.0.0-
|
|
48
|
-
"@ts-for-gir/lib": "^4.0.0-
|
|
49
|
-
"@ts-for-gir/reporter": "^4.0.0-
|
|
50
|
-
"typedoc": "^0.28.
|
|
44
|
+
"@gi.ts/parser": "^4.0.0-rc.10",
|
|
45
|
+
"@ts-for-gir/generator-base": "^4.0.0-rc.10",
|
|
46
|
+
"@ts-for-gir/generator-typescript": "^4.0.0-rc.10",
|
|
47
|
+
"@ts-for-gir/gir-module-metadata": "^4.0.0-rc.10",
|
|
48
|
+
"@ts-for-gir/lib": "^4.0.0-rc.10",
|
|
49
|
+
"@ts-for-gir/reporter": "^4.0.0-rc.10",
|
|
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 */
|
package/src/typedoc-pipeline.ts
CHANGED
|
@@ -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
|
|
|
@@ -240,9 +252,75 @@ export class TypeDocPipeline {
|
|
|
240
252
|
|
|
241
253
|
const result = await this.convertApp(app, "merged documentation");
|
|
242
254
|
this.fixExportImportReferences(result.project);
|
|
255
|
+
this.enrichMergedModuleMetadata(result.project);
|
|
243
256
|
return result;
|
|
244
257
|
}
|
|
245
258
|
|
|
259
|
+
/**
|
|
260
|
+
* Enrich module reflections with curated metadata after merge.
|
|
261
|
+
*
|
|
262
|
+
* In merge mode, girNamespaceMetadata lives at the project-root level of
|
|
263
|
+
* each individual JSON file. When TypeDoc merges these files, the metadata
|
|
264
|
+
* may not be transferred to the resulting module reflections. This method
|
|
265
|
+
* fills in missing metadata from the curated registry so that the theme
|
|
266
|
+
* can always categorise and describe every module.
|
|
267
|
+
*/
|
|
268
|
+
private enrichMergedModuleMetadata(project: ProjectReflection): void {
|
|
269
|
+
if (!project.children) return;
|
|
270
|
+
for (const child of project.children) {
|
|
271
|
+
const enriched = child as DeclarationReflection & { girNamespaceMetadata?: GirNamespaceMetadata };
|
|
272
|
+
// Skip modules that already have a category from the JSON deserializer
|
|
273
|
+
if (enriched.girNamespaceMetadata?.category) continue;
|
|
274
|
+
|
|
275
|
+
// Try to find curated metadata by matching the module name to a GIR ID.
|
|
276
|
+
// Module names in the merged project follow the pattern "Namespace-Version"
|
|
277
|
+
// (e.g. "Gtk-4.0") which matches the girId used in the metadata registry.
|
|
278
|
+
const meta = getModuleMetadata(child.name);
|
|
279
|
+
if (!meta) continue;
|
|
280
|
+
|
|
281
|
+
const existing = enriched.girNamespaceMetadata ?? ({} as GirNamespaceMetadata);
|
|
282
|
+
enriched.girNamespaceMetadata = {
|
|
283
|
+
...existing,
|
|
284
|
+
displayName: existing.displayName ?? meta.displayName,
|
|
285
|
+
description: existing.description ?? meta.description,
|
|
286
|
+
logoUrl:
|
|
287
|
+
existing.logoUrl ?? meta.logoUrl ?? (meta.iconFile ? `assets/library-icons/${meta.iconFile}` : undefined),
|
|
288
|
+
iconFile: existing.iconFile ?? meta.iconFile,
|
|
289
|
+
websiteUrl: existing.websiteUrl ?? meta.websiteUrl,
|
|
290
|
+
cDocsUrl: existing.cDocsUrl ?? meta.cDocsUrl,
|
|
291
|
+
license: existing.license ?? meta.license,
|
|
292
|
+
category: existing.category ?? meta.category,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
}
|
|
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
|
+
|
|
246
324
|
async cleanup(): Promise<void> {
|
|
247
325
|
if (this.tempDir) {
|
|
248
326
|
await rm(this.tempDir, { recursive: true, force: true });
|
|
@@ -472,25 +550,77 @@ export class TypeDocPipeline {
|
|
|
472
550
|
|
|
473
551
|
/**
|
|
474
552
|
* Extract a human-readable source name from an inherited member's `inheritedFrom`.
|
|
475
|
-
*
|
|
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.
|
|
476
572
|
*/
|
|
477
573
|
private extractInheritedSourceName(child: DeclarationReflection): string | null {
|
|
478
574
|
if (!child.inheritedFrom) return null;
|
|
479
575
|
|
|
480
|
-
//
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
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();
|
|
487
613
|
if (fullName) return fullName;
|
|
614
|
+
if (target.parent) {
|
|
615
|
+
const parentName = target.parent.getFullName();
|
|
616
|
+
if (parentName) return parentName;
|
|
617
|
+
}
|
|
488
618
|
}
|
|
489
619
|
|
|
490
|
-
//
|
|
620
|
+
// Final fallback: parse the immediate `inheritedFrom.name`.
|
|
491
621
|
const name = child.inheritedFrom.name;
|
|
492
|
-
const
|
|
493
|
-
return
|
|
622
|
+
const lastDot = name.lastIndexOf(".");
|
|
623
|
+
return lastDot > 0 ? name.slice(0, lastDot) : name;
|
|
494
624
|
}
|
|
495
625
|
|
|
496
626
|
/**
|
|
@@ -635,7 +765,8 @@ export class TypeDocPipeline {
|
|
|
635
765
|
packageVersion: pkgJson?.version,
|
|
636
766
|
displayName: meta?.displayName,
|
|
637
767
|
description: meta?.description ?? pkgJson?.description,
|
|
638
|
-
logoUrl: meta?.logoUrl,
|
|
768
|
+
logoUrl: meta?.logoUrl ?? (meta?.iconFile ? `assets/library-icons/${meta.iconFile}` : undefined),
|
|
769
|
+
iconFile: meta?.iconFile,
|
|
639
770
|
websiteUrl: meta?.websiteUrl ?? pkgJson?.homepage,
|
|
640
771
|
cDocsUrl: meta?.cDocsUrl,
|
|
641
772
|
license: meta?.license ?? pkgJson?.license,
|