@gtkx/gir 0.1.18 → 0.1.20
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/parser.ts +28 -1
- package/src/types.ts +119 -37
package/package.json
CHANGED
package/src/parser.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { XMLParser } from "fast-xml-parser";
|
|
2
2
|
import type {
|
|
3
|
+
GirCallback,
|
|
3
4
|
GirClass,
|
|
4
5
|
GirConstructor,
|
|
5
6
|
GirEnumeration,
|
|
@@ -23,6 +24,7 @@ const ARRAY_ELEMENT_PATHS = new Set<string>([
|
|
|
23
24
|
"namespace.enumeration",
|
|
24
25
|
"namespace.bitfield",
|
|
25
26
|
"namespace.record",
|
|
27
|
+
"namespace.callback",
|
|
26
28
|
"namespace.class.method",
|
|
27
29
|
"namespace.class.constructor",
|
|
28
30
|
"namespace.class.function",
|
|
@@ -49,6 +51,7 @@ const ARRAY_ELEMENT_PATHS = new Set<string>([
|
|
|
49
51
|
"namespace.record.method.parameters.parameter",
|
|
50
52
|
"namespace.record.constructor.parameters.parameter",
|
|
51
53
|
"namespace.record.function.parameters.parameter",
|
|
54
|
+
"namespace.callback.parameters.parameter",
|
|
52
55
|
]);
|
|
53
56
|
|
|
54
57
|
const extractDoc = (node: Record<string, unknown>): string | undefined => {
|
|
@@ -105,15 +108,38 @@ export class GirParser {
|
|
|
105
108
|
enumerations: this.parseEnumerations(namespace.enumeration ?? []),
|
|
106
109
|
bitfields: this.parseEnumerations(namespace.bitfield ?? []),
|
|
107
110
|
records: this.parseRecords(namespace.record ?? []),
|
|
111
|
+
callbacks: this.parseCallbacks(namespace.callback ?? []),
|
|
108
112
|
};
|
|
109
113
|
}
|
|
110
114
|
|
|
115
|
+
private parseCallbacks(callbacks: Record<string, unknown>[]): GirCallback[] {
|
|
116
|
+
if (!callbacks || !Array.isArray(callbacks)) {
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
return callbacks
|
|
120
|
+
.filter((cb) => cb["@_introspectable"] !== "0")
|
|
121
|
+
.map((cb) => ({
|
|
122
|
+
name: String(cb["@_name"] ?? ""),
|
|
123
|
+
cType: String(cb["@_c:type"] ?? ""),
|
|
124
|
+
returnType: this.parseReturnType(cb["return-value"] as Record<string, unknown> | undefined),
|
|
125
|
+
parameters: this.parseParameters(
|
|
126
|
+
(cb.parameters && typeof cb.parameters === "object" && cb.parameters !== null
|
|
127
|
+
? cb.parameters
|
|
128
|
+
: {}) as Record<string, unknown>,
|
|
129
|
+
),
|
|
130
|
+
doc: extractDoc(cb),
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
|
|
111
134
|
private parseClasses(classes: Record<string, unknown>[]): GirClass[] {
|
|
112
135
|
return classes.map((cls) => ({
|
|
113
136
|
name: String(cls["@_name"] ?? ""),
|
|
114
137
|
cType: String(cls["@_c:type"] ?? cls["@_glib:type-name"] ?? ""),
|
|
115
138
|
parent: String(cls["@_parent"] ?? ""),
|
|
116
139
|
abstract: cls["@_abstract"] === "1",
|
|
140
|
+
glibTypeName: cls["@_glib:type-name"] ? String(cls["@_glib:type-name"]) : undefined,
|
|
141
|
+
glibGetType: cls["@_glib:get-type"] ? String(cls["@_glib:get-type"]) : undefined,
|
|
142
|
+
cSymbolPrefix: cls["@_c:symbol-prefix"] ? String(cls["@_c:symbol-prefix"]) : undefined,
|
|
117
143
|
implements: this.parseImplements(
|
|
118
144
|
cls.implements as Record<string, unknown>[] | Record<string, unknown> | undefined,
|
|
119
145
|
),
|
|
@@ -193,6 +219,7 @@ export class GirParser {
|
|
|
193
219
|
? ctor.parameters
|
|
194
220
|
: {}) as Record<string, unknown>,
|
|
195
221
|
),
|
|
222
|
+
throws: ctor["@_throws"] === "1",
|
|
196
223
|
doc: extractDoc(ctor),
|
|
197
224
|
}));
|
|
198
225
|
}
|
|
@@ -265,7 +292,7 @@ export class GirParser {
|
|
|
265
292
|
const typeName = typeNode["@_name"] ? String(typeNode["@_name"]) : undefined;
|
|
266
293
|
|
|
267
294
|
if (typeName === "GLib.List" || typeName === "GLib.SList") {
|
|
268
|
-
const innerType = typeNode.type as Record<string, unknown> | undefined;
|
|
295
|
+
const innerType = (typeNode.type ?? typeNode.array) as Record<string, unknown> | undefined;
|
|
269
296
|
return {
|
|
270
297
|
name: "array",
|
|
271
298
|
cType: typeNode["@_c:type"] ? String(typeNode["@_c:type"]) : undefined,
|
package/src/types.ts
CHANGED
|
@@ -22,10 +22,28 @@ export interface GirNamespace {
|
|
|
22
22
|
bitfields: GirEnumeration[];
|
|
23
23
|
/** All records (structs) defined in this namespace. */
|
|
24
24
|
records: GirRecord[];
|
|
25
|
+
/** All callback types defined in this namespace. */
|
|
26
|
+
callbacks: GirCallback[];
|
|
25
27
|
/** Documentation for the namespace. */
|
|
26
28
|
doc?: string;
|
|
27
29
|
}
|
|
28
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Represents a GIR callback type definition.
|
|
33
|
+
*/
|
|
34
|
+
export interface GirCallback {
|
|
35
|
+
/** The callback name. */
|
|
36
|
+
name: string;
|
|
37
|
+
/** The C type name. */
|
|
38
|
+
cType: string;
|
|
39
|
+
/** The return type. */
|
|
40
|
+
returnType: GirType;
|
|
41
|
+
/** The callback parameters. */
|
|
42
|
+
parameters: GirParameter[];
|
|
43
|
+
/** Documentation for the callback. */
|
|
44
|
+
doc?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
29
47
|
/**
|
|
30
48
|
* Represents a GIR interface definition.
|
|
31
49
|
*/
|
|
@@ -56,6 +74,12 @@ export interface GirClass {
|
|
|
56
74
|
parent?: string;
|
|
57
75
|
/** Whether this is an abstract class. */
|
|
58
76
|
abstract?: boolean;
|
|
77
|
+
/** The GLib type name. */
|
|
78
|
+
glibTypeName?: string;
|
|
79
|
+
/** The GLib get-type function. */
|
|
80
|
+
glibGetType?: string;
|
|
81
|
+
/** The C symbol prefix for this class. */
|
|
82
|
+
cSymbolPrefix?: string;
|
|
59
83
|
/** List of interface names this class implements. */
|
|
60
84
|
implements: string[];
|
|
61
85
|
/** Methods defined on this class. */
|
|
@@ -148,6 +172,8 @@ export interface GirConstructor {
|
|
|
148
172
|
returnType: GirType;
|
|
149
173
|
/** The constructor parameters. */
|
|
150
174
|
parameters: GirParameter[];
|
|
175
|
+
/** Whether this constructor can throw a GError. */
|
|
176
|
+
throws?: boolean;
|
|
151
177
|
/** Documentation for the constructor. */
|
|
152
178
|
doc?: string;
|
|
153
179
|
}
|
|
@@ -354,7 +380,7 @@ export const registerEnumsFromNamespace = (typeMapper: TypeMapper, namespace: Gi
|
|
|
354
380
|
|
|
355
381
|
type TypeMapping = { ts: string; ffi: FfiTypeDescriptor };
|
|
356
382
|
|
|
357
|
-
export type TypeKind = "class" | "interface" | "enum" | "record";
|
|
383
|
+
export type TypeKind = "class" | "interface" | "enum" | "record" | "callback";
|
|
358
384
|
|
|
359
385
|
export interface RegisteredType {
|
|
360
386
|
kind: TypeKind;
|
|
@@ -418,6 +444,16 @@ export class TypeRegistry {
|
|
|
418
444
|
});
|
|
419
445
|
}
|
|
420
446
|
|
|
447
|
+
registerCallback(namespace: string, name: string): void {
|
|
448
|
+
const transformedName = toPascalCase(name);
|
|
449
|
+
this.types.set(`${namespace}.${name}`, {
|
|
450
|
+
kind: "callback",
|
|
451
|
+
name,
|
|
452
|
+
namespace,
|
|
453
|
+
transformedName,
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
|
|
421
457
|
resolve(qualifiedName: string): RegisteredType | undefined {
|
|
422
458
|
return this.types.get(qualifiedName);
|
|
423
459
|
}
|
|
@@ -445,16 +481,13 @@ export class TypeRegistry {
|
|
|
445
481
|
registry.registerEnum(ns.name, bitfield.name);
|
|
446
482
|
}
|
|
447
483
|
for (const record of ns.records) {
|
|
448
|
-
if (
|
|
449
|
-
record.glibTypeName &&
|
|
450
|
-
!record.disguised &&
|
|
451
|
-
!record.name.endsWith("Class") &&
|
|
452
|
-
!record.name.endsWith("Private") &&
|
|
453
|
-
!record.name.endsWith("Iface")
|
|
454
|
-
) {
|
|
484
|
+
if (record.glibTypeName && !record.disguised) {
|
|
455
485
|
registry.registerRecord(ns.name, record.name, record.glibTypeName);
|
|
456
486
|
}
|
|
457
487
|
}
|
|
488
|
+
for (const callback of ns.callbacks) {
|
|
489
|
+
registry.registerCallback(ns.name, callback.name);
|
|
490
|
+
}
|
|
458
491
|
}
|
|
459
492
|
return registry;
|
|
460
493
|
}
|
|
@@ -462,6 +495,65 @@ export class TypeRegistry {
|
|
|
462
495
|
|
|
463
496
|
const STRING_TYPES = new Set(["utf8", "filename"]);
|
|
464
497
|
|
|
498
|
+
const POINTER_TYPE: TypeMapping = { ts: "number", ffi: { type: "int", size: 64, unsigned: true } };
|
|
499
|
+
|
|
500
|
+
const C_TYPE_MAP = new Map<string, TypeMapping>([
|
|
501
|
+
["void", { ts: "void", ffi: { type: "undefined" } }],
|
|
502
|
+
["gboolean", { ts: "boolean", ffi: { type: "boolean" } }],
|
|
503
|
+
["gchar", { ts: "number", ffi: { type: "int", size: 8, unsigned: false } }],
|
|
504
|
+
["guchar", { ts: "number", ffi: { type: "int", size: 8, unsigned: true } }],
|
|
505
|
+
["gint", { ts: "number", ffi: { type: "int", size: 32, unsigned: false } }],
|
|
506
|
+
["guint", { ts: "number", ffi: { type: "int", size: 32, unsigned: true } }],
|
|
507
|
+
["gshort", { ts: "number", ffi: { type: "int", size: 16, unsigned: false } }],
|
|
508
|
+
["gushort", { ts: "number", ffi: { type: "int", size: 16, unsigned: true } }],
|
|
509
|
+
["glong", { ts: "number", ffi: { type: "int", size: 64, unsigned: false } }],
|
|
510
|
+
["gulong", { ts: "number", ffi: { type: "int", size: 64, unsigned: true } }],
|
|
511
|
+
["gint8", { ts: "number", ffi: { type: "int", size: 8, unsigned: false } }],
|
|
512
|
+
["guint8", { ts: "number", ffi: { type: "int", size: 8, unsigned: true } }],
|
|
513
|
+
["gint16", { ts: "number", ffi: { type: "int", size: 16, unsigned: false } }],
|
|
514
|
+
["guint16", { ts: "number", ffi: { type: "int", size: 16, unsigned: true } }],
|
|
515
|
+
["gint32", { ts: "number", ffi: { type: "int", size: 32, unsigned: false } }],
|
|
516
|
+
["guint32", { ts: "number", ffi: { type: "int", size: 32, unsigned: true } }],
|
|
517
|
+
["gint64", { ts: "number", ffi: { type: "int", size: 64, unsigned: false } }],
|
|
518
|
+
["guint64", { ts: "number", ffi: { type: "int", size: 64, unsigned: true } }],
|
|
519
|
+
["gfloat", { ts: "number", ffi: { type: "float", size: 32 } }],
|
|
520
|
+
["gdouble", { ts: "number", ffi: { type: "float", size: 64 } }],
|
|
521
|
+
["gsize", { ts: "number", ffi: { type: "int", size: 64, unsigned: true } }],
|
|
522
|
+
["gssize", { ts: "number", ffi: { type: "int", size: 64, unsigned: false } }],
|
|
523
|
+
["goffset", { ts: "number", ffi: { type: "int", size: 64, unsigned: false } }],
|
|
524
|
+
["int", { ts: "number", ffi: { type: "int", size: 32, unsigned: false } }],
|
|
525
|
+
["unsigned int", { ts: "number", ffi: { type: "int", size: 32, unsigned: true } }],
|
|
526
|
+
["long", { ts: "number", ffi: { type: "int", size: 64, unsigned: false } }],
|
|
527
|
+
["unsigned long", { ts: "number", ffi: { type: "int", size: 64, unsigned: true } }],
|
|
528
|
+
["double", { ts: "number", ffi: { type: "float", size: 64 } }],
|
|
529
|
+
["float", { ts: "number", ffi: { type: "float", size: 32 } }],
|
|
530
|
+
["size_t", { ts: "number", ffi: { type: "int", size: 64, unsigned: true } }],
|
|
531
|
+
["ssize_t", { ts: "number", ffi: { type: "int", size: 64, unsigned: false } }],
|
|
532
|
+
["GType", { ts: "number", ffi: { type: "int", size: 64, unsigned: true } }],
|
|
533
|
+
["GQuark", { ts: "number", ffi: { type: "int", size: 32, unsigned: true } }],
|
|
534
|
+
]);
|
|
535
|
+
|
|
536
|
+
const mapCType = (cType: string | undefined): TypeMapping => {
|
|
537
|
+
if (!cType) {
|
|
538
|
+
return POINTER_TYPE;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
if (cType.endsWith("*")) {
|
|
542
|
+
return POINTER_TYPE;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
const mapped = C_TYPE_MAP.get(cType);
|
|
546
|
+
if (mapped) {
|
|
547
|
+
return mapped;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
if (cType.startsWith("const ")) {
|
|
551
|
+
return mapCType(cType.slice(6));
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
return POINTER_TYPE;
|
|
555
|
+
};
|
|
556
|
+
|
|
465
557
|
const BASIC_TYPE_MAP = new Map<string, TypeMapping>([
|
|
466
558
|
["gboolean", { ts: "boolean", ffi: { type: "boolean" } }],
|
|
467
559
|
["gchar", { ts: "number", ffi: { type: "int", size: 8, unsigned: false } }],
|
|
@@ -522,16 +614,6 @@ const BASIC_TYPE_MAP = new Map<string, TypeMapping>([
|
|
|
522
614
|
["FreeFunc", { ts: "number", ffi: { type: "int", size: 64, unsigned: true } }],
|
|
523
615
|
]);
|
|
524
616
|
|
|
525
|
-
const LIBRARY_MAP: Record<string, string> = {
|
|
526
|
-
Gtk: "libgtk-4.so.1",
|
|
527
|
-
GObject: "libgobject-2.0.so.0",
|
|
528
|
-
GLib: "libglib-2.0.so.0",
|
|
529
|
-
Gio: "libgio-2.0.so.0",
|
|
530
|
-
GdkPixbuf: "libgdk_pixbuf-2.0.so.0",
|
|
531
|
-
Pango: "libpango-1.0.so.0",
|
|
532
|
-
Cairo: "libcairo.so.2",
|
|
533
|
-
};
|
|
534
|
-
|
|
535
617
|
export interface ExternalTypeUsage {
|
|
536
618
|
namespace: string;
|
|
537
619
|
name: string;
|
|
@@ -767,6 +849,9 @@ export class TypeMapper {
|
|
|
767
849
|
externalType: isExternal ? externalType : undefined,
|
|
768
850
|
};
|
|
769
851
|
}
|
|
852
|
+
if (registered.kind === "callback") {
|
|
853
|
+
return POINTER_TYPE;
|
|
854
|
+
}
|
|
770
855
|
return {
|
|
771
856
|
ts: qualifiedName,
|
|
772
857
|
ffi: { type: "gobject", borrowed: isReturn },
|
|
@@ -775,10 +860,7 @@ export class TypeMapper {
|
|
|
775
860
|
};
|
|
776
861
|
}
|
|
777
862
|
}
|
|
778
|
-
return
|
|
779
|
-
ts: "unknown",
|
|
780
|
-
ffi: { type: "gobject", borrowed: isReturn },
|
|
781
|
-
};
|
|
863
|
+
return mapCType(girType.cType);
|
|
782
864
|
}
|
|
783
865
|
|
|
784
866
|
if (this.typeRegistry && this.currentNamespace) {
|
|
@@ -820,6 +902,9 @@ export class TypeMapper {
|
|
|
820
902
|
kind: registered.kind,
|
|
821
903
|
};
|
|
822
904
|
}
|
|
905
|
+
if (registered.kind === "callback") {
|
|
906
|
+
return POINTER_TYPE;
|
|
907
|
+
}
|
|
823
908
|
return {
|
|
824
909
|
ts: qualifiedName,
|
|
825
910
|
ffi: { type: "gobject", borrowed: isReturn },
|
|
@@ -829,10 +914,17 @@ export class TypeMapper {
|
|
|
829
914
|
}
|
|
830
915
|
}
|
|
831
916
|
|
|
832
|
-
return
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
917
|
+
return mapCType(girType.cType);
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
isCallback(typeName: string): boolean {
|
|
921
|
+
if (this.typeRegistry) {
|
|
922
|
+
const resolved = this.currentNamespace
|
|
923
|
+
? this.typeRegistry.resolveInNamespace(typeName, this.currentNamespace)
|
|
924
|
+
: this.typeRegistry.resolve(typeName);
|
|
925
|
+
return resolved?.kind === "callback";
|
|
926
|
+
}
|
|
927
|
+
return false;
|
|
836
928
|
}
|
|
837
929
|
|
|
838
930
|
/**
|
|
@@ -901,7 +993,7 @@ export class TypeMapper {
|
|
|
901
993
|
};
|
|
902
994
|
}
|
|
903
995
|
|
|
904
|
-
if (param.type.name === "GLib.Closure" || param.type.name
|
|
996
|
+
if (param.type.name === "GLib.Closure" || this.isCallback(param.type.name)) {
|
|
905
997
|
return {
|
|
906
998
|
ts: "(...args: unknown[]) => unknown",
|
|
907
999
|
ffi: { type: "callback" },
|
|
@@ -920,7 +1012,6 @@ export class TypeMapper {
|
|
|
920
1012
|
*/
|
|
921
1013
|
isClosureTarget(paramIndex: number, allParams: GirParameter[]): boolean {
|
|
922
1014
|
const trampolineCallbacks = ["Gio.AsyncReadyCallback", "Gtk.DrawingAreaDrawFunc", "DrawingAreaDrawFunc"];
|
|
923
|
-
// Check if this param is a closure (user_data) or destroy target for a trampoline callback
|
|
924
1015
|
return allParams.some(
|
|
925
1016
|
(p) => trampolineCallbacks.includes(p.type.name) && (p.closure === paramIndex || p.destroy === paramIndex),
|
|
926
1017
|
);
|
|
@@ -934,13 +1025,4 @@ export class TypeMapper {
|
|
|
934
1025
|
isNullable(param: GirParameter): boolean {
|
|
935
1026
|
return param.nullable === true || param.optional === true;
|
|
936
1027
|
}
|
|
937
|
-
|
|
938
|
-
/**
|
|
939
|
-
* Gets the shared library name for a namespace.
|
|
940
|
-
* @param namespace - The namespace name
|
|
941
|
-
* @returns The shared library file name
|
|
942
|
-
*/
|
|
943
|
-
getLibraryName(namespace: string): string {
|
|
944
|
-
return LIBRARY_MAP[namespace] ?? `lib${namespace.toLowerCase()}.so`;
|
|
945
|
-
}
|
|
946
1028
|
}
|