@gtkx/gir 0.1.5 → 0.1.6

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gtkx/gir",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "GObject Introspection file parser for GTKX",
5
5
  "license": "MPL-2.0",
6
6
  "author": "Eugenio Depalo <eugeniodepalo@gmail.com>",
package/src/parser.ts CHANGED
@@ -4,12 +4,14 @@ import type {
4
4
  GirConstructor,
5
5
  GirEnumeration,
6
6
  GirEnumerationMember,
7
+ GirField,
7
8
  GirFunction,
8
9
  GirInterface,
9
10
  GirMethod,
10
11
  GirNamespace,
11
12
  GirParameter,
12
13
  GirProperty,
14
+ GirRecord,
13
15
  GirSignal,
14
16
  GirType,
15
17
  } from "./types.js";
@@ -20,6 +22,7 @@ const ARRAY_ELEMENT_PATHS = new Set<string>([
20
22
  "namespace.function",
21
23
  "namespace.enumeration",
22
24
  "namespace.bitfield",
25
+ "namespace.record",
23
26
  "namespace.class.method",
24
27
  "namespace.class.constructor",
25
28
  "namespace.class.function",
@@ -30,6 +33,10 @@ const ARRAY_ELEMENT_PATHS = new Set<string>([
30
33
  "namespace.interface.property",
31
34
  "namespace.interface.signal",
32
35
  "namespace.interface.glib:signal",
36
+ "namespace.record.method",
37
+ "namespace.record.constructor",
38
+ "namespace.record.function",
39
+ "namespace.record.field",
33
40
  "namespace.class.method.parameters.parameter",
34
41
  "namespace.class.constructor.parameters.parameter",
35
42
  "namespace.class.function.parameters.parameter",
@@ -39,6 +46,9 @@ const ARRAY_ELEMENT_PATHS = new Set<string>([
39
46
  "namespace.interface.method.parameters.parameter",
40
47
  "namespace.class.glib:signal.parameters.parameter",
41
48
  "namespace.interface.glib:signal.parameters.parameter",
49
+ "namespace.record.method.parameters.parameter",
50
+ "namespace.record.constructor.parameters.parameter",
51
+ "namespace.record.function.parameters.parameter",
42
52
  ]);
43
53
 
44
54
  const extractDoc = (node: Record<string, unknown>): string | undefined => {
@@ -94,6 +104,7 @@ export class GirParser {
94
104
  functions: this.parseFunctions(namespace.function ?? []),
95
105
  enumerations: this.parseEnumerations(namespace.enumeration ?? []),
96
106
  bitfields: this.parseEnumerations(namespace.bitfield ?? []),
107
+ records: this.parseRecords(namespace.record ?? []),
97
108
  };
98
109
  }
99
110
 
@@ -290,6 +301,48 @@ export class GirParser {
290
301
  });
291
302
  }
292
303
 
304
+ private parseRecords(records: Record<string, unknown>[]): GirRecord[] {
305
+ if (!records || !Array.isArray(records)) {
306
+ return [];
307
+ }
308
+ return records.map((record) => ({
309
+ name: String(record["@_name"] ?? ""),
310
+ cType: String(record["@_c:type"] ?? record["@_glib:type-name"] ?? ""),
311
+ opaque: record["@_opaque"] === "1",
312
+ disguised: record["@_disguised"] === "1",
313
+ glibTypeName: record["@_glib:type-name"] ? String(record["@_glib:type-name"]) : undefined,
314
+ glibGetType: record["@_glib:get-type"] ? String(record["@_glib:get-type"]) : undefined,
315
+ fields: this.parseFields(Array.isArray(record.field) ? (record.field as Record<string, unknown>[]) : []),
316
+ methods: this.parseMethods(Array.isArray(record.method) ? (record.method as Record<string, unknown>[]) : []),
317
+ constructors: this.parseConstructors(
318
+ Array.isArray(record.constructor) ? (record.constructor as Record<string, unknown>[]) : [],
319
+ ),
320
+ functions: this.parseFunctions(
321
+ Array.isArray(record.function) ? (record.function as Record<string, unknown>[]) : [],
322
+ ),
323
+ doc: extractDoc(record),
324
+ }));
325
+ }
326
+
327
+ private parseFields(fields: Record<string, unknown>[]): GirField[] {
328
+ if (!fields || !Array.isArray(fields)) {
329
+ return [];
330
+ }
331
+ return fields
332
+ .filter((field) => {
333
+ const hasCallback = field.callback !== undefined;
334
+ return !hasCallback;
335
+ })
336
+ .map((field) => ({
337
+ name: String(field["@_name"] ?? ""),
338
+ type: this.parseType((field.type ?? field.array) as Record<string, unknown> | undefined),
339
+ writable: field["@_writable"] === "1",
340
+ readable: field["@_readable"] !== "0",
341
+ private: field["@_private"] === "1",
342
+ doc: extractDoc(field),
343
+ }));
344
+ }
345
+
293
346
  private parseEnumerations(enumerations: Record<string, unknown>[]): GirEnumeration[] {
294
347
  if (!enumerations || !Array.isArray(enumerations)) {
295
348
  return [];
package/src/types.ts CHANGED
@@ -20,6 +20,8 @@ export interface GirNamespace {
20
20
  enumerations: GirEnumeration[];
21
21
  /** All bitfield enumerations defined in this namespace. */
22
22
  bitfields: GirEnumeration[];
23
+ /** All records (structs) defined in this namespace. */
24
+ records: GirRecord[];
23
25
  /** Documentation for the namespace. */
24
26
  doc?: string;
25
27
  }
@@ -70,6 +72,52 @@ export interface GirClass {
70
72
  doc?: string;
71
73
  }
72
74
 
75
+ /**
76
+ * Represents a GIR record (struct) definition.
77
+ */
78
+ export interface GirRecord {
79
+ /** The record name. */
80
+ name: string;
81
+ /** The C type name. */
82
+ cType: string;
83
+ /** Whether this record is opaque (no field access). */
84
+ opaque?: boolean;
85
+ /** Whether this record is disguised (typically internal). */
86
+ disguised?: boolean;
87
+ /** The GLib type name for boxed types. */
88
+ glibTypeName?: string;
89
+ /** The GLib get-type function. */
90
+ glibGetType?: string;
91
+ /** Fields defined in this record. */
92
+ fields: GirField[];
93
+ /** Methods defined on this record. */
94
+ methods: GirMethod[];
95
+ /** Constructor functions for this record. */
96
+ constructors: GirConstructor[];
97
+ /** Static functions defined on this record. */
98
+ functions: GirFunction[];
99
+ /** Documentation for the record. */
100
+ doc?: string;
101
+ }
102
+
103
+ /**
104
+ * Represents a GIR field definition in a record.
105
+ */
106
+ export interface GirField {
107
+ /** The field name. */
108
+ name: string;
109
+ /** The field type. */
110
+ type: GirType;
111
+ /** Whether this field is writable. */
112
+ writable?: boolean;
113
+ /** Whether this field is readable. */
114
+ readable?: boolean;
115
+ /** Whether this field is private. */
116
+ private?: boolean;
117
+ /** Documentation for the field. */
118
+ doc?: string;
119
+ }
120
+
73
121
  /**
74
122
  * Represents a GIR method definition.
75
123
  */
@@ -230,8 +278,8 @@ export interface FfiTypeDescriptor {
230
278
  unsigned?: boolean;
231
279
  /** Whether the pointer is borrowed (not owned). */
232
280
  borrowed?: boolean;
233
- /** Inner type for ref types. */
234
- innerType?: FfiTypeDescriptor;
281
+ /** Inner type for ref types (as descriptor) or boxed types (as GLib type name string). */
282
+ innerType?: FfiTypeDescriptor | string;
235
283
  /** Item type for array types. */
236
284
  itemType?: FfiTypeDescriptor;
237
285
  }
@@ -307,6 +355,8 @@ const BASIC_TYPE_MAP = new Map<string, TypeMapping>([
307
355
  ["filename", { ts: "string", ffi: { type: "string" } }],
308
356
  ["gpointer", { ts: "unknown", ffi: { type: "gobject" } }],
309
357
  ["gconstpointer", { ts: "unknown", ffi: { type: "gobject" } }],
358
+ ["Quark", { ts: "number", ffi: { type: "int", size: 32, unsigned: true } }],
359
+ ["GLib.Quark", { ts: "number", ffi: { type: "int", size: 32, unsigned: true } }],
310
360
  ["void", { ts: "void", ffi: { type: "undefined" } }],
311
361
  ["none", { ts: "void", ffi: { type: "undefined" } }],
312
362
  ["int", { ts: "number", ffi: { type: "int", size: 32, unsigned: false } }],
@@ -331,12 +381,16 @@ const LIBRARY_MAP: Record<string, string> = {
331
381
 
332
382
  /**
333
383
  * Maps GIR types to TypeScript types and FFI type descriptors.
334
- * Handles basic types, enumerations, arrays, and object references.
384
+ * Handles basic types, enumerations, records, arrays, and object references.
335
385
  */
336
386
  export class TypeMapper {
337
387
  private enumNames: Set<string> = new Set();
338
388
  private enumTransforms: Map<string, string> = new Map();
389
+ private recordNames: Set<string> = new Set();
390
+ private recordTransforms: Map<string, string> = new Map();
391
+ private recordGlibTypes: Map<string, string> = new Map();
339
392
  private onEnumUsed?: (enumName: string) => void;
393
+ private onRecordUsed?: (recordName: string) => void;
340
394
 
341
395
  /**
342
396
  * Registers an enumeration type for mapping.
@@ -350,6 +404,22 @@ export class TypeMapper {
350
404
  }
351
405
  }
352
406
 
407
+ /**
408
+ * Registers a record type for mapping.
409
+ * @param originalName - The original GIR record name
410
+ * @param transformedName - The transformed TypeScript class name
411
+ * @param glibTypeName - The GLib type name for boxed type handling
412
+ */
413
+ registerRecord(originalName: string, transformedName?: string, glibTypeName?: string): void {
414
+ this.recordNames.add(originalName);
415
+ if (transformedName) {
416
+ this.recordTransforms.set(originalName, transformedName);
417
+ }
418
+ if (glibTypeName) {
419
+ this.recordGlibTypes.set(originalName, glibTypeName);
420
+ }
421
+ }
422
+
353
423
  /**
354
424
  * Sets a callback to track enum usage during type mapping.
355
425
  * @param callback - Called when an enum is used, or null to clear
@@ -366,6 +436,22 @@ export class TypeMapper {
366
436
  return this.onEnumUsed ?? null;
367
437
  }
368
438
 
439
+ /**
440
+ * Sets a callback to track record usage during type mapping.
441
+ * @param callback - Called when a record is used, or null to clear
442
+ */
443
+ setRecordUsageCallback(callback: ((recordName: string) => void) | null): void {
444
+ this.onRecordUsed = callback ?? undefined;
445
+ }
446
+
447
+ /**
448
+ * Gets the current record usage callback.
449
+ * @returns The callback or null if not set
450
+ */
451
+ getRecordUsageCallback(): ((recordName: string) => void) | null {
452
+ return this.onRecordUsed ?? null;
453
+ }
454
+
369
455
  /**
370
456
  * Maps a GIR type to TypeScript and FFI type descriptors.
371
457
  * @param girType - The GIR type to map
@@ -401,6 +487,16 @@ export class TypeMapper {
401
487
  };
402
488
  }
403
489
 
490
+ if (this.recordNames.has(girType.name)) {
491
+ const transformedName = this.recordTransforms.get(girType.name) ?? girType.name;
492
+ const glibTypeName = this.recordGlibTypes.get(girType.name) ?? transformedName;
493
+ this.onRecordUsed?.(transformedName);
494
+ return {
495
+ ts: transformedName,
496
+ ffi: { type: "boxed", borrowed: isReturn, innerType: glibTypeName },
497
+ };
498
+ }
499
+
404
500
  if (girType.name.includes(".")) {
405
501
  const [_ns, typeName] = girType.name.split(".", 2);
406
502
  if (typeName && this.enumNames.has(typeName)) {
@@ -411,6 +507,15 @@ export class TypeMapper {
411
507
  ffi: { type: "int", size: 32, unsigned: false },
412
508
  };
413
509
  }
510
+ if (typeName && this.recordNames.has(typeName)) {
511
+ const transformedName = this.recordTransforms.get(typeName) ?? typeName;
512
+ const glibTypeName = this.recordGlibTypes.get(typeName) ?? transformedName;
513
+ this.onRecordUsed?.(transformedName);
514
+ return {
515
+ ts: transformedName,
516
+ ffi: { type: "boxed", borrowed: isReturn, innerType: glibTypeName },
517
+ };
518
+ }
414
519
  return {
415
520
  ts: "unknown",
416
521
  ffi: { type: "gobject", borrowed: isReturn },