@gtkx/gir 0.10.5 → 0.11.1

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,10 +1,10 @@
1
1
  /**
2
- * GObject Introspection XML (GIR) parser module.
2
+ * GObject Introspection XML (GIR) parser.
3
3
  *
4
4
  * Parses GIR files to extract type information for GTK/GLib libraries.
5
- * Used by the code generator to create TypeScript bindings.
5
+ * Outputs raw GIR types that are then normalized by the normalizer.
6
6
  *
7
- * @packageDocumentation
7
+ * @internal
8
8
  */
9
9
  import { XMLParser } from "fast-xml-parser";
10
10
  const ARRAY_ELEMENT_PATHS = new Set([
@@ -57,26 +57,9 @@ const ensureArray = (value) => Array.isArray(value) ? value : [];
57
57
  /**
58
58
  * Parser for GObject Introspection XML (GIR) files.
59
59
  *
60
- * Converts GIR XML into structured TypeScript objects that can be used
61
- * for code generation. Handles all GIR elements including classes,
62
- * interfaces, functions, signals, properties, and type information.
63
- *
64
- * @example
65
- * ```tsx
66
- * import { GirParser } from "@gtkx/gir";
67
- * import { readFileSync } from "fs";
68
- *
69
- * const parser = new GirParser();
70
- * const xml = readFileSync("Gtk-4.0.gir", "utf-8");
71
- * const namespace = parser.parse(xml);
72
- *
73
- * console.log(namespace.name); // "Gtk"
74
- * console.log(namespace.classes.length); // Number of GTK classes
75
- * ```
76
- *
77
- * @see {@link GirNamespace} for the parsed output structure
60
+ * Converts GIR XML into raw TypeScript objects.
78
61
  */
79
- export class GirParser {
62
+ export class RawGirParser {
80
63
  parser;
81
64
  constructor() {
82
65
  this.parser = new XMLParser({
@@ -90,26 +73,7 @@ export class GirParser {
90
73
  });
91
74
  }
92
75
  /**
93
- * Parses a GIR XML string into a structured namespace object.
94
- *
95
- * @param girXml - The raw XML content of a GIR file
96
- * @returns A parsed namespace containing all type information
97
- * @throws Error if the XML is missing required repository or namespace elements
98
- *
99
- * @example
100
- * ```tsx
101
- * const namespace = parser.parse(girXml);
102
- *
103
- * // Access parsed classes
104
- * for (const cls of namespace.classes) {
105
- * console.log(`Class: ${cls.name}, Parent: ${cls.parent}`);
106
- * }
107
- *
108
- * // Access parsed functions
109
- * for (const fn of namespace.functions) {
110
- * console.log(`Function: ${fn.name} -> ${fn.returnType.name}`);
111
- * }
112
- * ```
76
+ * Parses a GIR XML string into a raw namespace object.
113
77
  */
114
78
  parse(girXml) {
115
79
  const parsed = this.parser.parse(girXml);
@@ -153,7 +117,7 @@ export class GirParser {
153
117
  return classes.map((cls) => ({
154
118
  name: String(cls["@_name"] ?? ""),
155
119
  cType: String(cls["@_c:type"] ?? cls["@_glib:type-name"] ?? ""),
156
- parent: String(cls["@_parent"] ?? ""),
120
+ parent: cls["@_parent"] ? String(cls["@_parent"]) : undefined,
157
121
  abstract: cls["@_abstract"] === "1",
158
122
  glibTypeName: cls["@_glib:type-name"] ? String(cls["@_glib:type-name"]) : undefined,
159
123
  glibGetType: cls["@_glib:get-type"] ? String(cls["@_glib:get-type"]) : undefined,
@@ -202,6 +166,7 @@ export class GirParser {
202
166
  .filter((method) => method["@_introspectable"] !== "0")
203
167
  .map((method) => {
204
168
  const returnValue = method["return-value"];
169
+ const finishFunc = method["@_glib:finish-func"];
205
170
  return {
206
171
  name: String(method["@_name"] ?? ""),
207
172
  cIdentifier: String(method["@_c:identifier"] ?? ""),
@@ -212,6 +177,7 @@ export class GirParser {
212
177
  throws: method["@_throws"] === "1",
213
178
  doc: extractDoc(method),
214
179
  returnDoc: returnValue ? extractDoc(returnValue) : undefined,
180
+ finishFunc: finishFunc || undefined,
215
181
  };
216
182
  });
217
183
  }
@@ -304,20 +270,13 @@ export class GirParser {
304
270
  return { name: "void" };
305
271
  }
306
272
  const typeName = typeNode["@_name"] ? String(typeNode["@_name"]) : undefined;
307
- if (typeName === "GLib.List" || typeName === "GLib.SList") {
308
- const innerType = (typeNode.type ?? typeNode.array);
309
- return {
310
- name: "array",
311
- cType: typeNode["@_c:type"] ? String(typeNode["@_c:type"]) : undefined,
312
- isArray: true,
313
- elementType: innerType ? this.parseType(innerType) : undefined,
314
- };
273
+ const cType = typeNode["@_c:type"] ? String(typeNode["@_c:type"]) : undefined;
274
+ const containerResult = this.parseGLibContainerType(typeName, typeNode, cType);
275
+ if (containerResult) {
276
+ return containerResult;
315
277
  }
316
278
  if (typeName) {
317
- return {
318
- name: typeName,
319
- cType: typeNode["@_c:type"] ? String(typeNode["@_c:type"]) : undefined,
320
- };
279
+ return { name: typeName, cType };
321
280
  }
322
281
  const isArrayNode = typeNode.type ||
323
282
  typeNode["@_zero-terminated"] !== undefined ||
@@ -332,6 +291,56 @@ export class GirParser {
332
291
  }
333
292
  return { name: "void" };
334
293
  }
294
+ extractTypeParameters(typeNode) {
295
+ const types = [];
296
+ const typeChildren = typeNode.type;
297
+ if (Array.isArray(typeChildren)) {
298
+ for (const child of typeChildren) {
299
+ types.push(this.parseType(child));
300
+ }
301
+ }
302
+ else if (typeChildren) {
303
+ types.push(this.parseType(typeChildren));
304
+ }
305
+ return types;
306
+ }
307
+ parseGLibContainerType(typeName, typeNode, cType) {
308
+ if (typeName === "GLib.HashTable") {
309
+ const typeParams = this.extractTypeParameters(typeNode);
310
+ return {
311
+ name: "GLib.HashTable",
312
+ cType,
313
+ isArray: false,
314
+ containerType: "ghashtable",
315
+ typeParameters: typeParams.length >= 2 ? typeParams : undefined,
316
+ elementType: typeParams[1],
317
+ };
318
+ }
319
+ if (typeName === "GLib.PtrArray" || typeName === "GLib.Array") {
320
+ const typeParams = this.extractTypeParameters(typeNode);
321
+ return {
322
+ name: typeName,
323
+ cType,
324
+ isArray: true,
325
+ containerType: (typeName === "GLib.PtrArray" ? "gptrarray" : "garray"),
326
+ typeParameters: typeParams.length > 0 ? typeParams : undefined,
327
+ elementType: typeParams[0],
328
+ };
329
+ }
330
+ if (typeName === "GLib.List" || typeName === "GLib.SList") {
331
+ const innerType = (typeNode.type ?? typeNode.array);
332
+ const elementType = innerType ? this.parseType(innerType) : undefined;
333
+ return {
334
+ name: "array",
335
+ cType,
336
+ isArray: true,
337
+ containerType: (typeName === "GLib.List" ? "glist" : "gslist"),
338
+ typeParameters: elementType ? [elementType] : undefined,
339
+ elementType,
340
+ };
341
+ }
342
+ return null;
343
+ }
335
344
  parseProperties(properties) {
336
345
  if (!properties || !Array.isArray(properties)) {
337
346
  return [];
@@ -379,6 +388,9 @@ export class GirParser {
379
388
  disguised: record["@_disguised"] === "1",
380
389
  glibTypeName: record["@_glib:type-name"] ? String(record["@_glib:type-name"]) : undefined,
381
390
  glibGetType: record["@_glib:get-type"] ? String(record["@_glib:get-type"]) : undefined,
391
+ isGtypeStructFor: record["@_glib:is-gtype-struct-for"]
392
+ ? String(record["@_glib:is-gtype-struct-for"])
393
+ : undefined,
382
394
  fields: this.parseFields(ensureArray(record.field)),
383
395
  methods: this.parseMethods(ensureArray(record.method)),
384
396
  constructors: this.parseConstructors(ensureArray(record.constructor)),
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Raw GIR type definitions.
3
+ *
4
+ * These types represent the structure of parsed GIR XML data before normalization.
5
+ * They are internal to the @gtkx/gir package and not exported publicly.
6
+ *
7
+ * @internal
8
+ */
9
+ import type { ContainerType } from "../types.js";
10
+ export type { ContainerType };
11
+ /**
12
+ * Represents a parsed GIR namespace (library).
13
+ *
14
+ * Contains all type definitions from a single GIR file, including
15
+ * classes, interfaces, functions, enums, records, and callbacks.
16
+ */
17
+ export type RawNamespace = {
18
+ name: string;
19
+ version: string;
20
+ sharedLibrary: string;
21
+ cPrefix: string;
22
+ classes: RawClass[];
23
+ interfaces: RawInterface[];
24
+ functions: RawFunction[];
25
+ enumerations: RawEnumeration[];
26
+ bitfields: RawEnumeration[];
27
+ records: RawRecord[];
28
+ callbacks: RawCallback[];
29
+ constants: RawConstant[];
30
+ doc?: string;
31
+ };
32
+ /**
33
+ * A constant value defined in a GIR namespace.
34
+ */
35
+ export type RawConstant = {
36
+ name: string;
37
+ cType: string;
38
+ value: string;
39
+ type: RawType;
40
+ doc?: string;
41
+ };
42
+ /**
43
+ * A callback type definition (function pointer type).
44
+ */
45
+ export type RawCallback = {
46
+ name: string;
47
+ cType: string;
48
+ returnType: RawType;
49
+ parameters: RawParameter[];
50
+ doc?: string;
51
+ };
52
+ /**
53
+ * A GObject interface definition.
54
+ */
55
+ export type RawInterface = {
56
+ name: string;
57
+ cType: string;
58
+ glibTypeName?: string;
59
+ prerequisites: string[];
60
+ methods: RawMethod[];
61
+ properties: RawProperty[];
62
+ signals: RawSignal[];
63
+ doc?: string;
64
+ };
65
+ /**
66
+ * A GObject class definition.
67
+ */
68
+ export type RawClass = {
69
+ name: string;
70
+ cType: string;
71
+ parent?: string;
72
+ abstract?: boolean;
73
+ glibTypeName?: string;
74
+ glibGetType?: string;
75
+ cSymbolPrefix?: string;
76
+ implements: string[];
77
+ methods: RawMethod[];
78
+ constructors: RawConstructor[];
79
+ functions: RawFunction[];
80
+ properties: RawProperty[];
81
+ signals: RawSignal[];
82
+ doc?: string;
83
+ };
84
+ /**
85
+ * A GLib record (boxed type or struct).
86
+ */
87
+ export type RawRecord = {
88
+ name: string;
89
+ cType: string;
90
+ opaque?: boolean;
91
+ disguised?: boolean;
92
+ glibTypeName?: string;
93
+ glibGetType?: string;
94
+ isGtypeStructFor?: string;
95
+ fields: RawField[];
96
+ methods: RawMethod[];
97
+ constructors: RawConstructor[];
98
+ functions: RawFunction[];
99
+ doc?: string;
100
+ };
101
+ /**
102
+ * A field within a record or class.
103
+ */
104
+ export type RawField = {
105
+ name: string;
106
+ type: RawType;
107
+ writable?: boolean;
108
+ readable?: boolean;
109
+ private?: boolean;
110
+ doc?: string;
111
+ };
112
+ /**
113
+ * A method on a class, interface, or record.
114
+ */
115
+ export type RawMethod = {
116
+ name: string;
117
+ cIdentifier: string;
118
+ returnType: RawType;
119
+ parameters: RawParameter[];
120
+ throws?: boolean;
121
+ doc?: string;
122
+ returnDoc?: string;
123
+ /** For async methods, the name of the corresponding finish function */
124
+ finishFunc?: string;
125
+ };
126
+ /**
127
+ * A constructor for a class or record.
128
+ */
129
+ export type RawConstructor = {
130
+ name: string;
131
+ cIdentifier: string;
132
+ returnType: RawType;
133
+ parameters: RawParameter[];
134
+ throws?: boolean;
135
+ doc?: string;
136
+ returnDoc?: string;
137
+ };
138
+ /**
139
+ * A standalone function or static method.
140
+ */
141
+ export type RawFunction = {
142
+ name: string;
143
+ cIdentifier: string;
144
+ returnType: RawType;
145
+ parameters: RawParameter[];
146
+ throws?: boolean;
147
+ doc?: string;
148
+ returnDoc?: string;
149
+ };
150
+ /**
151
+ * A parameter to a function, method, or callback.
152
+ */
153
+ export type RawParameter = {
154
+ name: string;
155
+ type: RawType;
156
+ direction?: "in" | "out" | "inout";
157
+ callerAllocates?: boolean;
158
+ nullable?: boolean;
159
+ optional?: boolean;
160
+ scope?: "async" | "call" | "notified";
161
+ closure?: number;
162
+ destroy?: number;
163
+ transferOwnership?: "none" | "full" | "container";
164
+ doc?: string;
165
+ };
166
+ /**
167
+ * A type reference in GIR.
168
+ *
169
+ * Type names may be unqualified (e.g., "Widget") for local types
170
+ * or qualified (e.g., "GObject.Object") for cross-namespace references.
171
+ */
172
+ export type RawType = {
173
+ name: string;
174
+ cType?: string;
175
+ isArray?: boolean;
176
+ elementType?: RawType;
177
+ typeParameters?: RawType[];
178
+ containerType?: ContainerType;
179
+ transferOwnership?: "none" | "full" | "container";
180
+ nullable?: boolean;
181
+ };
182
+ /**
183
+ * A GObject property definition.
184
+ */
185
+ export type RawProperty = {
186
+ name: string;
187
+ type: RawType;
188
+ readable?: boolean;
189
+ writable?: boolean;
190
+ constructOnly?: boolean;
191
+ hasDefault?: boolean;
192
+ getter?: string;
193
+ setter?: string;
194
+ doc?: string;
195
+ };
196
+ /**
197
+ * A GObject signal definition.
198
+ */
199
+ export type RawSignal = {
200
+ name: string;
201
+ when?: "first" | "last" | "cleanup";
202
+ returnType?: RawType;
203
+ parameters?: RawParameter[];
204
+ doc?: string;
205
+ };
206
+ /**
207
+ * An enumeration or bitfield definition.
208
+ */
209
+ export type RawEnumeration = {
210
+ name: string;
211
+ cType: string;
212
+ members: RawEnumerationMember[];
213
+ doc?: string;
214
+ };
215
+ /**
216
+ * A member of an enumeration or bitfield.
217
+ */
218
+ export type RawEnumerationMember = {
219
+ name: string;
220
+ value: string;
221
+ cIdentifier: string;
222
+ doc?: string;
223
+ };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Raw GIR type definitions.
3
+ *
4
+ * These types represent the structure of parsed GIR XML data before normalization.
5
+ * They are internal to the @gtkx/gir package and not exported publicly.
6
+ *
7
+ * @internal
8
+ */
9
+ export {};
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Intrinsic (primitive) types that are not namespace-qualified.
3
+ *
4
+ * These are fundamental GLib/GObject types that exist outside of any namespace.
5
+ * When normalizing type references, intrinsic types remain as-is rather than
6
+ * being qualified with a namespace prefix.
7
+ */
8
+ export declare const INTRINSIC_TYPES: Set<string>;
9
+ /**
10
+ * Checks if a type name is an intrinsic (primitive) type.
11
+ *
12
+ * @param typeName - The type name to check
13
+ * @returns True if the type is intrinsic and should not be namespace-qualified
14
+ */
15
+ export declare const isIntrinsicType: (typeName: string) => boolean;
16
+ /**
17
+ * String type names (utf8 and filename).
18
+ */
19
+ export declare const STRING_TYPES: Set<string>;
20
+ /**
21
+ * Checks if a type name is a string type.
22
+ */
23
+ export declare const isStringType: (typeName: string) => boolean;
24
+ /**
25
+ * Numeric type names (integers and floats).
26
+ */
27
+ export declare const NUMERIC_TYPES: Set<string>;
28
+ /**
29
+ * Checks if a type name is a numeric type.
30
+ */
31
+ export declare const isNumericType: (typeName: string) => boolean;
32
+ /**
33
+ * Void type names.
34
+ */
35
+ export declare const VOID_TYPES: Set<string>;
36
+ /**
37
+ * Checks if a type name is void.
38
+ */
39
+ export declare const isVoidType: (typeName: string) => boolean;
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Intrinsic (primitive) types that are not namespace-qualified.
3
+ *
4
+ * These are fundamental GLib/GObject types that exist outside of any namespace.
5
+ * When normalizing type references, intrinsic types remain as-is rather than
6
+ * being qualified with a namespace prefix.
7
+ */
8
+ export const INTRINSIC_TYPES = new Set([
9
+ "void",
10
+ "none",
11
+ "gboolean",
12
+ "gint",
13
+ "gint8",
14
+ "gint16",
15
+ "gint32",
16
+ "gint64",
17
+ "gchar",
18
+ "gshort",
19
+ "glong",
20
+ "gssize",
21
+ "goffset",
22
+ "gintptr",
23
+ "guint",
24
+ "guint8",
25
+ "guint16",
26
+ "guint32",
27
+ "guint64",
28
+ "guchar",
29
+ "gushort",
30
+ "gulong",
31
+ "gsize",
32
+ "guintptr",
33
+ "gfloat",
34
+ "gdouble",
35
+ "gpointer",
36
+ "gconstpointer",
37
+ "utf8",
38
+ "filename",
39
+ "GType",
40
+ "GParamSpec",
41
+ "GVariant",
42
+ "int",
43
+ "uint",
44
+ "long",
45
+ "ulong",
46
+ "float",
47
+ "double",
48
+ "size_t",
49
+ "ssize_t",
50
+ ]);
51
+ /**
52
+ * Checks if a type name is an intrinsic (primitive) type.
53
+ *
54
+ * @param typeName - The type name to check
55
+ * @returns True if the type is intrinsic and should not be namespace-qualified
56
+ */
57
+ export const isIntrinsicType = (typeName) => {
58
+ return INTRINSIC_TYPES.has(typeName);
59
+ };
60
+ /**
61
+ * String type names (utf8 and filename).
62
+ */
63
+ export const STRING_TYPES = new Set(["utf8", "filename"]);
64
+ /**
65
+ * Checks if a type name is a string type.
66
+ */
67
+ export const isStringType = (typeName) => {
68
+ return STRING_TYPES.has(typeName);
69
+ };
70
+ /**
71
+ * Numeric type names (integers and floats).
72
+ */
73
+ export const NUMERIC_TYPES = new Set([
74
+ "gint",
75
+ "guint",
76
+ "gint8",
77
+ "guint8",
78
+ "gint16",
79
+ "guint16",
80
+ "gint32",
81
+ "guint32",
82
+ "gint64",
83
+ "guint64",
84
+ "gchar",
85
+ "guchar",
86
+ "gshort",
87
+ "gushort",
88
+ "glong",
89
+ "gulong",
90
+ "gsize",
91
+ "gssize",
92
+ "goffset",
93
+ "gintptr",
94
+ "guintptr",
95
+ "gfloat",
96
+ "gdouble",
97
+ "int",
98
+ "uint",
99
+ "long",
100
+ "ulong",
101
+ "float",
102
+ "double",
103
+ "size_t",
104
+ "ssize_t",
105
+ "GType",
106
+ ]);
107
+ /**
108
+ * Checks if a type name is a numeric type.
109
+ */
110
+ export const isNumericType = (typeName) => {
111
+ return NUMERIC_TYPES.has(typeName);
112
+ };
113
+ /**
114
+ * Void type names.
115
+ */
116
+ export const VOID_TYPES = new Set(["void", "none"]);
117
+ /**
118
+ * Checks if a type name is void.
119
+ */
120
+ export const isVoidType = (typeName) => {
121
+ return VOID_TYPES.has(typeName);
122
+ };