@gtkx/codegen 0.21.0
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/LICENSE +373 -0
- package/dist/dsl/context.d.ts +104 -0
- package/dist/dsl/context.d.ts.map +1 -0
- package/dist/dsl/context.js +140 -0
- package/dist/dsl/context.js.map +1 -0
- package/dist/dsl/emit.d.ts +28 -0
- package/dist/dsl/emit.d.ts.map +1 -0
- package/dist/dsl/emit.js +41 -0
- package/dist/dsl/emit.js.map +1 -0
- package/dist/dsl/identifier.d.ts +28 -0
- package/dist/dsl/identifier.d.ts.map +1 -0
- package/dist/dsl/identifier.js +45 -0
- package/dist/dsl/identifier.js.map +1 -0
- package/dist/dsl/imports.d.ts +58 -0
- package/dist/dsl/imports.d.ts.map +1 -0
- package/dist/dsl/imports.js +107 -0
- package/dist/dsl/imports.js.map +1 -0
- package/dist/dsl/module.d.ts +53 -0
- package/dist/dsl/module.d.ts.map +1 -0
- package/dist/dsl/module.js +76 -0
- package/dist/dsl/module.js.map +1 -0
- package/dist/ffi/pipeline.d.ts +19 -0
- package/dist/ffi/pipeline.d.ts.map +1 -0
- package/dist/ffi/pipeline.js +107 -0
- package/dist/ffi/pipeline.js.map +1 -0
- package/dist/fingerprint.d.ts +30 -0
- package/dist/fingerprint.d.ts.map +1 -0
- package/dist/fingerprint.js +33 -0
- package/dist/fingerprint.js.map +1 -0
- package/dist/gi-store.d.ts +34 -0
- package/dist/gi-store.d.ts.map +1 -0
- package/dist/gi-store.js +154 -0
- package/dist/gi-store.js.map +1 -0
- package/dist/gir/boxed.d.ts +66 -0
- package/dist/gir/boxed.d.ts.map +1 -0
- package/dist/gir/boxed.js +49 -0
- package/dist/gir/boxed.js.map +1 -0
- package/dist/gir/callback.d.ts +15 -0
- package/dist/gir/callback.d.ts.map +1 -0
- package/dist/gir/callback.js +17 -0
- package/dist/gir/callback.js.map +1 -0
- package/dist/gir/class.d.ts +49 -0
- package/dist/gir/class.d.ts.map +1 -0
- package/dist/gir/class.js +42 -0
- package/dist/gir/class.js.map +1 -0
- package/dist/gir/enum.d.ts +39 -0
- package/dist/gir/enum.d.ts.map +1 -0
- package/dist/gir/enum.js +24 -0
- package/dist/gir/enum.js.map +1 -0
- package/dist/gir/field.d.ts +27 -0
- package/dist/gir/field.d.ts.map +1 -0
- package/dist/gir/field.js +19 -0
- package/dist/gir/field.js.map +1 -0
- package/dist/gir/function.d.ts +47 -0
- package/dist/gir/function.d.ts.map +1 -0
- package/dist/gir/function.js +28 -0
- package/dist/gir/function.js.map +1 -0
- package/dist/gir/namespace.d.ts +65 -0
- package/dist/gir/namespace.d.ts.map +1 -0
- package/dist/gir/namespace.js +60 -0
- package/dist/gir/namespace.js.map +1 -0
- package/dist/gir/parameter.d.ts +82 -0
- package/dist/gir/parameter.d.ts.map +1 -0
- package/dist/gir/parameter.js +66 -0
- package/dist/gir/parameter.js.map +1 -0
- package/dist/gir/parse.d.ts +78 -0
- package/dist/gir/parse.d.ts.map +1 -0
- package/dist/gir/parse.js +155 -0
- package/dist/gir/parse.js.map +1 -0
- package/dist/gir/primitives.d.ts +36 -0
- package/dist/gir/primitives.d.ts.map +1 -0
- package/dist/gir/primitives.js +109 -0
- package/dist/gir/primitives.js.map +1 -0
- package/dist/gir/property.d.ts +29 -0
- package/dist/gir/property.d.ts.map +1 -0
- package/dist/gir/property.js +16 -0
- package/dist/gir/property.js.map +1 -0
- package/dist/gir/qualified-name.d.ts +37 -0
- package/dist/gir/qualified-name.d.ts.map +1 -0
- package/dist/gir/qualified-name.js +39 -0
- package/dist/gir/qualified-name.js.map +1 -0
- package/dist/gir/qualify.d.ts +32 -0
- package/dist/gir/qualify.d.ts.map +1 -0
- package/dist/gir/qualify.js +60 -0
- package/dist/gir/qualify.js.map +1 -0
- package/dist/gir/repository.d.ts +82 -0
- package/dist/gir/repository.d.ts.map +1 -0
- package/dist/gir/repository.js +122 -0
- package/dist/gir/repository.js.map +1 -0
- package/dist/gir/signal.d.ts +22 -0
- package/dist/gir/signal.d.ts.map +1 -0
- package/dist/gir/signal.js +20 -0
- package/dist/gir/signal.js.map +1 -0
- package/dist/gir/size.d.ts +67 -0
- package/dist/gir/size.d.ts.map +1 -0
- package/dist/gir/size.js +87 -0
- package/dist/gir/size.js.map +1 -0
- package/dist/gir/type-ref.d.ts +79 -0
- package/dist/gir/type-ref.d.ts.map +1 -0
- package/dist/gir/type-ref.js +101 -0
- package/dist/gir/type-ref.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/jsx-store.d.ts +22 -0
- package/dist/jsx-store.d.ts.map +1 -0
- package/dist/jsx-store.js +40 -0
- package/dist/jsx-store.js.map +1 -0
- package/dist/react/compounds-meta.d.ts +18 -0
- package/dist/react/compounds-meta.d.ts.map +1 -0
- package/dist/react/compounds-meta.js +93 -0
- package/dist/react/compounds-meta.js.map +1 -0
- package/dist/react/compounds.d.ts +27 -0
- package/dist/react/compounds.d.ts.map +1 -0
- package/dist/react/compounds.js +164 -0
- package/dist/react/compounds.js.map +1 -0
- package/dist/react/internal.d.ts +14 -0
- package/dist/react/internal.d.ts.map +1 -0
- package/dist/react/internal.js +79 -0
- package/dist/react/internal.js.map +1 -0
- package/dist/react/jsx.d.ts +22 -0
- package/dist/react/jsx.d.ts.map +1 -0
- package/dist/react/jsx.js +134 -0
- package/dist/react/jsx.js.map +1 -0
- package/dist/react/pipeline.d.ts +13 -0
- package/dist/react/pipeline.d.ts.map +1 -0
- package/dist/react/pipeline.js +25 -0
- package/dist/react/pipeline.js.map +1 -0
- package/dist/react/props.d.ts +38 -0
- package/dist/react/props.d.ts.map +1 -0
- package/dist/react/props.js +231 -0
- package/dist/react/props.js.map +1 -0
- package/dist/react/slot-props.d.ts +10 -0
- package/dist/react/slot-props.d.ts.map +1 -0
- package/dist/react/slot-props.js +56 -0
- package/dist/react/slot-props.js.map +1 -0
- package/dist/react/widgets.d.ts +83 -0
- package/dist/react/widgets.d.ts.map +1 -0
- package/dist/react/widgets.js +152 -0
- package/dist/react/widgets.js.map +1 -0
- package/dist/runner.d.ts +55 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +60 -0
- package/dist/runner.js.map +1 -0
- package/dist/store-fs.d.ts +109 -0
- package/dist/store-fs.d.ts.map +1 -0
- package/dist/store-fs.js +98 -0
- package/dist/store-fs.js.map +1 -0
- package/dist/transpile.d.ts +32 -0
- package/dist/transpile.d.ts.map +1 -0
- package/dist/transpile.js +63 -0
- package/dist/transpile.js.map +1 -0
- package/dist/typecheck-store.d.ts +41 -0
- package/dist/typecheck-store.d.ts.map +1 -0
- package/dist/typecheck-store.js +102 -0
- package/dist/typecheck-store.js.map +1 -0
- package/dist/writers/alias.d.ts +13 -0
- package/dist/writers/alias.d.ts.map +1 -0
- package/dist/writers/alias.js +17 -0
- package/dist/writers/alias.js.map +1 -0
- package/dist/writers/async.d.ts +22 -0
- package/dist/writers/async.d.ts.map +1 -0
- package/dist/writers/async.js +48 -0
- package/dist/writers/async.js.map +1 -0
- package/dist/writers/boxed-constructor.d.ts +26 -0
- package/dist/writers/boxed-constructor.d.ts.map +1 -0
- package/dist/writers/boxed-constructor.js +85 -0
- package/dist/writers/boxed-constructor.js.map +1 -0
- package/dist/writers/boxed-field-accessor.d.ts +18 -0
- package/dist/writers/boxed-field-accessor.d.ts.map +1 -0
- package/dist/writers/boxed-field-accessor.js +260 -0
- package/dist/writers/boxed-field-accessor.js.map +1 -0
- package/dist/writers/boxed-layout.d.ts +27 -0
- package/dist/writers/boxed-layout.d.ts.map +1 -0
- package/dist/writers/boxed-layout.js +128 -0
- package/dist/writers/boxed-layout.js.map +1 -0
- package/dist/writers/boxed.d.ts +20 -0
- package/dist/writers/boxed.d.ts.map +1 -0
- package/dist/writers/boxed.js +71 -0
- package/dist/writers/boxed.js.map +1 -0
- package/dist/writers/callables.d.ts +124 -0
- package/dist/writers/callables.d.ts.map +1 -0
- package/dist/writers/callables.js +283 -0
- package/dist/writers/callables.js.map +1 -0
- package/dist/writers/callback.d.ts +16 -0
- package/dist/writers/callback.d.ts.map +1 -0
- package/dist/writers/callback.js +38 -0
- package/dist/writers/callback.js.map +1 -0
- package/dist/writers/class-struct-record.d.ts +31 -0
- package/dist/writers/class-struct-record.d.ts.map +1 -0
- package/dist/writers/class-struct-record.js +67 -0
- package/dist/writers/class-struct-record.js.map +1 -0
- package/dist/writers/class-struct.d.ts +22 -0
- package/dist/writers/class-struct.d.ts.map +1 -0
- package/dist/writers/class-struct.js +85 -0
- package/dist/writers/class-struct.js.map +1 -0
- package/dist/writers/class.d.ts +16 -0
- package/dist/writers/class.d.ts.map +1 -0
- package/dist/writers/class.js +307 -0
- package/dist/writers/class.js.map +1 -0
- package/dist/writers/constant.d.ts +15 -0
- package/dist/writers/constant.d.ts.map +1 -0
- package/dist/writers/constant.js +23 -0
- package/dist/writers/constant.js.map +1 -0
- package/dist/writers/constants.d.ts +15 -0
- package/dist/writers/constants.d.ts.map +1 -0
- package/dist/writers/constants.js +23 -0
- package/dist/writers/constants.js.map +1 -0
- package/dist/writers/constructor-props.d.ts +32 -0
- package/dist/writers/constructor-props.d.ts.map +1 -0
- package/dist/writers/constructor-props.js +110 -0
- package/dist/writers/constructor-props.js.map +1 -0
- package/dist/writers/enum.d.ts +21 -0
- package/dist/writers/enum.d.ts.map +1 -0
- package/dist/writers/enum.js +48 -0
- package/dist/writers/enum.js.map +1 -0
- package/dist/writers/function.d.ts +40 -0
- package/dist/writers/function.d.ts.map +1 -0
- package/dist/writers/function.js +127 -0
- package/dist/writers/function.js.map +1 -0
- package/dist/writers/gtype-binding.d.ts +19 -0
- package/dist/writers/gtype-binding.d.ts.map +1 -0
- package/dist/writers/gtype-binding.js +40 -0
- package/dist/writers/gtype-binding.js.map +1 -0
- package/dist/writers/inheritance.d.ts +48 -0
- package/dist/writers/inheritance.d.ts.map +1 -0
- package/dist/writers/inheritance.js +90 -0
- package/dist/writers/inheritance.js.map +1 -0
- package/dist/writers/interface.d.ts +16 -0
- package/dist/writers/interface.d.ts.map +1 -0
- package/dist/writers/interface.js +155 -0
- package/dist/writers/interface.js.map +1 -0
- package/dist/writers/method.d.ts +150 -0
- package/dist/writers/method.d.ts.map +1 -0
- package/dist/writers/method.js +510 -0
- package/dist/writers/method.js.map +1 -0
- package/dist/writers/param-classify.d.ts +93 -0
- package/dist/writers/param-classify.d.ts.map +1 -0
- package/dist/writers/param-classify.js +163 -0
- package/dist/writers/param-classify.js.map +1 -0
- package/dist/writers/property-accessor.d.ts +19 -0
- package/dist/writers/property-accessor.d.ts.map +1 -0
- package/dist/writers/property-accessor.js +117 -0
- package/dist/writers/property-accessor.js.map +1 -0
- package/dist/writers/registration.d.ts +27 -0
- package/dist/writers/registration.d.ts.map +1 -0
- package/dist/writers/registration.js +30 -0
- package/dist/writers/registration.js.map +1 -0
- package/dist/writers/return-wrap.d.ts +39 -0
- package/dist/writers/return-wrap.d.ts.map +1 -0
- package/dist/writers/return-wrap.js +152 -0
- package/dist/writers/return-wrap.js.map +1 -0
- package/dist/writers/runtime-override.d.ts +18 -0
- package/dist/writers/runtime-override.d.ts.map +1 -0
- package/dist/writers/runtime-override.js +44 -0
- package/dist/writers/runtime-override.js.map +1 -0
- package/dist/writers/signal.d.ts +21 -0
- package/dist/writers/signal.d.ts.map +1 -0
- package/dist/writers/signal.js +260 -0
- package/dist/writers/signal.js.map +1 -0
- package/dist/writers/ts-type.d.ts +50 -0
- package/dist/writers/ts-type.d.ts.map +1 -0
- package/dist/writers/ts-type.js +75 -0
- package/dist/writers/ts-type.js.map +1 -0
- package/dist/writers/types-ts.d.ts +27 -0
- package/dist/writers/types-ts.d.ts.map +1 -0
- package/dist/writers/types-ts.js +97 -0
- package/dist/writers/types-ts.js.map +1 -0
- package/dist/writers/value.d.ts +89 -0
- package/dist/writers/value.d.ts.map +1 -0
- package/dist/writers/value.js +402 -0
- package/dist/writers/value.js.map +1 -0
- package/package.json +55 -0
- package/src/dsl/context.ts +146 -0
- package/src/dsl/emit.ts +42 -0
- package/src/dsl/identifier.ts +52 -0
- package/src/dsl/imports.ts +109 -0
- package/src/dsl/module.ts +75 -0
- package/src/ffi/pipeline.ts +113 -0
- package/src/fingerprint.ts +50 -0
- package/src/gi-store.ts +199 -0
- package/src/gir/boxed.ts +94 -0
- package/src/gir/callback.ts +26 -0
- package/src/gir/class.ts +79 -0
- package/src/gir/enum.ts +55 -0
- package/src/gir/field.ts +40 -0
- package/src/gir/function.ts +67 -0
- package/src/gir/namespace.ts +118 -0
- package/src/gir/parameter.ts +120 -0
- package/src/gir/parse.ts +171 -0
- package/src/gir/primitives.ts +137 -0
- package/src/gir/property.ts +39 -0
- package/src/gir/qualified-name.ts +55 -0
- package/src/gir/qualify.ts +64 -0
- package/src/gir/repository.ts +149 -0
- package/src/gir/signal.ts +36 -0
- package/src/gir/size.ts +129 -0
- package/src/gir/type-ref.ts +180 -0
- package/src/index.ts +16 -0
- package/src/jsx-store.ts +53 -0
- package/src/react/compounds-meta.ts +99 -0
- package/src/react/compounds.ts +204 -0
- package/src/react/internal.ts +91 -0
- package/src/react/jsx.ts +155 -0
- package/src/react/pipeline.ts +29 -0
- package/src/react/props.ts +307 -0
- package/src/react/slot-props.ts +57 -0
- package/src/react/widgets.ts +185 -0
- package/src/runner.ts +89 -0
- package/src/store-fs.ts +157 -0
- package/src/transpile.ts +80 -0
- package/src/typecheck-store.ts +136 -0
- package/src/writers/alias.ts +19 -0
- package/src/writers/async.ts +44 -0
- package/src/writers/boxed-constructor.ts +105 -0
- package/src/writers/boxed-field-accessor.ts +306 -0
- package/src/writers/boxed-layout.ts +166 -0
- package/src/writers/boxed.ts +77 -0
- package/src/writers/callables.ts +339 -0
- package/src/writers/callback.ts +40 -0
- package/src/writers/class-struct-record.ts +75 -0
- package/src/writers/class-struct.ts +96 -0
- package/src/writers/class.ts +384 -0
- package/src/writers/constant.ts +29 -0
- package/src/writers/constructor-props.ts +130 -0
- package/src/writers/enum.ts +53 -0
- package/src/writers/function.ts +136 -0
- package/src/writers/gtype-binding.ts +48 -0
- package/src/writers/inheritance.ts +104 -0
- package/src/writers/interface.ts +168 -0
- package/src/writers/method.ts +678 -0
- package/src/writers/param-classify.ts +178 -0
- package/src/writers/property-accessor.ts +139 -0
- package/src/writers/registration.ts +42 -0
- package/src/writers/return-wrap.ts +180 -0
- package/src/writers/runtime-override.ts +59 -0
- package/src/writers/signal.ts +318 -0
- package/src/writers/ts-type.ts +115 -0
- package/src/writers/value.ts +485 -0
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
import { toCamelCase } from "@gtkx/utils";
|
|
2
|
+
import type { ModuleContext } from "../dsl/context.js";
|
|
3
|
+
import { indent } from "../dsl/emit.js";
|
|
4
|
+
import type { GirFunction } from "../gir/function.js";
|
|
5
|
+
import { callableReferencesClassStruct } from "./class-struct-record.js";
|
|
6
|
+
import { renderFnExpression } from "./function.js";
|
|
7
|
+
import { methodExportName, renderMethodBody, renderMethodReturnType, renderMethodSignature } from "./method.js";
|
|
8
|
+
import { renderRuntimeOverride } from "./runtime-override.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Constructors, static functions, and instance methods of a class, interface,
|
|
12
|
+
* or boxed record.
|
|
13
|
+
*/
|
|
14
|
+
export type Callables = {
|
|
15
|
+
readonly constructors: readonly GirFunction[];
|
|
16
|
+
readonly functions: readonly GirFunction[];
|
|
17
|
+
readonly methods: readonly GirFunction[];
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Drops callables that lack a `c:identifier` or repeat one already retained.
|
|
22
|
+
*
|
|
23
|
+
* GIR sometimes lists the same callable twice (e.g. as both a class function
|
|
24
|
+
* and a constructor); the C identifier is the canonical key.
|
|
25
|
+
*
|
|
26
|
+
* @param callables - The raw GIR callables
|
|
27
|
+
*/
|
|
28
|
+
export const dedupeCallables = (callables: readonly GirFunction[]): readonly GirFunction[] => {
|
|
29
|
+
const seen = new Set<string>();
|
|
30
|
+
const result: GirFunction[] = [];
|
|
31
|
+
for (const callable of callables) {
|
|
32
|
+
if (callable.cIdentifier === undefined) continue;
|
|
33
|
+
if (seen.has(callable.cIdentifier)) continue;
|
|
34
|
+
seen.add(callable.cIdentifier);
|
|
35
|
+
result.push(callable);
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Appends the top-level `const fn = t.fn(...)` binding for every introspectable
|
|
42
|
+
* callable that has a C identifier and is not shadowed.
|
|
43
|
+
*
|
|
44
|
+
* @param context - The module context
|
|
45
|
+
* @param callables - The callables to bind
|
|
46
|
+
*/
|
|
47
|
+
/**
|
|
48
|
+
* Appends the top-level `const fn = t.fn(...)` binding for a single callable,
|
|
49
|
+
* deduplicated by its C identifier. Used when flattening interface and
|
|
50
|
+
* prerequisite methods onto a type one at a time.
|
|
51
|
+
*
|
|
52
|
+
* @param context - The module context
|
|
53
|
+
* @param method - The callable to bind
|
|
54
|
+
*/
|
|
55
|
+
export const appendMethodBinding = (context: ModuleContext, method: GirFunction): void => {
|
|
56
|
+
if (method.cIdentifier === undefined) return;
|
|
57
|
+
if (callableReferencesClassStruct(context, method)) return;
|
|
58
|
+
const expression = renderFnExpression(context, method);
|
|
59
|
+
if (expression === undefined) return;
|
|
60
|
+
context.module.appendBinding(`const ${method.cIdentifier} = ${expression};`, method.cIdentifier);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const emitBindings = (context: ModuleContext, callables: Callables): void => {
|
|
64
|
+
const all = [...callables.constructors, ...callables.functions, ...callables.methods];
|
|
65
|
+
for (const callable of all) {
|
|
66
|
+
if (!callable.introspectable) continue;
|
|
67
|
+
if (callable.shadowedBy !== undefined) continue;
|
|
68
|
+
if (callable.cIdentifier === undefined) continue;
|
|
69
|
+
if (callableReferencesClassStruct(context, callable)) continue;
|
|
70
|
+
const expression = renderFnExpression(context, callable);
|
|
71
|
+
if (expression === undefined) continue;
|
|
72
|
+
context.module.appendBinding(`const ${callable.cIdentifier} = ${expression};`, callable.cIdentifier);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* How a type's static `<constructor>` factories wrap their result:
|
|
78
|
+
*
|
|
79
|
+
* - `"gobject"` — resolve the wrapper from the runtime GLib type (a class).
|
|
80
|
+
* - `"interface"` — resolve the runtime type, falling back to the closest
|
|
81
|
+
* registered ancestor that implements the interface, then the interface itself.
|
|
82
|
+
* - `"boxed"` — wrap as the exact value-type class (boxed records).
|
|
83
|
+
*/
|
|
84
|
+
export type ConstructorWrap = "gobject" | "interface" | "boxed";
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Renders a `static <name>(...): Owner` factory method for a GIR `<constructor>`.
|
|
88
|
+
*
|
|
89
|
+
* Returns `undefined` for non-introspectable, shadowed, identifier-less, or
|
|
90
|
+
* `constructor`-named entries.
|
|
91
|
+
*
|
|
92
|
+
* @param context - The module context
|
|
93
|
+
* @param callable - The GIR constructor callable
|
|
94
|
+
* @param ownerClassName - The local class name that wraps the result
|
|
95
|
+
* @param wrap - How the result is lifted to its JavaScript wrapper
|
|
96
|
+
*/
|
|
97
|
+
const renderConstructorStatic = (
|
|
98
|
+
context: ModuleContext,
|
|
99
|
+
callable: GirFunction,
|
|
100
|
+
ownerClassName: string,
|
|
101
|
+
wrap: ConstructorWrap,
|
|
102
|
+
): string | undefined => {
|
|
103
|
+
if (!isEmittableCallable(context, callable)) return undefined;
|
|
104
|
+
const name = constructorMemberName(callable.name);
|
|
105
|
+
if (name === undefined) return undefined;
|
|
106
|
+
const cIdentifier = callable.cIdentifier;
|
|
107
|
+
if (cIdentifier === undefined) return undefined;
|
|
108
|
+
const signature = renderMethodSignature(context, callable);
|
|
109
|
+
const body = renderMethodBody(context, callable, {
|
|
110
|
+
bindingExpression: cIdentifier,
|
|
111
|
+
isStatic: true,
|
|
112
|
+
returnAs: wrap === "gobject" ? { via: "gobject" } : { via: wrap, className: ownerClassName },
|
|
113
|
+
});
|
|
114
|
+
return `static ${name}(${signature}): ${ownerClassName} {\n${indent(body, 1)}\n}`;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Renders a `static <name>(...): Return` member for a GIR `<function>`.
|
|
119
|
+
*
|
|
120
|
+
* Returns `undefined` when the callable cannot be emitted on a class body.
|
|
121
|
+
*
|
|
122
|
+
* @param context - The module context
|
|
123
|
+
* @param callable - The GIR function callable
|
|
124
|
+
*/
|
|
125
|
+
const renderStaticMember = (context: ModuleContext, callable: GirFunction): string | undefined => {
|
|
126
|
+
if (!isEmittableCallable(context, callable)) return undefined;
|
|
127
|
+
const cIdentifier = callable.cIdentifier;
|
|
128
|
+
if (cIdentifier === undefined) return undefined;
|
|
129
|
+
const name = toCamelCase(callable.name);
|
|
130
|
+
if (name === "constructor") return undefined;
|
|
131
|
+
const signature = renderMethodSignature(context, callable);
|
|
132
|
+
const returnType = renderMethodReturnType(context, callable);
|
|
133
|
+
const body = renderMethodBody(context, callable, { bindingExpression: cIdentifier, isStatic: true });
|
|
134
|
+
return `static ${name}(${signature}): ${returnType} {\n${indent(body, 1)}\n}`;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Renders an instance method body for a GIR `<method>`.
|
|
139
|
+
*
|
|
140
|
+
* Hand-written runtime overrides (e.g. `g_value_get_boxed`) short-circuit the
|
|
141
|
+
* usual FFI call body with a throwing stub that the runtime replaces on the
|
|
142
|
+
* prototype at module load.
|
|
143
|
+
*
|
|
144
|
+
* Returns `undefined` for non-emittable callables.
|
|
145
|
+
*
|
|
146
|
+
* @param context - The module context
|
|
147
|
+
* @param callable - The GIR method callable
|
|
148
|
+
*/
|
|
149
|
+
export const renderInstanceMethod = (
|
|
150
|
+
context: ModuleContext,
|
|
151
|
+
callable: GirFunction,
|
|
152
|
+
nameOverride?: string,
|
|
153
|
+
): string | undefined => {
|
|
154
|
+
if (!isEmittableCallable(context, callable)) return undefined;
|
|
155
|
+
const cIdentifier = callable.cIdentifier;
|
|
156
|
+
if (cIdentifier === undefined) return undefined;
|
|
157
|
+
const name = nameOverride ?? methodExportName(callable);
|
|
158
|
+
if (name === "constructor") return undefined;
|
|
159
|
+
const override = renderRuntimeOverride(callable, name);
|
|
160
|
+
if (override !== undefined) return override;
|
|
161
|
+
const signature = renderMethodSignature(context, callable);
|
|
162
|
+
const returnType = renderMethodReturnType(context, callable);
|
|
163
|
+
const body = renderMethodBody(context, callable, { bindingExpression: cIdentifier, isStatic: false });
|
|
164
|
+
return `${name}(${signature}): ${returnType} {\n${indent(body, 1)}\n}`;
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Renders the legacy-name alias of a method that has been shadowed by a
|
|
169
|
+
* variadic or kebab-cased successor.
|
|
170
|
+
*
|
|
171
|
+
* Returns `undefined` when the alias collides with `constructor` or the
|
|
172
|
+
* shadower lacks a C identifier.
|
|
173
|
+
*
|
|
174
|
+
* @param context - The module context
|
|
175
|
+
* @param original - The shadowed callable whose name should remain reachable
|
|
176
|
+
* @param shadower - The callable the alias dispatches into
|
|
177
|
+
*/
|
|
178
|
+
const renderInstanceAlias = (
|
|
179
|
+
context: ModuleContext,
|
|
180
|
+
original: GirFunction,
|
|
181
|
+
shadower: GirFunction,
|
|
182
|
+
): string | undefined => {
|
|
183
|
+
if (shadower.cIdentifier === undefined) return undefined;
|
|
184
|
+
const aliasName = toCamelCase(original.name);
|
|
185
|
+
if (aliasName === "constructor") return undefined;
|
|
186
|
+
const signature = renderMethodSignature(context, shadower);
|
|
187
|
+
const returnType = renderMethodReturnType(context, shadower);
|
|
188
|
+
const body = renderMethodBody(context, shadower, { bindingExpression: shadower.cIdentifier, isStatic: false });
|
|
189
|
+
return `${aliasName}(${signature}): ${returnType} {\n${indent(body, 1)}\n}`;
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Inputs for {@link appendShadowedAliases}.
|
|
194
|
+
*/
|
|
195
|
+
export type ShadowedAliasOptions = {
|
|
196
|
+
readonly context: ModuleContext;
|
|
197
|
+
/** The full list of method callables. */
|
|
198
|
+
readonly methods: readonly GirFunction[];
|
|
199
|
+
/** Lookup table for shadower resolution. */
|
|
200
|
+
readonly methodByName: ReadonlyMap<string, GirFunction>;
|
|
201
|
+
/** The accumulating members list to append to. */
|
|
202
|
+
readonly members: string[];
|
|
203
|
+
/** Set of names already emitted on the class body. */
|
|
204
|
+
readonly claimedNames: Set<string>;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Appends shadowed-method aliases for every callable in `methods` whose
|
|
209
|
+
* shadower is introspectable.
|
|
210
|
+
*
|
|
211
|
+
* Records each emitted alias name in `claimedNames` so subsequent renderers
|
|
212
|
+
* can detect collisions.
|
|
213
|
+
*
|
|
214
|
+
* @param options - {@link ShadowedAliasOptions}
|
|
215
|
+
*/
|
|
216
|
+
export const appendShadowedAliases = (options: ShadowedAliasOptions): void => {
|
|
217
|
+
const { context, methods, methodByName, members, claimedNames } = options;
|
|
218
|
+
for (const callable of methods) {
|
|
219
|
+
if (callable.shadowedBy === undefined) continue;
|
|
220
|
+
if (callable.introspectable) continue;
|
|
221
|
+
const shadower = methodByName.get(callable.shadowedBy);
|
|
222
|
+
if (shadower === undefined || !shadower.introspectable) continue;
|
|
223
|
+
const aliasName = toCamelCase(callable.name);
|
|
224
|
+
if (claimedNames.has(aliasName)) continue;
|
|
225
|
+
const block = renderInstanceAlias(context, callable, shadower);
|
|
226
|
+
if (block !== undefined) {
|
|
227
|
+
members.push(block);
|
|
228
|
+
claimedNames.add(aliasName);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Indexes a list of method callables by their GIR name for shadower lookup.
|
|
235
|
+
*/
|
|
236
|
+
export const indexMethodsByName = (methods: readonly GirFunction[]): ReadonlyMap<string, GirFunction> => {
|
|
237
|
+
const map = new Map<string, GirFunction>();
|
|
238
|
+
for (const callable of methods) map.set(callable.name, callable);
|
|
239
|
+
return map;
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const isEmittableCallable = (context: ModuleContext, callable: GirFunction): boolean =>
|
|
243
|
+
callable.introspectable &&
|
|
244
|
+
callable.shadowedBy === undefined &&
|
|
245
|
+
callable.cIdentifier !== undefined &&
|
|
246
|
+
!callableReferencesClassStruct(context, callable);
|
|
247
|
+
|
|
248
|
+
const constructorMemberName = (girName: string): string | undefined => {
|
|
249
|
+
const camel = toCamelCase(girName);
|
|
250
|
+
if (camel === "constructor") return undefined;
|
|
251
|
+
return camel;
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Renders the shared head of a class/interface/boxed body: every `static`
|
|
256
|
+
* constructor factory and every `static` namespace function on the same type.
|
|
257
|
+
*
|
|
258
|
+
* @param context - The module context
|
|
259
|
+
* @param callables - The class's emittable callables
|
|
260
|
+
* @param ownerClassName - The local PascalCase class name
|
|
261
|
+
* @param wrap - How static constructors lift their result to a wrapper
|
|
262
|
+
*/
|
|
263
|
+
export const renderStaticHead = (
|
|
264
|
+
context: ModuleContext,
|
|
265
|
+
callables: Callables,
|
|
266
|
+
ownerClassName: string,
|
|
267
|
+
wrap: ConstructorWrap,
|
|
268
|
+
): readonly string[] => {
|
|
269
|
+
const blocks: string[] = [];
|
|
270
|
+
for (const callable of callables.constructors) {
|
|
271
|
+
const block = renderConstructorStatic(context, callable, ownerClassName, wrap);
|
|
272
|
+
if (block !== undefined) blocks.push(block);
|
|
273
|
+
}
|
|
274
|
+
for (const callable of callables.functions) {
|
|
275
|
+
const block = renderStaticMember(context, callable);
|
|
276
|
+
if (block !== undefined) blocks.push(block);
|
|
277
|
+
}
|
|
278
|
+
return blocks;
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Renders the plain instance methods of a class/interface/boxed body, the
|
|
283
|
+
* variant that does NOT consult inherited-signature conflicts. Used for
|
|
284
|
+
* interfaces and boxed records that do not extend other widget shapes.
|
|
285
|
+
*
|
|
286
|
+
* Records each emitted method name in `claimedNames` so subsequent property
|
|
287
|
+
* and signal-method renderers can detect collisions.
|
|
288
|
+
*/
|
|
289
|
+
const renderPlainInstanceMethods = (
|
|
290
|
+
context: ModuleContext,
|
|
291
|
+
methods: readonly GirFunction[],
|
|
292
|
+
claimedNames: Set<string>,
|
|
293
|
+
): readonly string[] => {
|
|
294
|
+
const blocks: string[] = [];
|
|
295
|
+
for (const callable of methods) {
|
|
296
|
+
const block = renderInstanceMethod(context, callable);
|
|
297
|
+
if (block === undefined) continue;
|
|
298
|
+
blocks.push(block);
|
|
299
|
+
claimedNames.add(methodExportName(callable));
|
|
300
|
+
}
|
|
301
|
+
return blocks;
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Inputs for {@link renderPlainTypeMembers}.
|
|
306
|
+
*/
|
|
307
|
+
export type PlainTypeMembersOptions = {
|
|
308
|
+
readonly context: ModuleContext;
|
|
309
|
+
readonly className: string;
|
|
310
|
+
readonly callables: Callables;
|
|
311
|
+
/** Whether to prepend `declare __gtype__: number;`. */
|
|
312
|
+
readonly hasGType: boolean;
|
|
313
|
+
/** How static constructors lift their result to a wrapper. */
|
|
314
|
+
readonly wrap: ConstructorWrap;
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Renders the shared head of an interface or boxed class body — `__gtype__`
|
|
319
|
+
* declaration (optional), statics, plain instance methods, and
|
|
320
|
+
* shadowed-method aliases — plus the `claimedNames` set populated by those
|
|
321
|
+
* renderers.
|
|
322
|
+
*
|
|
323
|
+
* Callers append the constructor, property accessors, field accessors, and
|
|
324
|
+
* signal members on top of the returned members list. The class writer takes
|
|
325
|
+
* a different path because it has to consult inherited signatures.
|
|
326
|
+
*/
|
|
327
|
+
export const renderPlainTypeMembers = (
|
|
328
|
+
options: PlainTypeMembersOptions,
|
|
329
|
+
): { readonly members: string[]; readonly claimedNames: Set<string> } => {
|
|
330
|
+
const { context, className, callables, hasGType, wrap } = options;
|
|
331
|
+
const members: string[] = [];
|
|
332
|
+
if (hasGType) members.push("declare __gtype__: number;");
|
|
333
|
+
const claimedNames = new Set<string>();
|
|
334
|
+
members.push(...renderStaticHead(context, callables, className, wrap));
|
|
335
|
+
members.push(...renderPlainInstanceMethods(context, callables.methods, claimedNames));
|
|
336
|
+
const methodByName = indexMethodsByName(callables.methods);
|
|
337
|
+
appendShadowedAliases({ context, methods: callables.methods, methodByName, members, claimedNames });
|
|
338
|
+
return { members, claimedNames };
|
|
339
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ModuleContext } from "../dsl/context.js";
|
|
2
|
+
import type { GirCallback } from "../gir/callback.js";
|
|
3
|
+
import type { GirFunction } from "../gir/function.js";
|
|
4
|
+
import { renderMethodReturnType, renderMethodSignature } from "./method.js";
|
|
5
|
+
|
|
6
|
+
const callbackAsFunction = (callback: GirCallback): GirFunction => ({
|
|
7
|
+
kind: "function",
|
|
8
|
+
name: callback.name,
|
|
9
|
+
cIdentifier: undefined,
|
|
10
|
+
throws: false,
|
|
11
|
+
introspectable: callback.introspectable,
|
|
12
|
+
shadows: undefined,
|
|
13
|
+
shadowedBy: undefined,
|
|
14
|
+
movedTo: undefined,
|
|
15
|
+
instance: undefined,
|
|
16
|
+
parameters: callback.parameters,
|
|
17
|
+
returnValue: callback.returnValue,
|
|
18
|
+
invoker: undefined,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Emits an `export type` alias for a top-level GIR `<callback>`.
|
|
23
|
+
*
|
|
24
|
+
* The callback is surfaced under its GIR `name` verbatim with a fully typed
|
|
25
|
+
* call signature: input parameters follow {@link renderMethodSignature} (the
|
|
26
|
+
* folded `user_data`/`GDestroyNotify` slots are dropped) and the return follows
|
|
27
|
+
* {@link renderMethodReturnType}, so out-parameters tuple into the return the
|
|
28
|
+
* same way a method's would.
|
|
29
|
+
*
|
|
30
|
+
* @param context - The module context
|
|
31
|
+
* @param callback - The callback to emit
|
|
32
|
+
*/
|
|
33
|
+
export const emitCallback = (context: ModuleContext, callback: GirCallback): void => {
|
|
34
|
+
if (!callback.introspectable) return;
|
|
35
|
+
if (callback.name.length === 0) return;
|
|
36
|
+
const fn = callbackAsFunction(callback);
|
|
37
|
+
const signature = renderMethodSignature(context, fn);
|
|
38
|
+
const returnType = renderMethodReturnType(context, fn);
|
|
39
|
+
context.module.appendDeclaration(`export type ${callback.name} = (${signature}) => ${returnType};`);
|
|
40
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { ModuleContext } from "../dsl/context.js";
|
|
2
|
+
import type { GirBoxed } from "../gir/boxed.js";
|
|
3
|
+
import type { GirFunction } from "../gir/function.js";
|
|
4
|
+
import type { GirTypeRef } from "../gir/type-ref.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* GObject's class- and interface-struct roots. Every concrete class struct
|
|
8
|
+
* (`GEnumClass`, `GFlagsClass`, …) embeds one of these as its first field; the
|
|
9
|
+
* roots themselves open with a bare `GType` and are matched by name.
|
|
10
|
+
*/
|
|
11
|
+
const GTYPE_STRUCT_ROOTS = new Set(["GObject.TypeClass", "GObject.TypeInterface"]);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Class/interface-struct records that carry no embedded `GTypeClass`/
|
|
15
|
+
* `GTypeInterface` marker and therefore have to be named outright.
|
|
16
|
+
*/
|
|
17
|
+
const EXPLICIT_CLASS_STRUCTS = new Set(["Pango.AttrClass"]);
|
|
18
|
+
|
|
19
|
+
const qualify = (namespaceName: string, name: string): string => `${namespaceName}.${name}`;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Reports whether a `<record>` is a GObject class- or interface-struct — the
|
|
23
|
+
* runtime vtable of a type rather than a marshallable value. These are never
|
|
24
|
+
* constructed or passed by value from JavaScript, so codegen emits neither the
|
|
25
|
+
* record nor any binding that references it.
|
|
26
|
+
*
|
|
27
|
+
* @param namespaceName - The namespace the record lives in
|
|
28
|
+
* @param boxed - The record under consideration
|
|
29
|
+
*/
|
|
30
|
+
export const isClassStructRecord = (namespaceName: string, boxed: GirBoxed): boolean => {
|
|
31
|
+
const qualified = qualify(namespaceName, boxed.name);
|
|
32
|
+
if (GTYPE_STRUCT_ROOTS.has(qualified) || EXPLICIT_CLASS_STRUCTS.has(qualified)) return true;
|
|
33
|
+
const first = boxed.fields[0];
|
|
34
|
+
if (first === undefined || first.type === undefined || first.type.kind !== "named") return false;
|
|
35
|
+
const fieldNamespace = first.type.namespaceName ?? namespaceName;
|
|
36
|
+
return GTYPE_STRUCT_ROOTS.has(qualify(fieldNamespace, first.type.typeName));
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const refIsClassStruct = (context: ModuleContext, ref: GirTypeRef | undefined): boolean => {
|
|
40
|
+
if (ref === undefined) return false;
|
|
41
|
+
switch (ref.kind) {
|
|
42
|
+
case "named": {
|
|
43
|
+
const namespaceName = ref.namespaceName ?? context.namespace.name;
|
|
44
|
+
const resolved = context.repository.resolveNamed(namespaceName, ref.typeName);
|
|
45
|
+
if (resolved === undefined || resolved.kind !== "boxed") return false;
|
|
46
|
+
return isClassStructRecord(resolved.namespace.name, resolved.value);
|
|
47
|
+
}
|
|
48
|
+
case "array":
|
|
49
|
+
case "list":
|
|
50
|
+
return refIsClassStruct(context, ref.element);
|
|
51
|
+
default:
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Reports whether a type reference resolves to a class/interface-struct record,
|
|
58
|
+
* following array and list element types.
|
|
59
|
+
*
|
|
60
|
+
* @param context - The module context
|
|
61
|
+
* @param ref - The type reference, or `undefined`
|
|
62
|
+
*/
|
|
63
|
+
export const typeRefIsClassStruct = (context: ModuleContext, ref: GirTypeRef | undefined): boolean =>
|
|
64
|
+
refIsClassStruct(context, ref);
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Reports whether a callable's return type or any parameter resolves to a
|
|
68
|
+
* class/interface-struct record, so its binding and wrapper can be dropped.
|
|
69
|
+
*
|
|
70
|
+
* @param context - The module context
|
|
71
|
+
* @param fn - The callable
|
|
72
|
+
*/
|
|
73
|
+
export const callableReferencesClassStruct = (context: ModuleContext, fn: GirFunction): boolean =>
|
|
74
|
+
refIsClassStruct(context, fn.returnValue.type) ||
|
|
75
|
+
fn.parameters.some((parameter) => refIsClassStruct(context, parameter.type));
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { quote, toCamelCase, toIdentifier, toPascalCase } from "@gtkx/utils";
|
|
2
|
+
import type { ModuleContext } from "../dsl/context.js";
|
|
3
|
+
import { indent } from "../dsl/emit.js";
|
|
4
|
+
import { callbackFromNode, type GirCallback } from "../gir/callback.js";
|
|
5
|
+
import type { GirClass } from "../gir/class.js";
|
|
6
|
+
import type { GirField } from "../gir/field.js";
|
|
7
|
+
import type { GirTypeRef } from "../gir/type-ref.js";
|
|
8
|
+
import { computeBoxedFieldSlots } from "./boxed-layout.js";
|
|
9
|
+
import { renderFfiType } from "./value.js";
|
|
10
|
+
|
|
11
|
+
type VtableKind = "class" | "interface";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Renders the `{ … }` vtable descriptor literal for a class or interface
|
|
15
|
+
* descriptor's `vfuncs` field, or `undefined` when the type exposes no
|
|
16
|
+
* marshallable slots.
|
|
17
|
+
*
|
|
18
|
+
* Each entry describes one overridable vtable slot — keyed by the slot's
|
|
19
|
+
* camelCase name and carrying `{ kind, className, vfuncName, byteOffset,
|
|
20
|
+
* argTypes, returnType }` — so the runtime `registerClass` can auto-discover
|
|
21
|
+
* a subclass method, locate the matching slot by byte offset, and register a
|
|
22
|
+
* trampoline with the correct marshalling. Slots whose signature cannot be
|
|
23
|
+
* marshalled (non-introspectable, variadic, out-parameters without
|
|
24
|
+
* caller-allocates, or nested callbacks) are omitted. The `kind` discriminator
|
|
25
|
+
* lets the runtime register an interface vfunc mapping in addition to the class
|
|
26
|
+
* one when the descriptor's role is `"interface"`.
|
|
27
|
+
*
|
|
28
|
+
* @param context - The module context
|
|
29
|
+
* @param klass - The class or interface
|
|
30
|
+
*/
|
|
31
|
+
export const renderVfuncMetadata = (context: ModuleContext, klass: GirClass): string | undefined => {
|
|
32
|
+
if (klass.glibTypeStruct === undefined) return undefined;
|
|
33
|
+
const structName = toPascalCase(klass.glibTypeStruct);
|
|
34
|
+
const kind: VtableKind = klass.isInterface ? "interface" : "class";
|
|
35
|
+
const entries = vtableEntries(context, structName, kind, klass.glibTypeStruct);
|
|
36
|
+
if (entries.length === 0) return undefined;
|
|
37
|
+
return `{\n${entries.map((entry) => indent(entry, 1)).join("\n")}\n}`;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const vtableEntries = (context: ModuleContext, structName: string, kind: VtableKind, typeStruct: string): string[] => {
|
|
41
|
+
const resolved = context.repository.resolveNamed(context.namespace.name, typeStruct);
|
|
42
|
+
if (resolved === undefined || resolved.kind !== "boxed") return [];
|
|
43
|
+
const { slots } = computeBoxedFieldSlots(context, resolved.value.fields, resolved.value.isUnion);
|
|
44
|
+
const entries: string[] = [];
|
|
45
|
+
const claimedNames = new Set<string>();
|
|
46
|
+
for (const { field, slot } of slots) {
|
|
47
|
+
if (field.callback === undefined) continue;
|
|
48
|
+
const key = toIdentifier(toCamelCase(field.name));
|
|
49
|
+
if (key === "constructor" || claimedNames.has(key)) continue;
|
|
50
|
+
const callback = callbackFromNode(field.callback);
|
|
51
|
+
if (!isVtableSlotEligible(callback)) continue;
|
|
52
|
+
claimedNames.add(key);
|
|
53
|
+
entries.push(
|
|
54
|
+
renderDescriptor(context, { key, structName, kind, field, callback, byteOffset: slot.byteOffset }),
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
return entries;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const isVtableSlotEligible = (callback: GirCallback): boolean => {
|
|
61
|
+
if (!callback.introspectable) return false;
|
|
62
|
+
for (const param of callback.parameters) {
|
|
63
|
+
if (param.isVarargs) return false;
|
|
64
|
+
if ((param.direction === "out" || param.direction === "inout") && !param.callerAllocates) return false;
|
|
65
|
+
if (isCallbackRef(param.type)) return false;
|
|
66
|
+
}
|
|
67
|
+
return !isCallbackRef(callback.returnValue.type);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const isCallbackRef = (ref: GirTypeRef | undefined): boolean => ref?.kind === "callback";
|
|
71
|
+
|
|
72
|
+
type RenderDescriptorOptions = {
|
|
73
|
+
readonly key: string;
|
|
74
|
+
readonly structName: string;
|
|
75
|
+
readonly kind: VtableKind;
|
|
76
|
+
readonly field: GirField;
|
|
77
|
+
readonly callback: GirCallback;
|
|
78
|
+
readonly byteOffset: number;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const renderDescriptor = (context: ModuleContext, options: RenderDescriptorOptions): string => {
|
|
82
|
+
const { key, structName, kind, field, callback, byteOffset } = options;
|
|
83
|
+
const argTypes = callback.parameters
|
|
84
|
+
.map((param) => renderFfiType(context, param.type, param.transferOwnership))
|
|
85
|
+
.join(", ");
|
|
86
|
+
const returnType = renderFfiType(context, callback.returnValue.type, callback.returnValue.transferOwnership);
|
|
87
|
+
const lines = [
|
|
88
|
+
`kind: ${quote(kind)},`,
|
|
89
|
+
`className: ${quote(structName)},`,
|
|
90
|
+
`vfuncName: ${quote(field.name)},`,
|
|
91
|
+
`byteOffset: ${byteOffset},`,
|
|
92
|
+
`argTypes: [${argTypes}],`,
|
|
93
|
+
`returnType: ${returnType},`,
|
|
94
|
+
];
|
|
95
|
+
return `${key}: {\n${lines.map((line) => indent(line, 1)).join("\n")}\n},`;
|
|
96
|
+
};
|