@gtkx/gir 0.18.0 → 0.18.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.
Files changed (41) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +1 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/internal/normalizer.d.ts +1 -0
  6. package/dist/internal/normalizer.d.ts.map +1 -0
  7. package/dist/internal/normalizer.js +1 -0
  8. package/dist/internal/normalizer.js.map +1 -0
  9. package/dist/internal/parser.d.ts +1 -0
  10. package/dist/internal/parser.d.ts.map +1 -0
  11. package/dist/internal/parser.js +1 -0
  12. package/dist/internal/parser.js.map +1 -0
  13. package/dist/internal/raw-types.d.ts +1 -0
  14. package/dist/internal/raw-types.d.ts.map +1 -0
  15. package/dist/internal/raw-types.js +1 -0
  16. package/dist/internal/raw-types.js.map +1 -0
  17. package/dist/intrinsics.d.ts +1 -0
  18. package/dist/intrinsics.d.ts.map +1 -0
  19. package/dist/intrinsics.js +1 -0
  20. package/dist/intrinsics.js.map +1 -0
  21. package/dist/repository.d.ts +1 -0
  22. package/dist/repository.d.ts.map +1 -0
  23. package/dist/repository.js +1 -0
  24. package/dist/repository.js.map +1 -0
  25. package/dist/types.d.ts +1 -0
  26. package/dist/types.d.ts.map +1 -0
  27. package/dist/types.js +1 -0
  28. package/dist/types.js.map +1 -0
  29. package/dist/utils.d.ts +1 -0
  30. package/dist/utils.d.ts.map +1 -0
  31. package/dist/utils.js +1 -0
  32. package/dist/utils.js.map +1 -0
  33. package/package.json +4 -2
  34. package/src/index.ts +64 -0
  35. package/src/internal/normalizer.ts +551 -0
  36. package/src/internal/parser.ts +633 -0
  37. package/src/internal/raw-types.ts +268 -0
  38. package/src/intrinsics.ts +129 -0
  39. package/src/repository.ts +406 -0
  40. package/src/types.ts +1192 -0
  41. package/src/utils.ts +12 -0
