@gtkx/gir 0.8.0 → 0.9.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.
Files changed (3) hide show
  1. package/package.json +4 -1
  2. package/src/parser.ts +48 -36
  3. package/src/types.ts +66 -44
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gtkx/gir",
3
- "version": "0.8.0",
3
+ "version": "0.9.1",
4
4
  "description": "GObject Introspection file parser for GTKX",
5
5
  "keywords": [
6
6
  "gtk",
@@ -29,6 +29,9 @@
29
29
  "files": [
30
30
  "src"
31
31
  ],
32
+ "dependencies": {
33
+ "fast-xml-parser": "^5.3.3"
34
+ },
32
35
  "scripts": {
33
36
  "test": "vitest run"
34
37
  }
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
- name: String(method["@_name"] ?? ""),
191
- cIdentifier: String(method["@_c:identifier"] ?? ""),
192
- returnType: this.parseReturnType(method["return-value"] as Record<string, unknown> | undefined),
193
- parameters: this.parseParameters(
194
- (method.parameters && typeof method.parameters === "object" && method.parameters !== null
195
- ? method.parameters
196
- : {}) as Record<string, unknown>,
197
- ),
198
- throws: method["@_throws"] === "1",
199
- doc: extractDoc(method),
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
- name: String(ctor["@_name"] ?? ""),
211
- cIdentifier: String(ctor["@_c:identifier"] ?? ""),
212
- returnType: this.parseReturnType(ctor["return-value"] as Record<string, unknown> | undefined),
213
- parameters: this.parseParameters(
214
- (ctor.parameters && typeof ctor.parameters === "object" && ctor.parameters !== null
215
- ? ctor.parameters
216
- : {}) as Record<string, unknown>,
217
- ),
218
- throws: ctor["@_throws"] === "1",
219
- doc: extractDoc(ctor),
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
- name: String(func["@_name"] ?? ""),
231
- cIdentifier: String(func["@_c:identifier"] ?? ""),
232
- returnType: this.parseReturnType(func["return-value"] as Record<string, unknown> | undefined),
233
- parameters: this.parseParameters(
234
- (func.parameters && typeof func.parameters === "object" && func.parameters !== null
235
- ? func.parameters
236
- : {}) as Record<string, unknown>,
237
- ),
238
- throws: func["@_throws"] === "1",
239
- doc: extractDoc(func),
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,12 +350,16 @@ 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. */
350
360
  listType?: "glist" | "gslist";
351
- /** Trampoline type for callbacks (asyncReady, destroy, sourceFunc, drawFunc, compareDataFunc, tickFunc). Default is "closure". */
352
- trampoline?: "asyncReady" | "destroy" | "sourceFunc" | "drawFunc" | "compareDataFunc" | "tickFunc";
361
+ /** Trampoline type for callbacks. Default is "closure". */
362
+ trampoline?: "asyncReady" | "destroy" | "drawFunc" | "scaleFormatValueFunc";
353
363
  /** Source type for asyncReady callback (the GObject source). */
354
364
  sourceType?: FfiTypeDescriptor;
355
365
  /** Result type for asyncReady callback (the GAsyncResult). */
@@ -441,7 +451,7 @@ export class TypeRegistry {
441
451
  * @param namespace - The namespace containing the class
442
452
  * @param name - The class name
443
453
  */
444
- registerType(namespace: string, name: string): void {
454
+ registerNativeClass(namespace: string, name: string): void {
445
455
  const transformedName = normalizeTypeName(name, namespace);
446
456
  this.types.set(`${namespace}.${name}`, {
447
457
  kind: "class",
@@ -557,7 +567,7 @@ export class TypeRegistry {
557
567
  const registry = new TypeRegistry();
558
568
  for (const ns of namespaces) {
559
569
  for (const cls of ns.classes) {
560
- registry.registerType(ns.name, cls.name);
570
+ registry.registerNativeClass(ns.name, cls.name);
561
571
  }
562
572
  for (const iface of ns.interfaces) {
563
573
  registry.registerInterface(ns.name, iface.name);
@@ -727,6 +737,7 @@ export class TypeMapper {
727
737
  private recordNames: Set<string> = new Set();
728
738
  private recordTransforms: Map<string, string> = new Map();
729
739
  private recordGlibTypes: Map<string, string> = new Map();
740
+ private skippedClasses: Set<string> = new Set();
730
741
  private onEnumUsed?: (enumName: string) => void;
731
742
  private onRecordUsed?: (recordName: string) => void;
732
743
  private onExternalTypeUsed?: (usage: ExternalTypeUsage) => void;
@@ -836,6 +847,14 @@ export class TypeMapper {
836
847
  this.currentNamespace = currentNamespace;
837
848
  }
838
849
 
850
+ registerSkippedClass(name: string): void {
851
+ this.skippedClasses.add(name);
852
+ }
853
+
854
+ clearSkippedClasses(): void {
855
+ this.skippedClasses.clear();
856
+ }
857
+
839
858
  /**
840
859
  * Maps a GIR type to TypeScript and FFI type descriptors.
841
860
  * @param girType - The GIR type to map
@@ -897,6 +916,12 @@ export class TypeMapper {
897
916
  if (isExternal) {
898
917
  this.onExternalTypeUsed?.(externalType as ExternalTypeUsage);
899
918
  } else if (registered.kind === "class" || registered.kind === "interface") {
919
+ if (this.skippedClasses.has(registered.name)) {
920
+ return {
921
+ ts: "unknown",
922
+ ffi: { type: "gobject", borrowed: isReturn },
923
+ };
924
+ }
900
925
  this.onSameNamespaceClassUsed?.(registered.transformedName, registered.name);
901
926
  } else if (registered.kind === "enum") {
902
927
  this.onEnumUsed?.(registered.transformedName);
@@ -1044,6 +1069,12 @@ export class TypeMapper {
1044
1069
  if (isExternal) {
1045
1070
  this.onExternalTypeUsed?.(externalType as ExternalTypeUsage);
1046
1071
  } else if (registered.kind === "class" || registered.kind === "interface") {
1072
+ if (this.skippedClasses.has(registered.name)) {
1073
+ return {
1074
+ ts: "unknown",
1075
+ ffi: { type: "gobject", borrowed: isReturn },
1076
+ };
1077
+ }
1047
1078
  this.onSameNamespaceClassUsed?.(registered.transformedName, registered.name);
1048
1079
  }
1049
1080
  if (registered.kind === "enum") {
@@ -1159,25 +1190,28 @@ export class TypeMapper {
1159
1190
  };
1160
1191
  }
1161
1192
 
1162
- if (param.type.name === "GLib.SourceFunc" || param.type.name === "SourceFunc") {
1163
- return {
1164
- ts: "() => boolean",
1165
- ffi: {
1166
- type: "callback",
1167
- trampoline: "sourceFunc",
1168
- },
1169
- };
1170
- }
1171
-
1172
1193
  if (param.type.name === "Gtk.DrawingAreaDrawFunc" || param.type.name === "DrawingAreaDrawFunc") {
1194
+ this.onExternalTypeUsed?.({
1195
+ namespace: "Cairo",
1196
+ name: "Context",
1197
+ transformedName: "Context",
1198
+ kind: "record",
1199
+ });
1200
+ this.onSameNamespaceClassUsed?.("DrawingArea", "DrawingArea");
1173
1201
  return {
1174
- ts: "(self: unknown, cr: unknown, width: number, height: number) => void",
1202
+ ts: "(self: DrawingArea, cr: Cairo.Context, width: number, height: number) => void",
1175
1203
  ffi: {
1176
1204
  type: "callback",
1177
1205
  trampoline: "drawFunc",
1178
1206
  argTypes: [
1179
1207
  { type: "gobject", borrowed: true },
1180
- { type: "int", size: 64, unsigned: true },
1208
+ {
1209
+ type: "boxed",
1210
+ borrowed: true,
1211
+ innerType: "CairoContext",
1212
+ lib: "libcairo-gobject.so.2",
1213
+ getTypeFn: "cairo_gobject_context_get_type",
1214
+ },
1181
1215
  { type: "int", size: 32, unsigned: false },
1182
1216
  { type: "int", size: 32, unsigned: false },
1183
1217
  ],
@@ -1185,34 +1219,6 @@ export class TypeMapper {
1185
1219
  };
1186
1220
  }
1187
1221
 
1188
- if (param.type.name === "GLib.CompareDataFunc" || param.type.name === "CompareDataFunc") {
1189
- return {
1190
- ts: "(a: unknown, b: unknown) => number",
1191
- ffi: {
1192
- type: "callback",
1193
- trampoline: "compareDataFunc",
1194
- argTypes: [
1195
- { type: "gobject", borrowed: true },
1196
- { type: "gobject", borrowed: true },
1197
- ],
1198
- },
1199
- };
1200
- }
1201
-
1202
- if (param.type.name === "Gtk.TickCallback" || param.type.name === "TickCallback") {
1203
- return {
1204
- ts: "(widget: unknown, frameClock: unknown) => boolean",
1205
- ffi: {
1206
- type: "callback",
1207
- trampoline: "tickFunc",
1208
- argTypes: [
1209
- { type: "gobject", borrowed: true },
1210
- { type: "gobject", borrowed: true },
1211
- ],
1212
- },
1213
- };
1214
- }
1215
-
1216
1222
  if (param.type.name === "GLib.Closure" || this.isCallback(param.type.name)) {
1217
1223
  return {
1218
1224
  ts: "(...args: unknown[]) => unknown",
@@ -1278,4 +1284,20 @@ export class TypeMapper {
1278
1284
  isNullable(param: GirParameter): boolean {
1279
1285
  return param.nullable === true || param.optional === true;
1280
1286
  }
1287
+
1288
+ hasUnsupportedCallback(param: GirParameter): boolean {
1289
+ const supportedCallbacks = [
1290
+ "Gio.AsyncReadyCallback",
1291
+ "GLib.DestroyNotify",
1292
+ "DestroyNotify",
1293
+ "Gtk.DrawingAreaDrawFunc",
1294
+ "DrawingAreaDrawFunc",
1295
+ ];
1296
+
1297
+ if (supportedCallbacks.includes(param.type.name)) {
1298
+ return false;
1299
+ }
1300
+
1301
+ return param.type.name === "GLib.Closure" || this.isCallback(param.type.name);
1302
+ }
1281
1303
  }