@gtkx/gir 0.9.0 → 0.9.2
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 +1 -1
- package/src/doc-sanitizer.ts +370 -0
- package/src/index.ts +1 -0
- package/src/parser.ts +48 -36
- package/src/types.ts +47 -7
package/package.json
CHANGED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
type GirLinkType =
|
|
2
|
+
| "class"
|
|
3
|
+
| "iface"
|
|
4
|
+
| "struct"
|
|
5
|
+
| "enum"
|
|
6
|
+
| "flags"
|
|
7
|
+
| "error"
|
|
8
|
+
| "callback"
|
|
9
|
+
| "method"
|
|
10
|
+
| "vfunc"
|
|
11
|
+
| "func"
|
|
12
|
+
| "ctor"
|
|
13
|
+
| "property"
|
|
14
|
+
| "signal"
|
|
15
|
+
| "const"
|
|
16
|
+
| "type"
|
|
17
|
+
| "id";
|
|
18
|
+
|
|
19
|
+
interface GirLink {
|
|
20
|
+
type: GirLinkType;
|
|
21
|
+
namespace: string | undefined;
|
|
22
|
+
target: string;
|
|
23
|
+
member: string | undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const GIR_LINK_PATTERN = /\[([a-z]+)@([^\]]+)\]/gi;
|
|
27
|
+
|
|
28
|
+
function parseGirLink(type: string, reference: string): GirLink | undefined {
|
|
29
|
+
const linkType = type.toLowerCase() as GirLinkType;
|
|
30
|
+
|
|
31
|
+
const validTypes: GirLinkType[] = [
|
|
32
|
+
"class",
|
|
33
|
+
"iface",
|
|
34
|
+
"struct",
|
|
35
|
+
"enum",
|
|
36
|
+
"flags",
|
|
37
|
+
"error",
|
|
38
|
+
"callback",
|
|
39
|
+
"method",
|
|
40
|
+
"vfunc",
|
|
41
|
+
"func",
|
|
42
|
+
"ctor",
|
|
43
|
+
"property",
|
|
44
|
+
"signal",
|
|
45
|
+
"const",
|
|
46
|
+
"type",
|
|
47
|
+
"id",
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
if (!validTypes.includes(linkType)) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const parts = reference.split(".");
|
|
55
|
+
if (parts.length === 0) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (linkType === "property" || linkType === "signal") {
|
|
60
|
+
const colonIndex = reference.indexOf(":");
|
|
61
|
+
if (colonIndex !== -1) {
|
|
62
|
+
const beforeColon = reference.substring(0, colonIndex);
|
|
63
|
+
const afterColon = reference.substring(colonIndex + 1);
|
|
64
|
+
const beforeParts = beforeColon.split(".");
|
|
65
|
+
if (beforeParts.length >= 2) {
|
|
66
|
+
return {
|
|
67
|
+
type: linkType,
|
|
68
|
+
namespace: beforeParts[0],
|
|
69
|
+
target: beforeParts.slice(1).join("."),
|
|
70
|
+
member: afterColon.replace("::", ""),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
type: linkType,
|
|
75
|
+
namespace: undefined,
|
|
76
|
+
target: beforeColon,
|
|
77
|
+
member: afterColon.replace("::", ""),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (parts.length === 1) {
|
|
83
|
+
return {
|
|
84
|
+
type: linkType,
|
|
85
|
+
namespace: undefined,
|
|
86
|
+
target: parts[0] ?? "",
|
|
87
|
+
member: undefined,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (parts.length === 2) {
|
|
92
|
+
const first = parts[0] ?? "";
|
|
93
|
+
const second = parts[1] ?? "";
|
|
94
|
+
const isNamespace = first.length > 0 && first[0] === first[0]?.toUpperCase();
|
|
95
|
+
|
|
96
|
+
if (linkType === "func" || linkType === "const") {
|
|
97
|
+
return {
|
|
98
|
+
type: linkType,
|
|
99
|
+
namespace: first,
|
|
100
|
+
target: second,
|
|
101
|
+
member: undefined,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (isNamespace) {
|
|
106
|
+
return {
|
|
107
|
+
type: linkType,
|
|
108
|
+
namespace: first,
|
|
109
|
+
target: second,
|
|
110
|
+
member: undefined,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
type: linkType,
|
|
116
|
+
namespace: undefined,
|
|
117
|
+
target: first,
|
|
118
|
+
member: second,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
type: linkType,
|
|
124
|
+
namespace: parts[0],
|
|
125
|
+
target: parts[1] ?? "",
|
|
126
|
+
member: parts.slice(2).join(".") || undefined,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function formatGirLinkForTsDoc(link: GirLink): string {
|
|
131
|
+
let displayText: string;
|
|
132
|
+
if (link.member) {
|
|
133
|
+
displayText = `${link.target}.${link.member}`;
|
|
134
|
+
} else {
|
|
135
|
+
displayText = link.target;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const linkTarget = link.namespace ? `${link.namespace}.${displayText}` : displayText;
|
|
139
|
+
|
|
140
|
+
switch (link.type) {
|
|
141
|
+
case "class":
|
|
142
|
+
case "iface":
|
|
143
|
+
case "struct":
|
|
144
|
+
case "enum":
|
|
145
|
+
case "flags":
|
|
146
|
+
case "error":
|
|
147
|
+
case "callback":
|
|
148
|
+
case "type":
|
|
149
|
+
return `{@link ${linkTarget}}`;
|
|
150
|
+
|
|
151
|
+
case "method":
|
|
152
|
+
case "vfunc":
|
|
153
|
+
case "func":
|
|
154
|
+
case "ctor":
|
|
155
|
+
return `{@link ${linkTarget}}`;
|
|
156
|
+
|
|
157
|
+
case "property":
|
|
158
|
+
return `{@link ${linkTarget}}`;
|
|
159
|
+
|
|
160
|
+
case "signal":
|
|
161
|
+
return `{@link ${linkTarget}}`;
|
|
162
|
+
|
|
163
|
+
case "const":
|
|
164
|
+
return `{@link ${linkTarget}}`;
|
|
165
|
+
|
|
166
|
+
case "id":
|
|
167
|
+
return `\`${link.target}\``;
|
|
168
|
+
|
|
169
|
+
default:
|
|
170
|
+
return `\`${displayText}\``;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function convertGirLinks(text: string): string {
|
|
175
|
+
return text.replace(GIR_LINK_PATTERN, (_, type: string, reference: string) => {
|
|
176
|
+
const link = parseGirLink(type, reference);
|
|
177
|
+
if (!link) {
|
|
178
|
+
return `\`${reference}\``;
|
|
179
|
+
}
|
|
180
|
+
return formatGirLinkForTsDoc(link);
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const NAMESPACE_TO_DOCS_PATH: Record<string, string> = {
|
|
185
|
+
Gtk: "gtk4",
|
|
186
|
+
Gdk: "gdk4",
|
|
187
|
+
Gsk: "gsk4",
|
|
188
|
+
Adw: "adw1",
|
|
189
|
+
GLib: "glib",
|
|
190
|
+
GObject: "gobject",
|
|
191
|
+
Gio: "gio",
|
|
192
|
+
Pango: "Pango",
|
|
193
|
+
PangoCairo: "PangoCairo",
|
|
194
|
+
GdkPixbuf: "gdk-pixbuf",
|
|
195
|
+
Cairo: "cairo",
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
function getDocsBaseUrl(namespace: string | undefined): string {
|
|
199
|
+
if (!namespace) {
|
|
200
|
+
return "https://docs.gtk.org/gtk4";
|
|
201
|
+
}
|
|
202
|
+
const docsPath = NAMESPACE_TO_DOCS_PATH[namespace];
|
|
203
|
+
if (docsPath) {
|
|
204
|
+
return `https://docs.gtk.org/${docsPath}`;
|
|
205
|
+
}
|
|
206
|
+
return `https://docs.gtk.org/${namespace.toLowerCase()}`;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function convertHtmlImageElements(text: string, baseUrl: string): string {
|
|
210
|
+
let result = text;
|
|
211
|
+
|
|
212
|
+
result = result.replace(/<picture[^>]*>([\s\S]*?)<\/picture>/gi, (_, pictureContent: string) => {
|
|
213
|
+
const imgMatch = /<img[^>]*alt="([^"]*)"[^>]*src="([^"]*)"[^>]*\/?>/i.exec(pictureContent);
|
|
214
|
+
if (!imgMatch) {
|
|
215
|
+
const imgMatch2 = /<img[^>]*src="([^"]*)"[^>]*alt="([^"]*)"[^>]*\/?>/i.exec(pictureContent);
|
|
216
|
+
if (imgMatch2) {
|
|
217
|
+
const src = imgMatch2[1];
|
|
218
|
+
const alt = imgMatch2[2];
|
|
219
|
+
return ``;
|
|
220
|
+
}
|
|
221
|
+
return "";
|
|
222
|
+
}
|
|
223
|
+
const alt = imgMatch[1];
|
|
224
|
+
const src = imgMatch[2];
|
|
225
|
+
return ``;
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
result = result.replace(/<img[^>]*alt="([^"]*)"[^>]*src="([^"]*)"[^>]*\/?>/gi, (_, alt: string, src: string) => {
|
|
229
|
+
if (src.startsWith("http://") || src.startsWith("https://")) {
|
|
230
|
+
return ``;
|
|
231
|
+
}
|
|
232
|
+
return ``;
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
result = result.replace(/<img[^>]*src="([^"]*)"[^>]*alt="([^"]*)"[^>]*\/?>/gi, (_, src: string, alt: string) => {
|
|
236
|
+
if (src.startsWith("http://") || src.startsWith("https://")) {
|
|
237
|
+
return ``;
|
|
238
|
+
}
|
|
239
|
+
return ``;
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
result = result.replace(/<img[^>]*src="([^"]*)"[^>]*\/?>/gi, (_, src: string) => {
|
|
243
|
+
if (src.startsWith("http://") || src.startsWith("https://")) {
|
|
244
|
+
return ``;
|
|
245
|
+
}
|
|
246
|
+
return ``;
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
result = result.replace(/<source[^>]*\/?>/gi, "");
|
|
250
|
+
|
|
251
|
+
return result;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function convertMarkdownImageUrls(text: string, baseUrl: string): string {
|
|
255
|
+
return text.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, (match, alt: string, src: string) => {
|
|
256
|
+
if (src.startsWith("http://") || src.startsWith("https://")) {
|
|
257
|
+
return match;
|
|
258
|
+
}
|
|
259
|
+
return ``;
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function convertKbdElements(text: string): string {
|
|
264
|
+
return text.replace(/<kbd>([^<]*)<\/kbd>/gi, "`$1`");
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function stripHtmlLinks(text: string): string {
|
|
268
|
+
return text.replace(/\[([^\]]+)\]\([^)]+\.html[^)]*\)/gi, "$1");
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function convertAtAnnotations(text: string): string {
|
|
272
|
+
return text.replace(/(?<!\{)@([a-zA-Z_][a-zA-Z0-9_]*)\b(?!\s*\{)/g, "`$1`");
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function escapeXmlStyleTags(text: string): string {
|
|
276
|
+
return text.replace(/<(\/?)(child|object|property|signal|template|style|item|attribute)>/gi, "`<$1$2>`");
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function cleanupWhitespace(text: string): string {
|
|
280
|
+
let result = text.replace(/\n{3,}/g, "\n\n");
|
|
281
|
+
result = result.replace(/[ \t]+$/gm, "");
|
|
282
|
+
return result.trim();
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export interface SanitizeDocOptions {
|
|
286
|
+
escapeXmlTags?: boolean;
|
|
287
|
+
namespace?: string;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export function sanitizeDoc(doc: string, options: SanitizeDocOptions = {}): string {
|
|
291
|
+
let result = doc;
|
|
292
|
+
|
|
293
|
+
const baseUrl = getDocsBaseUrl(options.namespace);
|
|
294
|
+
result = convertHtmlImageElements(result, baseUrl);
|
|
295
|
+
result = convertMarkdownImageUrls(result, baseUrl);
|
|
296
|
+
result = convertKbdElements(result);
|
|
297
|
+
result = stripHtmlLinks(result);
|
|
298
|
+
result = convertGirLinks(result);
|
|
299
|
+
result = convertAtAnnotations(result);
|
|
300
|
+
|
|
301
|
+
if (options.escapeXmlTags) {
|
|
302
|
+
result = escapeXmlStyleTags(result);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
result = cleanupWhitespace(result);
|
|
306
|
+
|
|
307
|
+
return result;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export function formatDoc(doc: string | undefined, indent: string = "", options: SanitizeDocOptions = {}): string {
|
|
311
|
+
if (!doc) {
|
|
312
|
+
return "";
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const sanitized = sanitizeDoc(doc, options);
|
|
316
|
+
if (!sanitized) {
|
|
317
|
+
return "";
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const lines = sanitized.split("\n").map((line) => line.trim());
|
|
321
|
+
const firstLine = lines[0] ?? "";
|
|
322
|
+
|
|
323
|
+
if (lines.length === 1 && firstLine.length < 80) {
|
|
324
|
+
return `${indent}/** ${firstLine} */\n`;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const formattedLines = lines.map((line) => `${indent} * ${line}`);
|
|
328
|
+
return `${indent}/**\n${formattedLines.join("\n")}\n${indent} */\n`;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
interface DocParameter {
|
|
332
|
+
name: string;
|
|
333
|
+
doc: string | undefined;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export function formatMethodDoc(
|
|
337
|
+
doc: string | undefined,
|
|
338
|
+
params: DocParameter[],
|
|
339
|
+
indent: string = " ",
|
|
340
|
+
options: SanitizeDocOptions = {},
|
|
341
|
+
): string {
|
|
342
|
+
const sanitizedDoc = doc ? sanitizeDoc(doc, options) : undefined;
|
|
343
|
+
|
|
344
|
+
const hasDocumentation = sanitizedDoc || params.some((p) => p.doc);
|
|
345
|
+
if (!hasDocumentation) {
|
|
346
|
+
return "";
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const lines: string[] = [];
|
|
350
|
+
|
|
351
|
+
if (sanitizedDoc) {
|
|
352
|
+
for (const line of sanitizedDoc.split("\n")) {
|
|
353
|
+
lines.push(` * ${line.trim()}`);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
for (const param of params) {
|
|
358
|
+
if (param.doc && param.name && param.name !== "..." && param.name !== "") {
|
|
359
|
+
const sanitizedParamDoc = sanitizeDoc(param.doc, options);
|
|
360
|
+
const paramDocFirstLine = sanitizedParamDoc.split("\n")[0]?.trim() ?? "";
|
|
361
|
+
lines.push(` * @param ${param.name} - ${paramDocFirstLine}`);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if (lines.length === 0) {
|
|
366
|
+
return "";
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return `${indent}/**\n${indent}${lines.join(`\n${indent}`)}\n${indent} */\n`;
|
|
370
|
+
}
|
package/src/index.ts
CHANGED
package/src/parser.ts
CHANGED
|
@@ -186,18 +186,22 @@ export class GirParser {
|
|
|
186
186
|
}
|
|
187
187
|
return methods
|
|
188
188
|
.filter((method) => method["@_introspectable"] !== "0")
|
|
189
|
-
.map((method) =>
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
189
|
+
.map((method) => {
|
|
190
|
+
const returnValue = method["return-value"] as Record<string, unknown> | undefined;
|
|
191
|
+
return {
|
|
192
|
+
name: String(method["@_name"] ?? ""),
|
|
193
|
+
cIdentifier: String(method["@_c:identifier"] ?? ""),
|
|
194
|
+
returnType: this.parseReturnType(returnValue),
|
|
195
|
+
parameters: this.parseParameters(
|
|
196
|
+
(method.parameters && typeof method.parameters === "object" && method.parameters !== null
|
|
197
|
+
? method.parameters
|
|
198
|
+
: {}) as Record<string, unknown>,
|
|
199
|
+
),
|
|
200
|
+
throws: method["@_throws"] === "1",
|
|
201
|
+
doc: extractDoc(method),
|
|
202
|
+
returnDoc: returnValue ? extractDoc(returnValue) : undefined,
|
|
203
|
+
};
|
|
204
|
+
});
|
|
201
205
|
}
|
|
202
206
|
|
|
203
207
|
private parseConstructors(constructors: Record<string, unknown>[]): GirConstructor[] {
|
|
@@ -206,18 +210,22 @@ export class GirParser {
|
|
|
206
210
|
}
|
|
207
211
|
return constructors
|
|
208
212
|
.filter((ctor) => ctor["@_introspectable"] !== "0")
|
|
209
|
-
.map((ctor) =>
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
213
|
+
.map((ctor) => {
|
|
214
|
+
const returnValue = ctor["return-value"] as Record<string, unknown> | undefined;
|
|
215
|
+
return {
|
|
216
|
+
name: String(ctor["@_name"] ?? ""),
|
|
217
|
+
cIdentifier: String(ctor["@_c:identifier"] ?? ""),
|
|
218
|
+
returnType: this.parseReturnType(returnValue),
|
|
219
|
+
parameters: this.parseParameters(
|
|
220
|
+
(ctor.parameters && typeof ctor.parameters === "object" && ctor.parameters !== null
|
|
221
|
+
? ctor.parameters
|
|
222
|
+
: {}) as Record<string, unknown>,
|
|
223
|
+
),
|
|
224
|
+
throws: ctor["@_throws"] === "1",
|
|
225
|
+
doc: extractDoc(ctor),
|
|
226
|
+
returnDoc: returnValue ? extractDoc(returnValue) : undefined,
|
|
227
|
+
};
|
|
228
|
+
});
|
|
221
229
|
}
|
|
222
230
|
|
|
223
231
|
private parseFunctions(functions: Record<string, unknown>[]): GirFunction[] {
|
|
@@ -226,18 +234,22 @@ export class GirParser {
|
|
|
226
234
|
}
|
|
227
235
|
return functions
|
|
228
236
|
.filter((func) => func["@_introspectable"] !== "0")
|
|
229
|
-
.map((func) =>
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
237
|
+
.map((func) => {
|
|
238
|
+
const returnValue = func["return-value"] as Record<string, unknown> | undefined;
|
|
239
|
+
return {
|
|
240
|
+
name: String(func["@_name"] ?? ""),
|
|
241
|
+
cIdentifier: String(func["@_c:identifier"] ?? ""),
|
|
242
|
+
returnType: this.parseReturnType(returnValue),
|
|
243
|
+
parameters: this.parseParameters(
|
|
244
|
+
(func.parameters && typeof func.parameters === "object" && func.parameters !== null
|
|
245
|
+
? func.parameters
|
|
246
|
+
: {}) as Record<string, unknown>,
|
|
247
|
+
),
|
|
248
|
+
throws: func["@_throws"] === "1",
|
|
249
|
+
doc: extractDoc(func),
|
|
250
|
+
returnDoc: returnValue ? extractDoc(returnValue) : undefined,
|
|
251
|
+
};
|
|
252
|
+
});
|
|
241
253
|
}
|
|
242
254
|
|
|
243
255
|
private parseParameters(parametersNode: Record<string, unknown>): GirParameter[] {
|
package/src/types.ts
CHANGED
|
@@ -178,6 +178,8 @@ export type GirMethod = {
|
|
|
178
178
|
throws?: boolean;
|
|
179
179
|
/** Documentation for the method. */
|
|
180
180
|
doc?: string;
|
|
181
|
+
/** Documentation for the return value. */
|
|
182
|
+
returnDoc?: string;
|
|
181
183
|
};
|
|
182
184
|
|
|
183
185
|
/**
|
|
@@ -196,6 +198,8 @@ export type GirConstructor = {
|
|
|
196
198
|
throws?: boolean;
|
|
197
199
|
/** Documentation for the constructor. */
|
|
198
200
|
doc?: string;
|
|
201
|
+
/** Documentation for the return value. */
|
|
202
|
+
returnDoc?: string;
|
|
199
203
|
};
|
|
200
204
|
|
|
201
205
|
/**
|
|
@@ -214,6 +218,8 @@ export type GirFunction = {
|
|
|
214
218
|
throws?: boolean;
|
|
215
219
|
/** Documentation for the function. */
|
|
216
220
|
doc?: string;
|
|
221
|
+
/** Documentation for the return value. */
|
|
222
|
+
returnDoc?: string;
|
|
217
223
|
};
|
|
218
224
|
|
|
219
225
|
/**
|
|
@@ -344,6 +350,10 @@ export type FfiTypeDescriptor = {
|
|
|
344
350
|
borrowed?: boolean;
|
|
345
351
|
/** Inner type for ref types (as descriptor) or boxed types (as GLib type name string). */
|
|
346
352
|
innerType?: FfiTypeDescriptor | string;
|
|
353
|
+
/** Library name for boxed types that need dynamic type lookup. */
|
|
354
|
+
lib?: string;
|
|
355
|
+
/** Explicit get_type function name for boxed types (when naive transformation doesn't work). */
|
|
356
|
+
getTypeFn?: string;
|
|
347
357
|
/** Item type for array types. */
|
|
348
358
|
itemType?: FfiTypeDescriptor;
|
|
349
359
|
/** List type for arrays (glist, gslist) - indicates native GList/GSList iteration. */
|
|
@@ -414,6 +424,8 @@ export type RegisteredType = {
|
|
|
414
424
|
namespace: string;
|
|
415
425
|
transformedName: string;
|
|
416
426
|
glibTypeName?: string;
|
|
427
|
+
sharedLibrary?: string;
|
|
428
|
+
glibGetType?: string;
|
|
417
429
|
};
|
|
418
430
|
|
|
419
431
|
const CLASS_RENAMES = new Map<string, string>([["Error", "GError"]]);
|
|
@@ -441,7 +453,7 @@ export class TypeRegistry {
|
|
|
441
453
|
* @param namespace - The namespace containing the class
|
|
442
454
|
* @param name - The class name
|
|
443
455
|
*/
|
|
444
|
-
|
|
456
|
+
registerNativeClass(namespace: string, name: string): void {
|
|
445
457
|
const transformedName = normalizeTypeName(name, namespace);
|
|
446
458
|
this.types.set(`${namespace}.${name}`, {
|
|
447
459
|
kind: "class",
|
|
@@ -486,8 +498,16 @@ export class TypeRegistry {
|
|
|
486
498
|
* @param namespace - The namespace containing the record
|
|
487
499
|
* @param name - The record name
|
|
488
500
|
* @param glibTypeName - Optional GLib type name for boxed type handling
|
|
501
|
+
* @param sharedLibrary - The shared library containing this record's type
|
|
502
|
+
* @param glibGetType - The GLib get_type function name
|
|
489
503
|
*/
|
|
490
|
-
registerRecord(
|
|
504
|
+
registerRecord(
|
|
505
|
+
namespace: string,
|
|
506
|
+
name: string,
|
|
507
|
+
glibTypeName?: string,
|
|
508
|
+
sharedLibrary?: string,
|
|
509
|
+
glibGetType?: string,
|
|
510
|
+
): void {
|
|
491
511
|
const transformedName = normalizeTypeName(name, namespace);
|
|
492
512
|
this.types.set(`${namespace}.${name}`, {
|
|
493
513
|
kind: "record",
|
|
@@ -495,6 +515,8 @@ export class TypeRegistry {
|
|
|
495
515
|
namespace,
|
|
496
516
|
transformedName,
|
|
497
517
|
glibTypeName,
|
|
518
|
+
sharedLibrary,
|
|
519
|
+
glibGetType,
|
|
498
520
|
});
|
|
499
521
|
}
|
|
500
522
|
|
|
@@ -557,7 +579,7 @@ export class TypeRegistry {
|
|
|
557
579
|
const registry = new TypeRegistry();
|
|
558
580
|
for (const ns of namespaces) {
|
|
559
581
|
for (const cls of ns.classes) {
|
|
560
|
-
registry.
|
|
582
|
+
registry.registerNativeClass(ns.name, cls.name);
|
|
561
583
|
}
|
|
562
584
|
for (const iface of ns.interfaces) {
|
|
563
585
|
registry.registerInterface(ns.name, iface.name);
|
|
@@ -570,7 +592,13 @@ export class TypeRegistry {
|
|
|
570
592
|
}
|
|
571
593
|
for (const record of ns.records) {
|
|
572
594
|
if (record.glibTypeName && !record.disguised) {
|
|
573
|
-
registry.registerRecord(
|
|
595
|
+
registry.registerRecord(
|
|
596
|
+
ns.name,
|
|
597
|
+
record.name,
|
|
598
|
+
record.glibTypeName,
|
|
599
|
+
ns.sharedLibrary,
|
|
600
|
+
record.glibGetType,
|
|
601
|
+
);
|
|
574
602
|
}
|
|
575
603
|
}
|
|
576
604
|
for (const callback of ns.callbacks) {
|
|
@@ -934,6 +962,8 @@ export class TypeMapper {
|
|
|
934
962
|
type: "boxed",
|
|
935
963
|
borrowed: isReturn,
|
|
936
964
|
innerType: registered.glibTypeName ?? registered.transformedName,
|
|
965
|
+
lib: registered.sharedLibrary,
|
|
966
|
+
getTypeFn: registered.glibGetType,
|
|
937
967
|
},
|
|
938
968
|
externalType,
|
|
939
969
|
kind: registered.kind,
|
|
@@ -1023,6 +1053,8 @@ export class TypeMapper {
|
|
|
1023
1053
|
type: "boxed",
|
|
1024
1054
|
borrowed: isReturn,
|
|
1025
1055
|
innerType: registered.glibTypeName ?? registered.transformedName,
|
|
1056
|
+
lib: registered.sharedLibrary,
|
|
1057
|
+
getTypeFn: registered.glibGetType,
|
|
1026
1058
|
},
|
|
1027
1059
|
externalType: isExternal ? externalType : undefined,
|
|
1028
1060
|
};
|
|
@@ -1081,6 +1113,8 @@ export class TypeMapper {
|
|
|
1081
1113
|
type: "boxed",
|
|
1082
1114
|
borrowed: isReturn,
|
|
1083
1115
|
innerType: registered.glibTypeName ?? registered.transformedName,
|
|
1116
|
+
lib: registered.sharedLibrary,
|
|
1117
|
+
getTypeFn: registered.glibGetType,
|
|
1084
1118
|
},
|
|
1085
1119
|
externalType,
|
|
1086
1120
|
kind: registered.kind,
|
|
@@ -1182,20 +1216,26 @@ export class TypeMapper {
|
|
|
1182
1216
|
|
|
1183
1217
|
if (param.type.name === "Gtk.DrawingAreaDrawFunc" || param.type.name === "DrawingAreaDrawFunc") {
|
|
1184
1218
|
this.onExternalTypeUsed?.({
|
|
1185
|
-
namespace: "
|
|
1219
|
+
namespace: "cairo",
|
|
1186
1220
|
name: "Context",
|
|
1187
1221
|
transformedName: "Context",
|
|
1188
1222
|
kind: "record",
|
|
1189
1223
|
});
|
|
1190
1224
|
this.onSameNamespaceClassUsed?.("DrawingArea", "DrawingArea");
|
|
1191
1225
|
return {
|
|
1192
|
-
ts: "(self: DrawingArea, cr:
|
|
1226
|
+
ts: "(self: DrawingArea, cr: cairo.Context, width: number, height: number) => void",
|
|
1193
1227
|
ffi: {
|
|
1194
1228
|
type: "callback",
|
|
1195
1229
|
trampoline: "drawFunc",
|
|
1196
1230
|
argTypes: [
|
|
1197
1231
|
{ type: "gobject", borrowed: true },
|
|
1198
|
-
{
|
|
1232
|
+
{
|
|
1233
|
+
type: "boxed",
|
|
1234
|
+
borrowed: true,
|
|
1235
|
+
innerType: "CairoContext",
|
|
1236
|
+
lib: "libcairo-gobject.so.2",
|
|
1237
|
+
getTypeFn: "cairo_gobject_context_get_type",
|
|
1238
|
+
},
|
|
1199
1239
|
{ type: "int", size: 32, unsigned: false },
|
|
1200
1240
|
{ type: "int", size: 32, unsigned: false },
|
|
1201
1241
|
],
|