@ts-for-gir/lib 4.0.0-beta.40 → 4.0.0-beta.42

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.
@@ -1,61 +1,471 @@
1
1
  import { NEW_LINE_REG_EXP } from "../constants.ts";
2
2
 
3
+ // ---------------------------------------------------------------------------
4
+ // Context interface for resolving C identifiers to TypeScript paths
5
+ // ---------------------------------------------------------------------------
6
+
7
+ /**
8
+ * Minimal interface for resolving GIR C identifiers to TypeScript paths.
9
+ * Keeps documentation.ts decoupled from GirModule to avoid circular deps.
10
+ */
11
+ export interface GirDocContext {
12
+ /** Resolve a C type name (e.g. "GBinding") to a TS path (e.g. "GObject.Binding"). */
13
+ resolveType(cTypeName: string): string | null;
14
+ /** Resolve a C enum constant (e.g. "G_BINDING_BIDIRECTIONAL") to a TS path (e.g. "GObject.BindingFlags.BIDIRECTIONAL"). */
15
+ resolveConstant(cIdentifier: string): string | null;
16
+ /** Base URL for gi-docgen content pages (e.g. "https://docs.gtk.org/gtk4/"). */
17
+ docBaseUrl?: string;
18
+ }
19
+
20
+ // ---------------------------------------------------------------------------
21
+ // GTK-Doc constant → JavaScript literal mapping
22
+ // ---------------------------------------------------------------------------
23
+
24
+ const JS_LITERAL_MAP: Record<string, string> = {
25
+ NULL: "null",
26
+ TRUE: "true",
27
+ FALSE: "false",
28
+ };
29
+
30
+ // ---------------------------------------------------------------------------
31
+ // Main entry points
32
+ // ---------------------------------------------------------------------------
33
+
3
34
  /**
4
- * Transforms GIR documentation text to markdown format
35
+ * Transforms GIR documentation text to markdown/TSDoc format.
36
+ *
37
+ * Handles GTK-Doc sigils (%NULL, #GObject, etc.), parameter highlights,
38
+ * code blocks, and function references.
39
+ *
5
40
  * @param text The documentation text to transform
41
+ * @param ctx Optional resolver for converting C identifiers to TS {@link} paths
6
42
  * @returns The transformed markdown text
7
43
  */