package/src/types.ts ADDED
@@ -0,0 +1,1192 @@
1
+ /**
2
+ * Normalized GIR types with helper methods.
3
+ *
4
+ * All type references use fully qualified names (Namespace.TypeName)
5
+ * except for intrinsic types which remain unqualified.
6
+ */
7
+
8
+ import { isIntrinsicType, isNumericType, isStringType, isVoidType } from "./intrinsics.js";
9
+
10
+ /**
11
+ * A fully qualified type name.
12
+ * Always in the format "Namespace.TypeName" (e.g., "Gtk.Widget", "GLib.Variant").
13
+ * Intrinsic types like "gint" are NOT QualifiedNames.
14
+ */
15
+ export type QualifiedName = string & { readonly __brand: "QualifiedName" };
16
+
17
+ /**
18
+ * Creates a QualifiedName from namespace and type name.
19
+ */
20
+ export const qualifiedName = (namespace: string, name: string): QualifiedName => {
21
+ return `${namespace}.${name}` as QualifiedName;
22
+ };
23
+
24
+ /**
25
+ * Parses a QualifiedName into its parts.
26
+ */
27
+ export const parseQualifiedName = (qn: QualifiedName): { namespace: string; name: string } => {
28
+ const dot = qn.indexOf(".");
29
+ return {
30
+ namespace: qn.slice(0, dot),
31
+ name: qn.slice(dot + 1),
32
+ };
33
+ };
34
+
35
+ /**
36
+ * The kind of a user-defined type (not intrinsic).
37
+ */
38
+ export type TypeKind = "class" | "interface" | "record" | "enum" | "flags" | "callback";
39
+
40
+ /**
41
+ * Container type discriminator for generic GLib containers.
42
+ */
43
+ export type ContainerType = "ghashtable" | "gptrarray" | "garray" | "glist" | "gslist";
44
+
45
+ /**
46
+ * Parsed default value from GIR property definitions.
47
+ */
48
+ export type DefaultValue =
49
+ | { kind: "null" }
50
+ | { kind: "boolean"; value: boolean }
51
+ | { kind: "number"; value: number }
52
+ | { kind: "string"; value: string }
53
+ | { kind: "enum"; cIdentifier: string }
54
+ | { kind: "unknown"; raw: string };
55
+
56
+ /**
57
+ * Parses a raw default value string from GIR into a typed DefaultValue.
58
+ */
59
+ export function parseDefaultValue(raw: string | undefined): DefaultValue | null {
60
+ if (raw === undefined) {
61
+ return null;
62
+ }
63
+
64
+ if (raw === "NULL") {
65
+ return { kind: "null" };
66
+ }
67
+
68
+ if (raw === "TRUE") {
69
+ return { kind: "boolean", value: true };
70
+ }
71
+
72
+ if (raw === "FALSE") {
73
+ return { kind: "boolean", value: false };
74
+ }
75
+
76
+ const num = Number(raw);
77
+ if (!Number.isNaN(num)) {
78
+ return { kind: "number", value: num };
79
+ }
80
+
81
+ if (raw.startsWith('"') && raw.endsWith('"')) {
82
+ return { kind: "string", value: raw.slice(1, -1) };
83
+ }
84
+
85
+ if (/^[A-Z][A-Z0-9_]*$/.test(raw)) {
86
+ return { kind: "enum", cIdentifier: raw };
87
+ }
88
+
89
+ return { kind: "unknown", raw };
90
+ }
91
+
92
+ type RepositoryLike = {
93
+ resolveClass(name: QualifiedName): GirClass | null;
94
+ resolveInterface(name: QualifiedName): GirInterface | null;
95
+ resolveRecord(name: QualifiedName): GirRecord | null;
96
+ resolveEnum(name: QualifiedName): GirEnumeration | null;
97
+ resolveFlags(name: QualifiedName): GirEnumeration | null;
98
+ resolveCallback(name: QualifiedName): GirCallback | null;
99
+ getTypeKind(name: QualifiedName): TypeKind | null;
100
+ findClasses(predicate: (cls: GirClass) => boolean): GirClass[];
101
+ };
102
+
103
+ /**
104
+ * Normalized namespace containing all resolved types.
105
+ */
106
+ export class GirNamespace {
107
+ readonly name: string;
108
+ readonly version: string;
109
+ readonly sharedLibrary: string;
110
+ readonly cPrefix: string;
111
+ readonly classes: Map<string, GirClass>;
112
+ readonly interfaces: Map<string, GirInterface>;
113
+ readonly records: Map<string, GirRecord>;
114
+ readonly enumerations: Map<string, GirEnumeration>;
115
+ readonly bitfields: Map<string, GirEnumeration>;
116
+ readonly callbacks: Map<string, GirCallback>;
117
+ readonly functions: Map<string, GirFunction>;
118
+ readonly constants: Map<string, GirConstant>;
119
+ readonly aliases: Map<string, GirAlias>;
120
+ readonly doc?: string;
121
+
122
+ constructor(data: {
123
+ name: string;
124
+ version: string;
125
+ sharedLibrary: string;
126
+ cPrefix: string;
127
+ classes: Map<string, GirClass>;
128
+ interfaces: Map<string, GirInterface>;
129
+ records: Map<string, GirRecord>;
130
+ enumerations: Map<string, GirEnumeration>;
131
+ bitfields: Map<string, GirEnumeration>;
132
+ callbacks: Map<string, GirCallback>;
133
+ functions: Map<string, GirFunction>;
134
+ constants: Map<string, GirConstant>;
135
+ aliases: Map<string, GirAlias>;
136
+ doc?: string;
137
+ }) {
138
+ this.name = data.name;
139
+ this.version = data.version;
140
+ this.sharedLibrary = data.sharedLibrary;
141
+ this.cPrefix = data.cPrefix;
142
+ this.classes = data.classes;
143
+ this.interfaces = data.interfaces;
144
+ this.records = data.records;
145
+ this.enumerations = data.enumerations;
146
+ this.bitfields = data.bitfields;
147
+ this.callbacks = data.callbacks;
148
+ this.functions = data.functions;
149
+ this.constants = data.constants;
150
+ this.aliases = data.aliases;
151
+ this.doc = data.doc;
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Normalized class with helper methods.
157
+ */
158
+ export class GirClass {
159
+ readonly name: string;
160
+ readonly qualifiedName: QualifiedName;
161
+ readonly cType: string;
162
+ readonly parent: QualifiedName | null;
163
+ readonly abstract: boolean;
164
+ readonly glibTypeName?: string;
165
+ readonly glibGetType?: string;
166
+ readonly cSymbolPrefix?: string;
167
+ readonly fundamental: boolean;
168
+ readonly refFunc?: string;
169
+ readonly unrefFunc?: string;
170
+ readonly implements: QualifiedName[];
171
+ readonly methods: GirMethod[];
172
+ readonly constructors: GirConstructor[];
173
+ readonly staticFunctions: GirFunction[];
174
+ readonly properties: GirProperty[];
175
+ readonly signals: GirSignal[];
176
+ readonly doc?: string;
177
+
178
+ /** @internal */
179
+ private _repo?: RepositoryLike;
180
+
181
+ constructor(data: {
182
+ name: string;
183
+ qualifiedName: QualifiedName;
184
+ cType: string;
185
+ parent: QualifiedName | null;
186
+ abstract: boolean;
187
+ glibTypeName?: string;
188
+ glibGetType?: string;
189
+ cSymbolPrefix?: string;
190
+ fundamental?: boolean;
191
+ refFunc?: string;
192
+ unrefFunc?: string;
193
+ implements: QualifiedName[];
194
+ methods: GirMethod[];
195
+ constructors: GirConstructor[];
196
+ staticFunctions: GirFunction[];
197
+ properties: GirProperty[];
198
+ signals: GirSignal[];
199
+ doc?: string;
200
+ }) {
201
+ this.name = data.name;
202
+ this.qualifiedName = data.qualifiedName;
203
+ this.cType = data.cType;
204
+ this.parent = data.parent;
205
+ this.abstract = data.abstract;
206
+ this.glibTypeName = data.glibTypeName;
207
+ this.glibGetType = data.glibGetType;
208
+ this.cSymbolPrefix = data.cSymbolPrefix;
209
+ this.fundamental = data.fundamental ?? false;
210
+ this.refFunc = data.refFunc;
211
+ this.unrefFunc = data.unrefFunc;
212
+ this.implements = data.implements;
213
+ this.methods = data.methods;
214
+ this.constructors = data.constructors;
215
+ this.staticFunctions = data.staticFunctions;
216
+ this.properties = data.properties;
217
+ this.signals = data.signals;
218
+ this.doc = data.doc;
219
+ }
220
+
221
+ /** @internal */
222
+ _setRepository(repo: RepositoryLike): void {
223
+ this._repo = repo;
224
+ }
225
+
226
+ /** Checks if this class is a subclass of another (direct or transitive). */
227
+ isSubclassOf(qualifiedName: QualifiedName): boolean {
228
+ if (this.qualifiedName === qualifiedName) return true;
229
+ if (!this.parent || !this._repo) return false;
230
+ if (this.parent === qualifiedName) return true;
231
+ const parentClass = this._repo.resolveClass(this.parent);
232
+ return parentClass?.isSubclassOf(qualifiedName) ?? false;
233
+ }
234
+
235
+ /** Gets the full inheritance chain from this class to the root. */
236
+ getInheritanceChain(): QualifiedName[] {
237
+ const chain: QualifiedName[] = [this.qualifiedName];
238
+ let current: GirClass | null = this;
239
+ while (current?.parent && this._repo) {
240
+ chain.push(current.parent);
241
+ current = this._repo.resolveClass(current.parent);
242
+ }
243
+ return chain;
244
+ }
245
+
246
+ /** Gets the parent class object, or null if this is a root class. */
247
+ getParent(): GirClass | null {
248
+ return this.parent && this._repo ? this._repo.resolveClass(this.parent) : null;
249
+ }
250
+
251
+ /** Checks if this class directly or transitively implements an interface. */
252
+ implementsInterface(qualifiedName: QualifiedName): boolean {
253
+ if (this.implements.includes(qualifiedName)) return true;
254
+ const parent = this.getParent();
255
+ return parent?.implementsInterface(qualifiedName) ?? false;
256
+ }
257
+
258
+ /** Gets all implemented interfaces including inherited ones. */
259
+ getAllImplementedInterfaces(): QualifiedName[] {
260
+ const interfaces = new Set<QualifiedName>(this.implements);
261
+ let current = this.getParent();
262
+ while (current) {
263
+ for (const iface of current.implements) {
264
+ interfaces.add(iface);
265
+ }
266
+ current = current.getParent();
267
+ }
268
+ return [...interfaces];
269
+ }
270
+
271
+ /** Finds a method defined on this class by name. */
272
+ getMethod(name: string): GirMethod | null {
273
+ return this.methods.find((m) => m.name === name) ?? null;
274
+ }
275
+
276
+ /** Finds a property defined on this class by name. */
277
+ getProperty(name: string): GirProperty | null {
278
+ return this.properties.find((p) => p.name === name) ?? null;
279
+ }
280
+
281
+ /** Finds a signal defined on this class by name. */
282
+ getSignal(name: string): GirSignal | null {
283
+ return this.signals.find((s) => s.name === name) ?? null;
284
+ }
285
+
286
+ /** Finds a constructor by name. */
287
+ getConstructor(name: string): GirConstructor | null {
288
+ return this.constructors.find((c) => c.name === name) ?? null;
289
+ }
290
+
291
+ /** Gets all methods including inherited ones. */
292
+ getAllMethods(): GirMethod[] {
293
+ const methods = [...this.methods];
294
+ let current = this.getParent();
295
+ while (current) {
296
+ methods.push(...current.methods);
297
+ current = current.getParent();
298
+ }
299
+ return methods;
300
+ }
301
+
302
+ /** Gets all properties including inherited ones. */
303
+ getAllProperties(): GirProperty[] {
304
+ const properties = [...this.properties];
305
+ let current = this.getParent();
306
+ while (current) {
307
+ properties.push(...current.properties);
308
+ current = current.getParent();
309
+ }
310
+ return properties;
311
+ }
312
+
313
+ /** Gets all signals including inherited ones. */
314
+ getAllSignals(): GirSignal[] {
315
+ const signals = [...this.signals];
316
+ let current = this.getParent();
317
+ while (current) {
318
+ signals.push(...current.signals);
319
+ current = current.getParent();
320
+ }
321
+ return signals;
322
+ }
323
+
324
+ /** Finds a method by name, searching up the inheritance chain. */
325
+ findMethod(name: string): GirMethod | null {
326
+ const own = this.getMethod(name);
327
+ if (own) return own;
328
+ return this.getParent()?.findMethod(name) ?? null;
329
+ }
330
+
331
+ /** Finds a method by its C identifier. */
332
+ getMethodByCIdentifier(cIdentifier: string): GirMethod | null {
333
+ return this.methods.find((m) => m.cIdentifier === cIdentifier) ?? null;
334
+ }
335
+
336
+ /** Finds a property by name, searching up the inheritance chain. */
337
+ findProperty(name: string): GirProperty | null {
338
+ const own = this.getProperty(name);
339
+ if (own) return own;
340
+ return this.getParent()?.findProperty(name) ?? null;
341
+ }
342
+
343
+ /** Finds a signal by name, searching up the inheritance chain. */
344
+ findSignal(name: string): GirSignal | null {
345
+ const own = this.getSignal(name);
346
+ if (own) return own;
347
+ return this.getParent()?.findSignal(name) ?? null;
348
+ }
349
+
350
+ /** True if this is an abstract class. */
351
+ isAbstract(): boolean {
352
+ return this.abstract;
353
+ }
354
+
355
+ /** True if this has a GType (most GObject classes do). */
356
+ hasGType(): boolean {
357
+ return this.glibTypeName !== undefined;
358
+ }
359
+
360
+ /** True if this is a fundamental type with custom ref/unref functions. */
361
+ isFundamental(): boolean {
362
+ return this.fundamental && this.refFunc !== undefined && this.unrefFunc !== undefined;
363
+ }
364
+
365
+ /** Gets direct subclasses of this class. */
366
+ getDirectSubclasses(): GirClass[] {
367
+ if (!this._repo) return [];
368
+ return this._repo.findClasses((cls) => cls.parent === this.qualifiedName);
369
+ }
370
+ }
371
+
372
+ /**
373
+ * Normalized interface with helper methods.
374
+ */
375
+ export class GirInterface {
376
+ readonly name: string;
377
+ readonly qualifiedName: QualifiedName;
378
+ readonly cType: string;
379
+ readonly glibTypeName?: string;
380
+ readonly prerequisites: QualifiedName[];
381
+ readonly methods: GirMethod[];
382
+ readonly properties: GirProperty[];
383
+ readonly signals: GirSignal[];
384
+ readonly doc?: string;
385
+
386
+ /** @internal */
387
+ private _repo?: RepositoryLike;
388
+
389
+ constructor(data: {
390
+ name: string;
391
+ qualifiedName: QualifiedName;
392
+ cType: string;
393
+ glibTypeName?: string;
394
+ prerequisites: QualifiedName[];
395
+ methods: GirMethod[];
396
+ properties: GirProperty[];
397
+ signals: GirSignal[];
398
+ doc?: string;
399
+ }) {
400
+ this.name = data.name;
401
+ this.qualifiedName = data.qualifiedName;
402
+ this.cType = data.cType;
403
+ this.glibTypeName = data.glibTypeName;
404
+ this.prerequisites = data.prerequisites;
405
+ this.methods = data.methods;
406
+ this.properties = data.properties;
407
+ this.signals = data.signals;
408
+ this.doc = data.doc;
409
+ }
410
+
411
+ /** @internal */
412
+ _setRepository(repo: RepositoryLike): void {
413
+ this._repo = repo;
414
+ }
415
+
416
+ /** Checks if this interface has a prerequisite (direct or transitive). */
417
+ hasPrerequisite(qualifiedName: QualifiedName): boolean {
418
+ if (this.prerequisites.includes(qualifiedName)) return true;
419
+ if (!this._repo) return false;
420
+ for (const prereq of this.prerequisites) {
421
+ const prereqIface = this._repo.resolveInterface(prereq);
422
+ if (prereqIface?.hasPrerequisite(qualifiedName)) return true;
423
+ }
424
+ return false;
425
+ }
426
+
427
+ /** Gets all prerequisites including transitive ones. */
428
+ getAllPrerequisites(): QualifiedName[] {
429
+ const all = new Set<QualifiedName>(this.prerequisites);
430
+ if (this._repo) {
431
+ for (const prereq of this.prerequisites) {
432
+ const prereqIface = this._repo.resolveInterface(prereq);
433
+ if (prereqIface) {
434
+ for (const p of prereqIface.getAllPrerequisites()) {
435
+ all.add(p);
436
+ }
437
+ }
438
+ }
439
+ }
440
+ return [...all];
441
+ }
442
+
443
+ /** Finds a method by name. */
444
+ getMethod(name: string): GirMethod | null {
445
+ return this.methods.find((m) => m.name === name) ?? null;
446
+ }
447
+
448
+ /** Finds a property by name. */
449
+ getProperty(name: string): GirProperty | null {
450
+ return this.properties.find((p) => p.name === name) ?? null;
451
+ }
452
+
453
+ /** Finds a signal by name. */
454
+ getSignal(name: string): GirSignal | null {
455
+ return this.signals.find((s) => s.name === name) ?? null;
456
+ }
457
+ }
458
+
459
+ /**
460
+ * Normalized record (boxed type or plain struct) with helper methods.
461
+ */
462
+ export class GirRecord {
463
+ readonly name: string;
464
+ readonly qualifiedName: QualifiedName;
465
+ readonly cType: string;
466
+ readonly opaque: boolean;
467
+ readonly disguised: boolean;
468
+ readonly glibTypeName?: string;
469
+ readonly glibGetType?: string;
470
+ readonly isGtypeStructFor?: string;
471
+ readonly copyFunction?: string;
472
+ readonly freeFunction?: string;
473
+ readonly fields: GirField[];
474
+ readonly methods: GirMethod[];
475
+ readonly constructors: GirConstructor[];
476
+ readonly staticFunctions: GirFunction[];
477
+ readonly doc?: string;
478
+
479
+ constructor(data: {
480
+ name: string;
481
+ qualifiedName: QualifiedName;
482
+ cType: string;
483
+ opaque: boolean;
484
+ disguised: boolean;
485
+ glibTypeName?: string;
486
+ glibGetType?: string;
487
+ isGtypeStructFor?: string;
488
+ copyFunction?: string;
489
+ freeFunction?: string;
490
+ fields: GirField[];
491
+ methods: GirMethod[];
492
+ constructors: GirConstructor[];
493
+ staticFunctions: GirFunction[];
494
+ doc?: string;
495
+ }) {
496
+ this.name = data.name;
497
+ this.qualifiedName = data.qualifiedName;
498
+ this.cType = data.cType;
499
+ this.opaque = data.opaque;
500
+ this.disguised = data.disguised;
501
+ this.glibTypeName = data.glibTypeName;
502
+ this.glibGetType = data.glibGetType;
503
+ this.isGtypeStructFor = data.isGtypeStructFor;
504
+ this.copyFunction = data.copyFunction;
505
+ this.freeFunction = data.freeFunction;
506
+ this.fields = data.fields;
507
+ this.methods = data.methods;
508
+ this.constructors = data.constructors;
509
+ this.staticFunctions = data.staticFunctions;
510
+ this.doc = data.doc;
511
+ }
512
+
513
+ /** True if this is a fundamental type with custom copy/free functions. */
514
+ isFundamental(): boolean {
515
+ return this.copyFunction !== undefined && this.freeFunction !== undefined;
516
+ }
517
+
518
+ /** True if this is a GLib boxed type (has glibTypeName). */
519
+ isBoxed(): boolean {
520
+ return this.glibTypeName !== undefined;
521
+ }
522
+
523
+ /** True if this is a GType struct (vtable for a class/interface). */
524
+ isGtypeStruct(): boolean {
525
+ return this.isGtypeStructFor !== undefined;
526
+ }
527
+
528
+ /** True if this is a plain C struct (no GType, has public fields). */
529
+ isPlainStruct(): boolean {
530
+ return !this.glibTypeName && !this.opaque && this.getPublicFields().length > 0;
531
+ }
532
+
533
+ /** Gets public (non-private) fields only. */
534
+ getPublicFields(): GirField[] {
535
+ return this.fields.filter((f) => !f.private);
536
+ }
537
+
538
+ /** Finds a method by name. */
539
+ getMethod(name: string): GirMethod | null {
540
+ return this.methods.find((m) => m.name === name) ?? null;
541
+ }
542
+
543
+ /** Finds a field by name. */
544
+ getField(name: string): GirField | null {
545
+ return this.fields.find((f) => f.name === name) ?? null;
546
+ }
547
+
548
+ /** Finds a constructor by name. */
549
+ getConstructor(name: string): GirConstructor | null {
550
+ return this.constructors.find((c) => c.name === name) ?? null;
551
+ }
552
+ }
553
+
554
+ /**
555
+ * Normalized enumeration with helper methods.
556
+ */
557
+ export class GirEnumeration {
558
+ readonly name: string;
559
+ readonly qualifiedName: QualifiedName;
560
+ readonly cType: string;
561
+ readonly members: GirEnumerationMember[];
562
+ readonly glibGetType?: string;
563
+ readonly doc?: string;
564
+
565
+ constructor(data: {
566
+ name: string;
567
+ qualifiedName: QualifiedName;
568
+ cType: string;
569
+ members: GirEnumerationMember[];
570
+ glibGetType?: string;
571
+ doc?: string;
572
+ }) {
573
+ this.name = data.name;
574
+ this.qualifiedName = data.qualifiedName;
575
+ this.cType = data.cType;
576
+ this.members = data.members;
577
+ this.glibGetType = data.glibGetType;
578
+ this.doc = data.doc;
579
+ }
580
+
581
+ /** Finds a member by name. */
582
+ getMember(name: string): GirEnumerationMember | null {
583
+ return this.members.find((m) => m.name === name) ?? null;
584
+ }
585
+
586
+ /** Finds a member by value. */
587
+ getMemberByValue(value: string): GirEnumerationMember | null {
588
+ return this.members.find((m) => m.value === value) ?? null;
589
+ }
590
+
591
+ /** Gets all member names. */
592
+ getMemberNames(): string[] {
593
+ return this.members.map((m) => m.name);
594
+ }
595
+ }
596
+
597
+ /**
598
+ * Normalized enumeration member.
599
+ */
600
+ export class GirEnumerationMember {
601
+ readonly name: string;
602
+ readonly value: string;
603
+ readonly cIdentifier: string;
604
+ readonly doc?: string;
605
+
606
+ constructor(data: { name: string; value: string; cIdentifier: string; doc?: string }) {
607
+ this.name = data.name;
608
+ this.value = data.value;
609
+ this.cIdentifier = data.cIdentifier;
610
+ this.doc = data.doc;
611
+ }
612
+ }
613
+
614
+ /**
615
+ * Normalized callback type.
616
+ */
617
+ export class GirCallback {
618
+ readonly name: string;
619
+ readonly qualifiedName: QualifiedName;
620
+ readonly cType: string;
621
+ readonly returnType: GirType;
622
+ readonly parameters: GirParameter[];
623
+ readonly doc?: string;
624
+
625
+ constructor(data: {
626
+ name: string;
627
+ qualifiedName: QualifiedName;
628
+ cType: string;
629
+ returnType: GirType;
630
+ parameters: GirParameter[];
631
+ doc?: string;
632
+ }) {
633
+ this.name = data.name;
634
+ this.qualifiedName = data.qualifiedName;
635
+ this.cType = data.cType;
636
+ this.returnType = data.returnType;
637
+ this.parameters = data.parameters;
638
+ this.doc = data.doc;
639
+ }
640
+ }
641
+
642
+ /**
643
+ * Normalized constant.
644
+ */
645
+ export class GirConstant {
646
+ readonly name: string;
647
+ readonly qualifiedName: QualifiedName;
648
+ readonly cType: string;
649
+ readonly value: string;
650
+ readonly type: GirType;
651
+ readonly doc?: string;
652
+
653
+ constructor(data: {
654
+ name: string;
655
+ qualifiedName: QualifiedName;
656
+ cType: string;
657
+ value: string;
658
+ type: GirType;
659
+ doc?: string;
660
+ }) {
661
+ this.name = data.name;
662
+ this.qualifiedName = data.qualifiedName;
663
+ this.cType = data.cType;
664
+ this.value = data.value;
665
+ this.type = data.type;
666
+ this.doc = data.doc;
667
+ }
668
+ }
669
+
670
+ /**
671
+ * Normalized type alias.
672
+ */
673
+ export class GirAlias {
674
+ readonly name: string;
675
+ readonly qualifiedName: QualifiedName;
676
+ readonly cType: string;
677
+ readonly targetType: GirType;
678
+ readonly doc?: string;
679
+
680
+ constructor(data: {
681
+ name: string;
682
+ qualifiedName: QualifiedName;
683
+ cType: string;
684
+ targetType: GirType;
685
+ doc?: string;
686
+ }) {
687
+ this.name = data.name;
688
+ this.qualifiedName = data.qualifiedName;
689
+ this.cType = data.cType;
690
+ this.targetType = data.targetType;
691
+ this.doc = data.doc;
692
+ }
693
+
694
+ isRecordAlias(): boolean {
695
+ return !this.targetType.isIntrinsic() && !this.targetType.isArray;
696
+ }
697
+ }
698
+
699
+ /**
700
+ * Normalized method with helper methods.
701
+ */
702
+ export class GirMethod {
703
+ readonly name: string;
704
+ readonly cIdentifier: string;
705
+ readonly returnType: GirType;
706
+ readonly parameters: GirParameter[];
707
+ readonly instanceParameter?: GirParameter;
708
+ readonly throws: boolean;
709
+ readonly doc?: string;
710
+ readonly returnDoc?: string;
711
+ /** For async methods, the name of the corresponding finish function */
712
+ readonly finishFunc?: string;
713
+ readonly shadows?: string;
714
+ readonly shadowedBy?: string;
715
+
716
+ constructor(data: {
717
+ name: string;
718
+ cIdentifier: string;
719
+ returnType: GirType;
720
+ parameters: GirParameter[];
721
+ instanceParameter?: GirParameter;
722
+ throws: boolean;
723
+ doc?: string;
724
+ returnDoc?: string;
725
+ finishFunc?: string;
726
+ shadows?: string;
727
+ shadowedBy?: string;
728
+ }) {
729
+ this.name = data.name;
730
+ this.cIdentifier = data.cIdentifier;
731
+ this.returnType = data.returnType;
732
+ this.parameters = data.parameters;
733
+ this.instanceParameter = data.instanceParameter;
734
+ this.throws = data.throws;
735
+ this.doc = data.doc;
736
+ this.returnDoc = data.returnDoc;
737
+ this.finishFunc = data.finishFunc;
738
+ this.shadows = data.shadows;
739
+ this.shadowedBy = data.shadowedBy;
740
+ }
741
+
742
+ /** True if this follows the async/finish pattern. */
743
+ isAsync(): boolean {
744
+ return this.name.endsWith("_async") || this.parameters.some((p) => p.scope === "async");
745
+ }
746
+
747
+ /** True if this is a _finish method for an async operation. */
748
+ isAsyncFinish(): boolean {
749
+ return this.name.endsWith("_finish");
750
+ }
751
+
752
+ /** Gets the corresponding _finish method name if this is async. */
753
+ getFinishMethodName(): string | null {
754
+ if (this.name.endsWith("_async")) {
755
+ return this.name.replace(/_async$/, "_finish");
756
+ }
757
+ return null;
758
+ }
759
+
760
+ /** Gets required (non-optional, non-nullable) parameters. */
761
+ getRequiredParameters(): GirParameter[] {
762
+ return this.parameters.filter((p) => !p.optional && !p.nullable && p.direction === "in");
763
+ }
764
+
765
+ /** Gets optional parameters. */
766
+ getOptionalParameters(): GirParameter[] {
767
+ return this.parameters.filter((p) => p.optional || p.nullable);
768
+ }
769
+
770
+ /** True if any parameter is an out parameter. */
771
+ hasOutParameters(): boolean {
772
+ return this.parameters.some((p) => p.direction === "out" || p.direction === "inout");
773
+ }
774
+
775
+ /** Gets out parameters only. */
776
+ getOutParameters(): GirParameter[] {
777
+ return this.parameters.filter((p) => p.direction === "out" || p.direction === "inout");
778
+ }
779
+ }
780
+
781
+ /**
782
+ * Normalized constructor.
783
+ */
784
+ export class GirConstructor {
785
+ readonly name: string;
786
+ readonly cIdentifier: string;
787
+ readonly returnType: GirType;
788
+ readonly parameters: GirParameter[];
789
+ readonly throws: boolean;
790
+ readonly doc?: string;
791
+ readonly returnDoc?: string;
792
+ readonly shadows?: string;
793
+ readonly shadowedBy?: string;
794
+
795
+ constructor(data: {
796
+ name: string;
797
+ cIdentifier: string;
798
+ returnType: GirType;
799
+ parameters: GirParameter[];
800
+ throws: boolean;
801
+ doc?: string;
802
+ returnDoc?: string;
803
+ shadows?: string;
804
+ shadowedBy?: string;
805
+ }) {
806
+ this.name = data.name;
807
+ this.cIdentifier = data.cIdentifier;
808
+ this.returnType = data.returnType;
809
+ this.parameters = data.parameters;
810
+ this.throws = data.throws;
811
+ this.doc = data.doc;
812
+ this.returnDoc = data.returnDoc;
813
+ this.shadows = data.shadows;
814
+ this.shadowedBy = data.shadowedBy;
815
+ }
816
+
817
+ /** Gets required (non-optional, non-nullable) parameters. */
818
+ getRequiredParameters(): GirParameter[] {
819
+ return this.parameters.filter((p) => !p.optional && !p.nullable && p.direction === "in");
820
+ }
821
+ }
822
+
823
+ /**
824
+ * Normalized standalone function.
825
+ */
826
+ export class GirFunction {
827
+ readonly name: string;
828
+ readonly cIdentifier: string;
829
+ readonly returnType: GirType;
830
+ readonly parameters: GirParameter[];
831
+ readonly throws: boolean;
832
+ readonly doc?: string;
833
+ readonly returnDoc?: string;
834
+ readonly shadows?: string;
835
+ readonly shadowedBy?: string;
836
+
837
+ constructor(data: {
838
+ name: string;
839
+ cIdentifier: string;
840
+ returnType: GirType;
841
+ parameters: GirParameter[];
842
+ throws: boolean;
843
+ doc?: string;
844
+ returnDoc?: string;
845
+ shadows?: string;
846
+ shadowedBy?: string;
847
+ }) {
848
+ this.name = data.name;
849
+ this.cIdentifier = data.cIdentifier;
850
+ this.returnType = data.returnType;
851
+ this.parameters = data.parameters;
852
+ this.throws = data.throws;
853
+ this.doc = data.doc;
854
+ this.returnDoc = data.returnDoc;
855
+ this.shadows = data.shadows;
856
+ this.shadowedBy = data.shadowedBy;
857
+ }
858
+
859
+ /** True if this follows the async/finish pattern. */
860
+ isAsync(): boolean {
861
+ return this.name.endsWith("_async") || this.parameters.some((p) => p.scope === "async");
862
+ }
863
+
864
+ /** Gets required parameters. */
865
+ getRequiredParameters(): GirParameter[] {
866
+ return this.parameters.filter((p) => !p.optional && !p.nullable && p.direction === "in");
867
+ }
868
+ }
869
+
870
+ /**
871
+ * Normalized parameter with helper methods.
872
+ */
873
+ export class GirParameter {
874
+ readonly name: string;
875
+ readonly type: GirType;
876
+ readonly direction: "in" | "out" | "inout";
877
+ readonly callerAllocates: boolean;
878
+ readonly nullable: boolean;
879
+ readonly optional: boolean;
880
+ readonly scope?: "async" | "call" | "notified";
881
+ readonly closure?: number;
882
+ readonly destroy?: number;
883
+ readonly transferOwnership?: "none" | "full" | "container";
884
+ readonly doc?: string;
885
+
886
+ constructor(data: {
887
+ name: string;
888
+ type: GirType;
889
+ direction: "in" | "out" | "inout";
890
+ callerAllocates: boolean;
891
+ nullable: boolean;
892
+ optional: boolean;
893
+ scope?: "async" | "call" | "notified";
894
+ closure?: number;
895
+ destroy?: number;
896
+ transferOwnership?: "none" | "full" | "container";
897
+ doc?: string;
898
+ }) {
899
+ this.name = data.name;
900
+ this.type = data.type;
901
+ this.direction = data.direction;
902
+ this.callerAllocates = data.callerAllocates;
903
+ this.nullable = data.nullable;
904
+ this.optional = data.optional;
905
+ this.scope = data.scope;
906
+ this.closure = data.closure;
907
+ this.destroy = data.destroy;
908
+ this.transferOwnership = data.transferOwnership;
909
+ this.doc = data.doc;
910
+ }
911
+
912
+ /** True if this is an input parameter. */
913
+ isIn(): boolean {
914
+ return this.direction === "in";
915
+ }
916
+
917
+ /** True if this is an output parameter. */
918
+ isOut(): boolean {
919
+ return this.direction === "out" || this.direction === "inout";
920
+ }
921
+
922
+ /** True if this is a callback parameter (has scope). */
923
+ isCallback(): boolean {
924
+ return this.scope !== undefined;
925
+ }
926
+
927
+ /** True if this is the user_data for a callback. */
928
+ isClosureData(): boolean {
929
+ return this.closure !== undefined;
930
+ }
931
+
932
+ /** True if this is a destroy notify for a callback. */
933
+ isDestroyNotify(): boolean {
934
+ return this.destroy !== undefined;
935
+ }
936
+
937
+ /** True if caller must allocate memory for this out param. */
938
+ requiresCallerAllocation(): boolean {
939
+ return this.callerAllocates && this.isOut();
940
+ }
941
+ }
942
+
943
+ /**
944
+ * Normalized property with helper methods.
945
+ */
946
+ export class GirProperty {
947
+ readonly name: string;
948
+ readonly type: GirType;
949
+ readonly readable: boolean;
950
+ readonly writable: boolean;
951
+ readonly constructOnly: boolean;
952
+ readonly defaultValue: DefaultValue | null;
953
+ readonly getter?: string;
954
+ readonly setter?: string;
955
+ readonly doc?: string;
956
+
957
+ constructor(data: {
958
+ name: string;
959
+ type: GirType;
960
+ readable: boolean;
961
+ writable: boolean;
962
+ constructOnly: boolean;
963
+ defaultValue: DefaultValue | null;
964
+ getter?: string;
965
+ setter?: string;
966
+ doc?: string;
967
+ }) {
968
+ this.name = data.name;
969
+ this.type = data.type;
970
+ this.readable = data.readable;
971
+ this.writable = data.writable;
972
+ this.constructOnly = data.constructOnly;
973
+ this.defaultValue = data.defaultValue;
974
+ this.getter = data.getter;
975
+ this.setter = data.setter;
976
+ this.doc = data.doc;
977
+ }
978
+
979
+ get hasDefault(): boolean {
980
+ return this.defaultValue !== null;
981
+ }
982
+
983
+ /** True if readable but not writable. */
984
+ isReadOnly(): boolean {
985
+ return this.readable && !this.writable;
986
+ }
987
+
988
+ /** True if writable but not readable. */
989
+ isWriteOnly(): boolean {
990
+ return this.writable && !this.readable;
991
+ }
992
+
993
+ /** True if can only be set during construction. */
994
+ isConstructOnly(): boolean {
995
+ return this.constructOnly;
996
+ }
997
+
998
+ /** True if has both getter and setter methods. */
999
+ hasAccessors(): boolean {
1000
+ return this.getter !== undefined && this.setter !== undefined;
1001
+ }
1002
+ }
1003
+
1004
+ /**
1005
+ * Normalized signal with helper methods.
1006
+ */
1007
+ export class GirSignal {
1008
+ readonly name: string;
1009
+ readonly when: "first" | "last" | "cleanup";
1010
+ readonly returnType: GirType | null;
1011
+ readonly parameters: GirParameter[];
1012
+ readonly doc?: string;
1013
+
1014
+ constructor(data: {
1015
+ name: string;
1016
+ when: "first" | "last" | "cleanup";
1017
+ returnType: GirType | null;
1018
+ parameters: GirParameter[];
1019
+ doc?: string;
1020
+ }) {
1021
+ this.name = data.name;
1022
+ this.when = data.when;
1023
+ this.returnType = data.returnType;
1024
+ this.parameters = data.parameters;
1025
+ this.doc = data.doc;
1026
+ }
1027
+
1028
+ /** True if the signal returns a value. */
1029
+ hasReturnValue(): boolean {
1030
+ return this.returnType !== null && !this.returnType.isVoid();
1031
+ }
1032
+ }
1033
+
1034
+ /**
1035
+ * Normalized field.
1036
+ */
1037
+ export class GirField {
1038
+ readonly name: string;
1039
+ readonly type: GirType;
1040
+ readonly writable: boolean;
1041
+ readonly readable: boolean;
1042
+ readonly private: boolean;
1043
+ readonly doc?: string;
1044
+
1045
+ constructor(data: {
1046
+ name: string;
1047
+ type: GirType;
1048
+ writable: boolean;
1049
+ readable: boolean;
1050
+ private: boolean;
1051
+ doc?: string;
1052
+ }) {
1053
+ this.name = data.name;
1054
+ this.type = data.type;
1055
+ this.writable = data.writable;
1056
+ this.readable = data.readable;
1057
+ this.private = data.private;
1058
+ this.doc = data.doc;
1059
+ }
1060
+ }
1061
+
1062
+ /**
1063
+ * Normalized type reference with helper methods.
1064
+ */
1065
+ export class GirType {
1066
+ /** Type name - either a QualifiedName or an intrinsic type string */
1067
+ readonly name: QualifiedName | string;
1068
+ readonly cType?: string;
1069
+ readonly isArray: boolean;
1070
+ readonly elementType: GirType | null;
1071
+ readonly typeParameters: readonly GirType[];
1072
+ readonly containerType?: ContainerType;
1073
+ readonly transferOwnership?: "none" | "full" | "container";
1074
+ readonly nullable: boolean;
1075
+ readonly sizeParamIndex?: number;
1076
+ readonly zeroTerminated?: boolean;
1077
+ readonly fixedSize?: number;
1078
+
1079
+ constructor(data: {
1080
+ name: QualifiedName | string;
1081
+ cType?: string;
1082
+ isArray: boolean;
1083
+ elementType: GirType | null;
1084
+ typeParameters?: readonly GirType[];
1085
+ containerType?: ContainerType;
1086
+ transferOwnership?: "none" | "full" | "container";
1087
+ nullable: boolean;
1088
+ sizeParamIndex?: number;
1089
+ zeroTerminated?: boolean;
1090
+ fixedSize?: number;
1091
+ }) {
1092
+ this.name = data.name;
1093
+ this.cType = data.cType;
1094
+ this.isArray = data.isArray;
1095
+ this.elementType = data.elementType;
1096
+ this.typeParameters = data.typeParameters ?? [];
1097
+ this.containerType = data.containerType;
1098
+ this.transferOwnership = data.transferOwnership;
1099
+ this.nullable = data.nullable;
1100
+ this.sizeParamIndex = data.sizeParamIndex;
1101
+ this.zeroTerminated = data.zeroTerminated;
1102
+ this.fixedSize = data.fixedSize;
1103
+ }
1104
+
1105
+ /** True if this is an intrinsic/primitive type. */
1106
+ isIntrinsic(): boolean {
1107
+ return typeof this.name === "string" && isIntrinsicType(this.name);
1108
+ }
1109
+
1110
+ /** True if this is a string type (utf8 or filename). */
1111
+ isString(): boolean {
1112
+ return typeof this.name === "string" && isStringType(this.name);
1113
+ }
1114
+
1115
+ /** True if this is a numeric type. */
1116
+ isNumeric(): boolean {
1117
+ return typeof this.name === "string" && isNumericType(this.name);
1118
+ }
1119
+
1120
+ /** True if this is a boolean type. */
1121
+ isBoolean(): boolean {
1122
+ return this.name === "gboolean";
1123
+ }
1124
+
1125
+ /** True if this is void. */
1126
+ isVoid(): boolean {
1127
+ return typeof this.name === "string" && isVoidType(this.name);
1128
+ }
1129
+
1130
+ /** True if this is GVariant. */
1131
+ isVariant(): boolean {
1132
+ return this.name === "GVariant";
1133
+ }
1134
+
1135
+ /** True if this is GParamSpec. */
1136
+ isParamSpec(): boolean {
1137
+ return this.name === "GParamSpec";
1138
+ }
1139
+
1140
+ /** True if this is a GHashTable container. */
1141
+ isHashTable(): boolean {
1142
+ return this.containerType === "ghashtable";
1143
+ }
1144
+
1145
+ /** True if this is a GPtrArray container. */
1146
+ isPtrArray(): boolean {
1147
+ return this.containerType === "gptrarray";
1148
+ }
1149
+
1150
+ /** True if this is a GArray container. */
1151
+ isGArray(): boolean {
1152
+ return this.containerType === "garray";
1153
+ }
1154
+
1155
+ /** True if this is a GList or GSList container. */
1156
+ isList(): boolean {
1157
+ return this.containerType === "glist" || this.containerType === "gslist";
1158
+ }
1159
+
1160
+ /** True if this is any generic container type. */
1161
+ isGenericContainer(): boolean {
1162
+ return this.containerType !== undefined;
1163
+ }
1164
+
1165
+ /** Gets the key type for GHashTable, or null for other types. */
1166
+ getKeyType(): GirType | null {
1167
+ if (!this.isHashTable() || this.typeParameters.length < 1) return null;
1168
+ return this.typeParameters[0] ?? null;
1169
+ }
1170
+
1171
+ /** Gets the value type for GHashTable, or null for other types. */
1172
+ getValueType(): GirType | null {
1173
+ if (!this.isHashTable() || this.typeParameters.length < 2) return null;
1174
+ return this.typeParameters[1] ?? null;
1175
+ }
1176
+
1177
+ /** Gets the namespace part of a qualified name, or null for intrinsics. */
1178
+ getNamespace(): string | null {
1179
+ if (this.isIntrinsic()) return null;
1180
+ const qn = this.name as QualifiedName;
1181
+ const dot = qn.indexOf(".");
1182
+ return dot >= 0 ? qn.slice(0, dot) : null;
1183
+ }
1184
+
1185
+ /** Gets the simple name part (without namespace). */
1186
+ getSimpleName(): string {
1187
+ if (this.isIntrinsic()) return this.name as string;
1188
+ const qn = this.name as QualifiedName;
1189
+ const dot = qn.indexOf(".");
1190
+ return dot >= 0 ? qn.slice(dot + 1) : qn;
1191
+ }
1192
+ }