@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.
- package/package.json +7 -6
- package/src/constants.ts +13 -47
- package/src/gir/alias.ts +2 -2
- package/src/gir/introspected-classes.ts +32 -69
- package/src/gir/record.ts +1 -1
- package/src/gir/registry.ts +0 -1
- package/src/gir/signal.ts +32 -0
- package/src/gir-module.ts +125 -165
- package/src/gir.ts +15 -39
- package/src/injections/gio.ts +14 -1
- package/src/injections/glib.ts +5 -0
- package/src/injections/gobject.ts +5 -0
- package/src/types/options-generation.ts +12 -0
- package/src/types/user-config.ts +12 -0
- package/src/utils/conflicts.ts +11 -45
- package/src/utils/documentation.ts +437 -27
- package/src/utils/gir-parsing.ts +31 -12
- package/src/utils/types.ts +3 -1
|
@@ -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 =
|
|
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
|
-
*
|
|
16
|
-
* Used for @param and @returns descriptions
|
|
17
|
-
*
|
|
18
|
-
*
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
448
|
+
* 2. Pandoc-style (newer, e.g. GLib 2.80+):
|
|
449
|
+
* ``` { .c }
|
|
450
|
+
* const char *pattern = ".*GLib.*";
|
|
451
|
+
* ```
|
|
46
452
|
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
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
|
-
.
|
|
58
|
-
.replaceAll(
|
|
59
|
-
|
|
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
|
}
|
package/src/utils/gir-parsing.ts
CHANGED
|
@@ -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:
|
|
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
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
-
|
|
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;
|
package/src/utils/types.ts
CHANGED
|
@@ -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
|
-
|
|
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;
|