8
- export function transformGirDocText(text: string): string {
9
- text = transformGirDocHighlights(text);
44
+ export function transformGirDocText(text: string, ctx?: GirDocContext): string {
45
+ text = transformRelativeImageUrls(text, ctx);
46
+ text = applyCommonDocTransforms(text, ctx);
10
47
  text = transformGirDocCodeBlocks(text);
11
48
  return text;
12
49
  }
13
50
 
14
51
  /**
15
- * Transforms TSDoc tag text by removing newlines
16
- * Used for @param and @returns descriptions
17
- * @param text The tag text to transform
18
- * @returns The cleaned text
52
+ * Cleans TSDoc tag text by removing newlines.
53
+ * Used for @param and @returns descriptions in gir-module.ts.
54
+ *
55
+ * Note: GTK-Doc marker transformation is NOT done here because the
56
+ * GirDocContext is not available at tag creation time. Marker transformation
57
+ * is applied later in addGirDocComment() where context is available.
19
58
  */
20
59
  export function transformGirDocTagText(text: string): string {
21
60
  return text.replace(NEW_LINE_REG_EXP, " ");
22
61
  }
23
62
 
24
63
  /**
25
- * Replaces "@any_property" with "`any_property`"
64
+ * Transforms TSDoc tag text with full GTK-Doc marker resolution.
65
+ * Used in addGirDocComment() where both text and context are available.
66
+ */
67
+ export function transformGirDocTagTextWithContext(text: string, ctx?: GirDocContext): string {
68
+ return applyCommonDocTransforms(text, ctx).replace(NEW_LINE_REG_EXP, " ");
69
+ }
70
+
71
+ /** Shared transformation chain used by both full-text and tag-text pipelines. */
72
+ function applyCommonDocTransforms(text: string, ctx?: GirDocContext): string {
73
+ text = transformRelativeDocLinks(text, ctx);
74
+ text = transformClassVfuncRefs(text, ctx);
75
+ text = transformGiDocgenLinks(text);
76
+ text = transformGtkDocMarkers(text, ctx);
77
+ text = transformBacktickTypeRefs(text, ctx);
78
+ text = transformGirDocHighlights(text);
79
+ return text;
80
+ }
81
+
82
+ // ---------------------------------------------------------------------------
83
+ // GTK-Doc marker transformations
84
+ // ---------------------------------------------------------------------------
85
+
86
+ /**
87
+ * Process GTK-Doc markers in order of specificity (like gi-docgen):
88
+ * signals (#T::s) → properties (#T:p) → types (#T) → constants (%C) → functions f()
89
+ */
90
+ function transformGtkDocMarkers(text: string, ctx?: GirDocContext): string {
91
+ text = transformSignalRefs(text, ctx);
92
+ text = transformPropertyRefs(text, ctx);
93
+ text = transformTypeRefs(text, ctx);
94
+ text = transformLowercaseCTypeRefs(text, ctx);
95
+ text = transformLiterals(text, ctx);
96
+ text = transformFunctionRefs(text);
97
+ return text;
98
+ }
99
+
100
+ // ---------------------------------------------------------------------------
101
+ // Individual marker handlers
102
+ // ---------------------------------------------------------------------------
103
+
104
+ /**
105
+ * Convert signal references: #CType::signal-name
106
+ * Signals aren't direct class members in TS, so we use backtick formatting.
107
+ */
108
+ function transformSignalRefs(text: string, ctx?: GirDocContext): string {
109
+ return text.replace(/#([A-Z][A-Za-z0-9]+)::([a-z0-9_-]+)/g, (_match, cType, signal) => {
110
+ const resolved = ctx?.resolveType(cType);
111
+ if (resolved) {
112
+ const signalKey = signal.replace(/-/g, "_");
113
+ return `{@link ${resolved}.SignalSignatures.${signalKey} | ${resolved}::${signal}}`;
114
+ }
115
+ return `\`${cType}::${signal}\``;
116
+ });
117
+ }
118
+
119
+ /**
120
+ * Convert property references: #CType:prop-name
121
+ * Properties ARE class members in TS, so we use {@link} when resolvable.
122
+ */
123
+ function transformPropertyRefs(text: string, ctx?: GirDocContext): string {
124
+ return text.replace(/#([A-Z][A-Za-z0-9]+):([a-z0-9_-]+)/g, (_match, cType, prop) => {
125
+ const resolved = ctx?.resolveType(cType);
126
+ // Convert kebab-case to snake_case for TS property names
127
+ const propName = prop.replace(/-/g, "_");
128
+ if (resolved) {
129
+ return `{@link ${resolved}.${propName}}`;
130
+ }
131
+ return `\`${cType}:${prop}\``;
132
+ });
133
+ }
134
+
135
+ /**
136
+ * Convert type references: #CType → {@link Ns.Type} or `CType`
137
+ * Must run AFTER signal/property refs to avoid partial matches.
138
+ */
139
+ function transformTypeRefs(text: string, ctx?: GirDocContext): string {
140
+ return text.replace(/(^|\W)#([A-Z][A-Za-z0-9]+)\b/gm, (_match, prefix, cType) => {
141
+ const resolved = ctx?.resolveType(cType);
142
+ if (resolved) {
143
+ return `${prefix}{@link ${resolved}}`;
144
+ }
145
+ return `${prefix}\`${cType}\``;
146
+ });
147
+ }
148
+
149
+ /**
150
+ * Known GLib/C primitive type names that should be formatted as code.
151
+ * These don't have underscores, so they need explicit recognition to
152
+ * distinguish them from HTML anchors like #io or #readme.
153
+ */
154
+ const GLIB_PRIMITIVES = new Set([
155
+ "gchar",
156
+ "guchar",
157
+ "gboolean",
158
+ "gshort",
159
+ "gushort",
160
+ "gint",
161
+ "guint",
162
+ "glong",
163
+ "gulong",
164
+ "gfloat",
165
+ "gdouble",
166
+ "gint8",
167
+ "guint8",
168
+ "gint16",
169
+ "guint16",
170
+ "gint32",
171
+ "guint32",
172
+ "gint64",
173
+ "guint64",
174
+ "gsize",
175
+ "gssize",
176
+ "goffset",
177
+ "gpointer",
178
+ "gconstpointer",
179
+ "gintptr",
180
+ "guintptr",
181
+ ]);
182
+
183
+ /**
184
+ * Convert lowercase C type references: #graphene_frustum_t → {@link Graphene.Frustum}
185
+ *
186
+ * Handles two categories:
187
+ * - Underscore-containing identifiers (e.g. #cairo_surface_t) → resolved or `code`
188
+ * - Known GLib primitives (e.g. #gchar, #gboolean) → `code`
189
+ *
190
+ * Leaves non-C references like #io, #readme unchanged.
191
+ * Must run AFTER transformTypeRefs (uppercase) to avoid conflicts.
192
+ */
193
+ function transformLowercaseCTypeRefs(text: string, ctx?: GirDocContext): string {
194
+ return text.replace(/(^|\W)#([a-z][a-z0-9_]+)\b/gm, (match, prefix, cType) => {
195
+ // Try to resolve as a known C type via context
196
+ const resolved = ctx?.resolveType(cType);
197
+ if (resolved) {
198
+ return `${prefix}{@link ${resolved}}`;
199
+ }
200
+ // Format as code if it contains underscores (strong C identifier signal)
201
+ if (cType.includes("_")) {
202
+ return `${prefix}\`${cType}\``;
203
+ }
204
+ // Format known GLib primitives as code
205
+ if (GLIB_PRIMITIVES.has(cType)) {
206
+ return `${prefix}\`${cType}\``;
207
+ }
208
+ // Leave unknown single-word refs unchanged (might be anchors/headings)
209
+ return match;
210
+ });
211
+ }
212
+
213
+ /**
214
+ * Convert literal/constant references:
215
+ * - %NULL → `null`, %TRUE → `true`, %FALSE → `false`
216
+ * - %G_CONSTANT_NAME → {@link Ns.Enum.MEMBER} or `G_CONSTANT_NAME`
217
+ */
218
+ function transformLiterals(text: string, ctx?: GirDocContext): string {
219
+ return text.replace(/(^|\W)%([A-Z][A-Z0-9_]*)\b/gm, (_match, prefix, constant) => {
220
+ // Check for JS literal equivalents first
221
+ const jsLiteral = JS_LITERAL_MAP[constant];
222
+ if (jsLiteral) {
223
+ return `${prefix}\`${jsLiteral}\``;
224
+ }
225
+ // Try to resolve as enum constant
226
+ const resolved = ctx?.resolveConstant(constant);
227
+ if (resolved) {
228
+ return `${prefix}{@link ${resolved}}`;
229
+ }
230
+ return `${prefix}\`${constant}\``;
231
+ });
232
+ }
233
+
234
+ /**
235
+ * Convert C function call references: c_func_name() → `c_func_name()`
236
+ * Only matches lowercase identifiers followed by () to avoid false positives.
237
+ */
238
+ function transformFunctionRefs(text: string): string {
239
+ return text.replace(/(^|\s)([a-z][a-z0-9_]*)\(\)/gm, (_match, prefix, func) => {
240
+ return `${prefix}\`${func}()\``;
241
+ });
242
+ }
243
+
244
+ // ---------------------------------------------------------------------------
245
+ // Relative documentation link resolution
246
+ // ---------------------------------------------------------------------------
247
+
248
+ /**
249
+ * Convert relative gi-docgen HTML links to absolute URLs.
250
+ *
251
+ * GIR docs contain markdown links to gi-docgen content pages like
252
+ * `[coordinate system](coordinates.html)` or `[Widget](class.Widget.html)`.
253
+ * These are converted to absolute URLs when a base URL is available.
254
+ */
255
+ function transformRelativeDocLinks(text: string, ctx?: GirDocContext): string {
256
+ const baseUrl = ctx?.docBaseUrl;
257
+ if (!baseUrl) return text;
258
+ return text.replace(
259
+ /\]\(([a-zA-Z][\w.-]*\.html(?:[#?][^\s)]*)?)\)/g,
260
+ (_match, relUrl: string) => `](${baseUrl}${relUrl})`,
261
+ );
262
+ }
263
+
264
+ /**
265
+ * Convert relative image URLs in HTML <img> and <source> tags to absolute URLs.
266
+ *
267
+ * GIR docs contain inline HTML with relative image paths like
268
+ * `<img src="about-dialog.png">` or `<source srcset="about-dialog-dark.png">`.
269
+ * These are converted to absolute URLs when a base URL is available.
270
+ */
271
+ function transformRelativeImageUrls(text: string, ctx?: GirDocContext): string {
272
+ const baseUrl = ctx?.docBaseUrl;
273
+ if (!baseUrl) return text;
274
+ // Match src="relative.png" and srcset="relative.png" in HTML tags
275
+ return text.replace(
276
+ /((?:src|srcset)\s*=\s*")([a-zA-Z][\w.-]+\.(?:png|jpg|jpeg|gif|svg|webp))(")/gi,
277
+ (_match, before: string, relUrl: string, after: string) => `${before}${baseUrl}${relUrl}${after}`,
278
+ );
279
+ }
280
+
281
+ // ---------------------------------------------------------------------------
282
+ // C class vfunc reference transformations
283
+ // ---------------------------------------------------------------------------
284
+
285
+ /**
286
+ * Convert C class vfunc references to {@link} or cleaned backtick format.
287
+ *
288
+ * Handles patterns from GIR docs (both correct and broken backtick variants):
289
+ * - `` `GtkWidgetClass.snapshot()` `` → {@link Gtk.Widget.snapshot}
290
+ * - `` `GtkWidget`Class.snapshot() `` → {@link Gtk.Widget.snapshot}
291
+ * - `GtkLayoutManagerClass.create_layout_child()` → {@link Gtk.LayoutManager.create_layout_child}
292
+ *
293
+ * Must run BEFORE other transformations to prevent partial matches.
294
+ */
295
+ function transformClassVfuncRefs(text: string, ctx?: GirDocContext): string {
296
+ return text.replace(/`([A-Z]\w+)`?Class\.(\w+)\(\)`?/g, (_match, cType: string, method: string) => {
297
+ const resolved = ctx?.resolveType(cType);
298
+ if (resolved) {
299
+ return `{@link ${resolved}.${method}}`;
300
+ }
301
+ return `\`${cType}Class.${method}()\``;
302
+ });
303
+ }
304
+
305
+ // ---------------------------------------------------------------------------
306
+ // gi-docgen link transformations
307
+ // ---------------------------------------------------------------------------
308
+
309
+ /** Fragment types that represent types → {@link Ns.Type} */
310
+ const TYPE_FRAGMENTS = new Set(["alias", "callback", "class", "const", "iface", "struct", "type"]);
311
+
312
+ /** Fragment types that represent enumerations (may have member suffix) */
313
+ const ENUM_FRAGMENTS = new Set(["enum", "error", "flags"]);
314
+
315
+ /** Fragment types that represent callable members → {@link Ns.Type.method} */
316
+ const CALLABLE_FRAGMENTS = new Set(["method", "ctor", "vfunc", "func"]);
317
+
318
+ /**
319
+ * Convert gi-docgen link syntax [fragment@Namespace.Type] to TSDoc.
320
+ *
321
+ * Handles all fragment types: alias, callback, class, const, ctor, enum,
322
+ * error, flags, func, id, iface, method, property, signal, struct, type, vfunc.
323
+ *
324
+ * Must run BEFORE transformGtkDocMarkers and transformGirDocHighlights to
325
+ * prevent corruption of the @ symbol inside [fragment@...] patterns.
326
+ */
327
+ function transformGiDocgenLinks(text: string): string {
328
+ return text.replace(/\[`?(\w+)@([\w.\-:]+)`?\]/g, (_match, fragment: string, endpoint: string) => {
329
+ // Type references: [class@Gtk.Widget] → {@link Gtk.Widget}
330
+ if (TYPE_FRAGMENTS.has(fragment)) {
331
+ return `{@link ${endpoint}}`;
332
+ }
333
+
334
+ // Enum/flags/error: [enum@Gtk.AccessibleRole.window] → {@link Gtk.AccessibleRole.WINDOW}
335
+ if (ENUM_FRAGMENTS.has(fragment)) {
336
+ const parts = endpoint.split(".");
337
+ if (parts.length >= 3) {
338
+ // Last part is enum member — uppercase for TS convention
339
+ const member = parts[parts.length - 1].toUpperCase();
340
+ const typePath = parts.slice(0, -1).join(".");
341
+ return `{@link ${typePath}.${member}}`;
342
+ }
343
+ return `{@link ${endpoint}}`;
344
+ }
345
+
346
+ // Signal references: [signal@Gtk.Widget::query-tooltip] → `Gtk.Widget::query-tooltip`
347
+ if (fragment === "signal") {
348
+ return `\`${endpoint}\``;
349
+ }
350
+
351
+ // Property references: [property@Gtk.Widget:visible] → {@link Gtk.Widget.visible}
352
+ if (fragment === "property") {
353
+ const colonIdx = endpoint.indexOf(":");
354
+ if (colonIdx !== -1) {
355
+ const typePart = endpoint.substring(0, colonIdx);
356
+ const propPart = endpoint.substring(colonIdx + 1).replace(/-/g, "_");
357
+ return `{@link ${typePart}.${propPart}}`;
358
+ }
359
+ return `\`${endpoint}\``;
360
+ }
361
+
362
+ // Method/ctor/vfunc/func: [method@Gtk.Widget.show] → {@link Gtk.Widget.show}
363
+ if (CALLABLE_FRAGMENTS.has(fragment)) {
364
+ return `{@link ${endpoint}}`;
365
+ }
366
+
367
+ // id and unknown fragments: [id@gtk_widget_show] → `gtk_widget_show`
368
+ return `\`${endpoint}\``;
369
+ });
370
+ }
371
+
372
+ // ---------------------------------------------------------------------------
373
+ // Backtick-wrapped C type name resolution
374
+ // ---------------------------------------------------------------------------
375
+
376
+ /**
377
+ * Convert backtick-wrapped C type references to TSDoc links when resolvable.
378
+ *
379
+ * GIR docs often contain C type names in backticks instead of GTK-Doc `#` notation.
380
+ * Handles three patterns:
381
+ * - `` `GtkWidget` `` → {@link Gtk.Widget}
382
+ * - `` `GtkWidget:visible` `` → {@link Gtk.Widget.visible} (property)
383
+ * - `` `GtkWidget::notify` `` → `Gtk.Widget::notify` (signal, backtick-quoted)
384
+ *
385
+ * Only converts names the resolver recognizes — unknown names keep backtick formatting.
386
+ * Must run AFTER transformGtkDocMarkers (which handles `#CType`) to avoid double-processing.
387
+ */
388
+ function transformBacktickTypeRefs(text: string, ctx?: GirDocContext): string {
389
+ if (!ctx) return text;
390
+
391
+ // Signal refs: `CType::signal-name` → `Ns.Type::signal-name`
392
+ text = text.replace(/`([A-Z][A-Za-z0-9]+)::([a-z0-9_-]+)`/g, (match, cType: string, signal: string) => {
393
+ const resolved = ctx.resolveType(cType);
394
+ if (resolved) {
395
+ return `\`${resolved}::${signal}\``;
396
+ }
397
+ return match;
398
+ });
399
+
400
+ // Property refs: `CType:prop-name` → {@link Ns.Type.prop_name}
401
+ text = text.replace(/`([A-Z][A-Za-z0-9]+):([a-z0-9_-]+)`/g, (match, cType: string, prop: string) => {
402
+ const resolved = ctx.resolveType(cType);
403
+ if (resolved) {
404
+ const propName = prop.replace(/-/g, "_");
405
+ return `{@link ${resolved}.${propName}}`;
406
+ }
407
+ return match;
408
+ });
409
+
410
+ // Plain type refs: `CType` → {@link Ns.Type}
411
+ text = text.replace(/`([A-Z][A-Za-z0-9]+)`/g, (match, cType: string) => {
412
+ const resolved = ctx.resolveType(cType);
413
+ if (resolved) {
414
+ return `{@link ${resolved}}`;
415
+ }
416
+ return match;
417
+ });
418
+
419
+ return text;
420
+ }
421
+
422
+ // ---------------------------------------------------------------------------
423
+ // Existing transformations (parameter highlights + code blocks)
424
+ // ---------------------------------------------------------------------------
425
+
426
+ /**
427
+ * Replaces "@any_property" with "`any_property`" for GIR parameter references.
428
+ * Skips TSDoc inline tags like {@link ...} (@ preceded by {) and any remaining
429
+ * gi-docgen fragments like [enum@...] (@ preceded by word char).
430
+ *
26
431
  * @param description E.g. "Creates a binding between @source_property on @source and @target_property on @target."
27
432
  * @returns E.g. "Creates a binding between `source_property` on `source` and `target_property` on `target`."
28
433
  */
29
434
  function transformGirDocHighlights(description: string): string {
30
- const highlights = description.match(/@[A-Za-z_-]*[^\s.]/gm);
31
- if (highlights) {
32
- for (const highlight of highlights) {
33
- description = description.replace(highlight, `\`${highlight.slice(1)}\``);
34
- }
35
- }
36
- return description;
435
+ return description.replace(/(?<!\{)(?<!\w)@([A-Za-z_][A-Za-z0-9_]*)/g, "`$1`");
37
436
  }
38
437
 
39
438
  /**
40
- * Replaces GIR code blocks with markdown code fences
439
+ * Replaces GIR code blocks with markdown code fences.
440
+ *
441
+ * Handles two formats found in GIR documentation:
442
+ *
443
+ * 1. GTK-Doc style (older):
444
+ * |[<!-- language="C" -->
445
+ * g_object_notify_by_pspec (self, properties[PROP_FOO]);
446
+ * ]|
41
447
  *
42
- * Replaces:
43
- * |[<!-- language="C" -->
44
- * g_object_notify_by_pspec (self, properties[PROP_FOO]);
45
- * ]|
448
+ * 2. Pandoc-style (newer, e.g. GLib 2.80+):
449
+ * ``` { .c }
450
+ * const char *pattern = ".*GLib.*";
451
+ * ```
46
452
  *
47
- * with:
48
- * ```c
49
- * g_object_notify_by_pspec (self, properties[PROP_FOO]);
50
- * ```
453
+ * Both are converted to standard markdown fences, e.g. ```c … ```.
454
+ * The language "plain" is mapped to no language (no syntax highlighting).
51
455
  *
52
456
  * @param description The description containing code blocks
53
457
  * @returns The description with markdown code fences
54
458
  */
55
459
  function transformGirDocCodeBlocks(description: string): string {
56
460
  description = description
57
- .replaceAll(/\|\[<!-- language="C" -->/gm, "\n```c") // C-Code
58
- .replaceAll(/\|\[/gm, "\n```") // Other code
59
- .replaceAll(/\]\|/gm, "```\n"); // End of code
461
+ // Pandoc-style: ``` { .c } ```c (or ``` { .xml } → ```xml etc.)
462
+ .replaceAll(/```\s*\{\s*\.(\w+)[^}]*\}/gm, "```$1")
463
+ // GTK-Doc style with language annotation (generic handler)
464
+ .replaceAll(/\|\[<!-- language="([^"]+)" -->/gm, (_match, lang: string) => {
465
+ if (lang === "plain" || lang === "text") return "\n```";
466
+ return `\n\`\`\`${lang.toLowerCase()}`;
467
+ })
468
+ .replaceAll(/\|\[/gm, "\n```") // GTK-Doc without language
469
+ .replaceAll(/\]\|/gm, "```\n"); // End of GTK-Doc code block
60
470
  return description;
61
471
  }
@@ -7,8 +7,10 @@ import type {
7
7
  GirFunctionElement,
8
8
  GirInfoAttrs,
9
9
  GirMethodElement,
10
+ GirType,
10
11
  } from "@gi.ts/parser";
11
12
  import { GirDirection } from "@gi.ts/parser";
13
+ import { LazyReporter } from "@ts-for-gir/reporter";
12
14
  import type { IntrospectedNamespace } from "../gir/namespace.ts";
13
15
  import {
14
16
  ArrayType,
@@ -24,6 +26,8 @@ import type { IntrospectedMetadata } from "../types/introspected.ts";
24
26
  import { deprecatedVersion, introducedVersion, isDeprecated } from "./girs.ts";
25
27
  import { isPrimitiveType, parseTypeExpression, resolvePrimitiveArrayType } from "./types.ts";
26
28
 
29
+ export const girParsingReporter = new LazyReporter("GirParsing");
30
+
27
31
  /**
28
32
  * Parse documentation from a GIR element
29
33
  */
@@ -65,7 +69,7 @@ export function parseMetadata(element: { $: GirInfoAttrs } & GirDocElement): Int
65
69
  * This function determines whether a given type is a "pointer type"...
66
70
  * Any type where the c:type ends with *
67
71
  */
68
- function isPointerType(types: import("@gi.ts/parser").GirType[] | undefined) {
72
+ function isPointerType(types: GirType[] | undefined) {
69
73
  const type = types?.[0];
70
74
  if (!type) return false;
71
75
 
@@ -122,11 +126,15 @@ export function getType(
122
126
  name = possibleName;
123
127
  } else {
124
128
  name = "unknown";
125
- console.log(
126
- `Failed to find array type in ${ns.packageName}: `,
127
- JSON.stringify(parameter.$, null, 4),
128
- "\nMarking as unknown!",
129
- );
129
+ const cType = (arr.type?.[0].$ as Record<string, string>)?.["c:type"] || "unknown";
130
+ girParsingReporter
131
+ .get()
132
+ .reportTypeResolutionWarning(
133
+ cType,
134
+ ns.namespace,
135
+ `Failed to find array type in ${ns.packageName}, marking as unknown`,
136
+ `c:type=${cType}`,
137
+ );
130
138
  }
131
139
  arrayDepth = depth;
132
140
  isPointer = isPointerType(array.type);
@@ -139,11 +147,15 @@ export function getType(
139
147
  name = possibleName;
140
148
  } else {
141
149
  name = "unknown";
142
- console.log(
143
- `Failed to find type in ${modName}: `,
144
- JSON.stringify(parameter.type[0].$, null, 4),
145
- "\nMarking as unknown!",
146
- );
150
+ const cType = (parameter.type[0].$ as Record<string, string>)?.["c:type"] || "unknown";
151
+ girParsingReporter
152
+ .get()
153
+ .reportTypeResolutionWarning(
154
+ cType,
155
+ modName,
156
+ `Failed to find type in ${modName}, marking as unknown`,
157
+ `c:type=${cType}`,
158
+ );
147
159
  }
148
160
  isPointer = isPointerType(parameter.type);
149
161
  } else if (parameter.varargs || (parameter.$ && parameter.$.name === "...")) {
@@ -151,7 +163,14 @@ export function getType(
151
163
  name = "any";
152
164
  } else {
153
165
  name = "unknown";
154
- console.log(`Unknown varargs type in ${modName}: `, JSON.stringify(parameter.$, null, 4), "\nMarking as unknown!");
166
+ girParsingReporter
167
+ .get()
168
+ .reportTypeResolutionWarning(
169
+ "varargs",
170
+ modName,
171
+ `Unknown varargs type in ${modName}, marking as unknown`,
172
+ parameter.$ ? JSON.stringify(parameter.$) : undefined,
173
+ );
155
174
  }
156
175
 
157
176
  let closure = null as null | number;
@@ -18,6 +18,7 @@ import {
18
18
  UnknownType,
19
19
  VoidType,
20
20
  } from "../gir.ts";
21
+ import { girParsingReporter } from "./gir-parsing.ts";
21
22
 
22
23
  /**
23
24
  * Get the type expression for an alias element
@@ -129,7 +130,7 @@ export function isPrimitiveType(name: string): boolean {
129
130
  export function resolvePrimitiveType(name: string): TypeExpression | null {
130
131
  switch (name) {
131
132
  case "":
132
- console.error(`Resolving '' to any on ${name}`);
133
+ girParsingReporter.get().reportTypeResolutionWarning("", "unknown", "Resolving empty type name to 'any'");
133
134
  return AnyType;
134
135
  case "filename":
135
136
  return StringType;
@@ -236,6 +237,7 @@ export function resolveDirectedType(type: TypeExpression, direction: GirDirectio
236
237
  }
237
238
  } else if (type.is("GLib", "HashTable")) {
238
239
  if (direction === GirDirection.In) {
240
+ // Intentional `any` — GLib.HashTable maps to a JS dict with dynamic values in generated output
239
241
  return new BinaryType(new NativeType("{ [key: string]: any }"), type);
240
242
  } else {
241
243
  return type;