@gtkx/codegen 1.2.0 → 1.2.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.
- package/dist/docs/symbol-page.js +1 -1
- package/dist/docs/symbol-page.js.map +1 -1
- package/dist/gir/class.d.ts +7 -2
- package/dist/gir/class.d.ts.map +1 -1
- package/dist/gir/class.js +4 -1
- package/dist/gir/class.js.map +1 -1
- package/dist/store/gi/callables.d.ts +1 -1
- package/dist/store/gi/callables.d.ts.map +1 -1
- package/dist/store/gi/callables.js +3 -3
- package/dist/store/gi/callables.js.map +1 -1
- package/dist/store/gi/class.d.ts.map +1 -1
- package/dist/store/gi/class.js +15 -8
- package/dist/store/gi/class.js.map +1 -1
- package/dist/store/gi/gtype-binding.d.ts +2 -1
- package/dist/store/gi/gtype-binding.d.ts.map +1 -1
- package/dist/store/gi/gtype-binding.js +13 -1
- package/dist/store/gi/gtype-binding.js.map +1 -1
- package/dist/store/gi/interface.js +2 -2
- package/dist/store/gi/interface.js.map +1 -1
- package/dist/store/gi/record-constructor.d.ts.map +1 -1
- package/dist/store/gi/record-constructor.js +4 -2
- package/dist/store/gi/record-constructor.js.map +1 -1
- package/dist/store/gi/record-field-accessor.d.ts +3 -2
- package/dist/store/gi/record-field-accessor.d.ts.map +1 -1
- package/dist/store/gi/record-field-accessor.js +27 -9
- package/dist/store/gi/record-field-accessor.js.map +1 -1
- package/dist/store/gi/record.d.ts.map +1 -1
- package/dist/store/gi/record.js +5 -9
- package/dist/store/gi/record.js.map +1 -1
- package/dist/store/gi/signal.d.ts.map +1 -1
- package/dist/store/gi/signal.js +14 -14
- package/dist/store/gi/signal.js.map +1 -1
- package/dist/store/resolve-store.d.ts.map +1 -1
- package/dist/store/resolve-store.js +1 -0
- package/dist/store/resolve-store.js.map +1 -1
- package/package.json +3 -3
- package/src/docs/symbol-page.ts +1 -1
- package/src/gir/class.ts +12 -3
- package/src/store/gi/callables.ts +4 -4
- package/src/store/gi/class.ts +33 -14
- package/src/store/gi/gtype-binding.ts +16 -1
- package/src/store/gi/interface.ts +2 -2
- package/src/store/gi/record-constructor.ts +4 -2
- package/src/store/gi/record-field-accessor.ts +47 -10
- package/src/store/gi/record.ts +13 -17
- package/src/store/gi/signal.ts +20 -23
- package/src/store/resolve-store.ts +1 -0
package/src/gir/class.ts
CHANGED
|
@@ -11,6 +11,12 @@ type GirVirtualMethod = GirCallable & {
|
|
|
11
11
|
invoker: string | undefined;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
+
/** A `<glib:signal>` on a class or interface. */
|
|
15
|
+
type GirSignal = GirCallable & {
|
|
16
|
+
/** Whether the signal takes a `::detail` suffix, so `changed::key` reaches only that detail. */
|
|
17
|
+
isDetailed: boolean;
|
|
18
|
+
};
|
|
19
|
+
|
|
14
20
|
/** A `<class>` or `<interface>` declared by a GIR namespace. */
|
|
15
21
|
type GirClass = {
|
|
16
22
|
/** Name GIR gives the type, without its namespace prefix. */
|
|
@@ -54,7 +60,7 @@ type GirClass = {
|
|
|
54
60
|
/** GObject properties the type declares. */
|
|
55
61
|
properties: GirProperty[];
|
|
56
62
|
/** GObject signals the type declares. */
|
|
57
|
-
signals:
|
|
63
|
+
signals: GirSignal[];
|
|
58
64
|
/** Virtual methods the type declares, carrying the documentation their vtable slots are generated from. */
|
|
59
65
|
vfuncs: GirVirtualMethod[];
|
|
60
66
|
};
|
|
@@ -88,8 +94,11 @@ const classFromNode = (node: RawNode, isInterface: boolean, context: ParseContex
|
|
|
88
94
|
constructors: getChildren(node, GIR_CONSTRUCTOR_TAG).map((ctor) => functionFromNode(ctor, context)),
|
|
89
95
|
functions: getChildren(node, "function").map((fn) => functionFromNode(fn, context)),
|
|
90
96
|
properties: getChildren(node, "property").map((property) => propertyFromNode(property, context)),
|
|
91
|
-
signals: getChildren(node, "glib:signal").map((signal) =>
|
|
97
|
+
signals: getChildren(node, "glib:signal").map((signal) => ({
|
|
98
|
+
...parseCallable(signal, context),
|
|
99
|
+
isDetailed: isAttrTrue(signal, "detailed"),
|
|
100
|
+
})),
|
|
92
101
|
vfuncs: virtualMethodsFromNode(node, context),
|
|
93
102
|
});
|
|
94
103
|
|
|
95
|
-
export { classFromNode, type GirClass, type GirVirtualMethod };
|
|
104
|
+
export { classFromNode, type GirClass, type GirSignal, type GirVirtualMethod };
|
|
@@ -7,7 +7,7 @@ import { renderBlock } from "../../writer/emit.js";
|
|
|
7
7
|
import { matchAsyncFinish } from "./async.js";
|
|
8
8
|
import { callableDoc, callableSpec } from "./callable-doc.js";
|
|
9
9
|
import { renderFnExpression } from "./function.js";
|
|
10
|
-
import { gtypeMemberDeclaration } from "./gtype-binding.js";
|
|
10
|
+
import { gtypeMemberDeclaration, gtypeStaticMember } from "./gtype-binding.js";
|
|
11
11
|
import {
|
|
12
12
|
finishCallExpression,
|
|
13
13
|
memberName,
|
|
@@ -66,7 +66,7 @@ type PlainTypeMembersOptions = {
|
|
|
66
66
|
context: ModuleContext;
|
|
67
67
|
className: string;
|
|
68
68
|
callables: Callables;
|
|
69
|
-
|
|
69
|
+
gtypeExpr: string | undefined;
|
|
70
70
|
};
|
|
71
71
|
|
|
72
72
|
const RUNTIME_OWNED_LIFETIME_METHODS: Set<string> = new Set([
|
|
@@ -514,11 +514,11 @@ const renderPlainInstanceMethods = (
|
|
|
514
514
|
const renderPlainTypeMembers = (
|
|
515
515
|
options: PlainTypeMembersOptions,
|
|
516
516
|
): { members: string[]; claimedNames: Set<string> } => {
|
|
517
|
-
const { context, className, callables,
|
|
517
|
+
const { context, className, callables, gtypeExpr } = options;
|
|
518
518
|
const claimedNames: Set<string> = new Set();
|
|
519
519
|
|
|
520
520
|
const members: string[] = [
|
|
521
|
-
...(
|
|
521
|
+
...(gtypeExpr === undefined ? [] : [gtypeMemberDeclaration(context), gtypeStaticMember(context)]),
|
|
522
522
|
...renderStaticHead(context, callables, className),
|
|
523
523
|
...renderPlainInstanceMethods(context, callables.methods, claimedNames),
|
|
524
524
|
];
|
package/src/store/gi/class.ts
CHANGED
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
} from "./callables.js";
|
|
35
35
|
import { renderClassConstructor, renderConstructorPropsInterface } from "./constructor-props.js";
|
|
36
36
|
import { getDoc } from "./doc-spec.js";
|
|
37
|
-
import { gtypeMemberDeclaration, renderSourceGtype } from "./gtype-binding.js";
|
|
37
|
+
import { gtypeMemberDeclaration, gtypeStaticMember, renderSourceGtype } from "./gtype-binding.js";
|
|
38
38
|
import { methodExportName } from "./method.js";
|
|
39
39
|
import { renderPropertyDeclarations } from "./properties.js";
|
|
40
40
|
import { renderResolvedPropertyAccessor, resolveAccessor, type ResolvedAccessor } from "./property-accessor.js";
|
|
@@ -60,6 +60,14 @@ type MemberDeclarationsOptions = {
|
|
|
60
60
|
|
|
61
61
|
type ClassMembers = { members: string[]; accessors: ResolvedAccessor[] };
|
|
62
62
|
|
|
63
|
+
type ClassMembersOptions = {
|
|
64
|
+
context: ModuleContext;
|
|
65
|
+
klass: GirClass;
|
|
66
|
+
callables: Callables;
|
|
67
|
+
gtypeExpr: string | undefined;
|
|
68
|
+
hasParent: boolean;
|
|
69
|
+
};
|
|
70
|
+
|
|
63
71
|
type ImplementedRefOptions = {
|
|
64
72
|
context: ModuleContext;
|
|
65
73
|
klass: GirClass;
|
|
@@ -97,7 +105,16 @@ const generateClass = (context: ModuleContext, klass: GirClass): void => {
|
|
|
97
105
|
const implemented = resolveImplementedRefs(context, klass);
|
|
98
106
|
const typeRefs = implemented.map((ref) => omittedTypeRef(ref.typeRef, ref.conflicts));
|
|
99
107
|
const implementsClause = typeRefs.length === 0 ? "" : ` implements ${typeRefs.join(", ")}`;
|
|
100
|
-
const
|
|
108
|
+
const gtypeExpr = renderSourceGtype(context, klass);
|
|
109
|
+
|
|
110
|
+
const { members, accessors } = renderClassMembers({
|
|
111
|
+
context,
|
|
112
|
+
klass,
|
|
113
|
+
callables,
|
|
114
|
+
gtypeExpr,
|
|
115
|
+
hasParent: parentExpression !== undefined,
|
|
116
|
+
});
|
|
117
|
+
|
|
101
118
|
const body = indentMembers(members);
|
|
102
119
|
const doc = getDoc(klass);
|
|
103
120
|
const modifier = klass.isAbstract ? "abstract " : "";
|
|
@@ -115,7 +132,7 @@ const generateClass = (context: ModuleContext, klass: GirClass): void => {
|
|
|
115
132
|
|
|
116
133
|
appendMemberDeclarations({ context, klass, className, accessors, implemented });
|
|
117
134
|
appendInstallMixins(context, className, implemented);
|
|
118
|
-
appendClassRegistrations(context, klass, className);
|
|
135
|
+
appendClassRegistrations(context, klass, className, gtypeExpr);
|
|
119
136
|
};
|
|
120
137
|
|
|
121
138
|
const appendMemberDeclarations = (options: MemberDeclarationsOptions): void => {
|
|
@@ -150,15 +167,14 @@ const appendInterfaceMerge = (
|
|
|
150
167
|
});
|
|
151
168
|
};
|
|
152
169
|
|
|
153
|
-
const renderClassMembers = (
|
|
154
|
-
context
|
|
155
|
-
klass: GirClass,
|
|
156
|
-
callables: Callables,
|
|
157
|
-
hasParent: boolean,
|
|
158
|
-
): ClassMembers => {
|
|
170
|
+
const renderClassMembers = (options: ClassMembersOptions): ClassMembers => {
|
|
171
|
+
const { context, klass, callables, gtypeExpr } = options;
|
|
159
172
|
const className = sanitizeTypeIdentifier(klass.name);
|
|
160
|
-
|
|
161
|
-
const
|
|
173
|
+
|
|
174
|
+
const members: string[] =
|
|
175
|
+
gtypeExpr === undefined ? [] : [gtypeMemberDeclaration(context), gtypeStaticMember(context)];
|
|
176
|
+
|
|
177
|
+
const constructorBlock = renderClassConstructor(context, klass, className, options.hasParent);
|
|
162
178
|
|
|
163
179
|
if (constructorBlock !== undefined) {
|
|
164
180
|
members.push(constructorBlock);
|
|
@@ -239,9 +255,12 @@ const appendInstallMixins = (context: ModuleContext, className: string, implemen
|
|
|
239
255
|
]);
|
|
240
256
|
};
|
|
241
257
|
|
|
242
|
-
const appendClassRegistrations = (
|
|
243
|
-
|
|
244
|
-
|
|
258
|
+
const appendClassRegistrations = (
|
|
259
|
+
context: ModuleContext,
|
|
260
|
+
klass: GirClass,
|
|
261
|
+
className: string,
|
|
262
|
+
gtypeExpr: string | undefined,
|
|
263
|
+
): void => {
|
|
245
264
|
appendWrapperClassRegistration(context, {
|
|
246
265
|
className,
|
|
247
266
|
gtypeExpr,
|
|
@@ -1,17 +1,32 @@
|
|
|
1
1
|
import { sourceStringLiteral } from "@gtkx/utils";
|
|
2
2
|
import type { ModuleContext } from "../../writer/context.js";
|
|
3
3
|
import { PRIMITIVE_TS_TYPE } from "../../gir/primitives.js";
|
|
4
|
+
import { renderJsDoc } from "../../writer/doc.js";
|
|
5
|
+
import { renderBlock } from "../../writer/emit.js";
|
|
4
6
|
|
|
5
7
|
type TypeSource = {
|
|
6
8
|
glibGetType: string | undefined;
|
|
7
9
|
glibTypeName: string | undefined;
|
|
8
10
|
};
|
|
9
11
|
|
|
12
|
+
const GTYPE_NOTE = [
|
|
13
|
+
"The GType this class is registered under, read off the class it is accessed on rather than",
|
|
14
|
+
"inherited, so a subclass `registerClass` created reports its own type and one that never went",
|
|
15
|
+
"through `registerClass` reports the invalid type.",
|
|
16
|
+
].join("\n");
|
|
17
|
+
|
|
10
18
|
const gtypeTsType = (context: ModuleContext): string =>
|
|
11
19
|
context.namespace.name === "GObject" ? "Type" : PRIMITIVE_TS_TYPE.gtype;
|
|
12
20
|
|
|
13
21
|
const gtypeMemberDeclaration = (context: ModuleContext): string => `declare __type__: ${gtypeTsType(context)};`;
|
|
14
22
|
|
|
23
|
+
const gtypeStaticMember = (context: ModuleContext): string => {
|
|
24
|
+
context.addRuntimeImport("getClassType");
|
|
25
|
+
const block = renderBlock(`static get __gtype__(): ${gtypeTsType(context)}`, "return getClassType(this);");
|
|
26
|
+
|
|
27
|
+
return `${renderJsDoc(undefined, GTYPE_NOTE)}${block}`;
|
|
28
|
+
};
|
|
29
|
+
|
|
15
30
|
const renderInternGtype = (context: ModuleContext, typeName: string | undefined): string | undefined => {
|
|
16
31
|
if (typeName === undefined) {
|
|
17
32
|
return undefined;
|
|
@@ -48,4 +63,4 @@ const renderSourceGtype = (context: ModuleContext, source: TypeSource): string |
|
|
|
48
63
|
? undefined
|
|
49
64
|
: renderGtypeExpression(context, source.glibGetType, source.glibTypeName);
|
|
50
65
|
|
|
51
|
-
export { gtypeTsType, gtypeMemberDeclaration, renderSourceGtype };
|
|
66
|
+
export { gtypeTsType, gtypeMemberDeclaration, gtypeStaticMember, renderSourceGtype };
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
renderStaticHead,
|
|
22
22
|
} from "./callables.js";
|
|
23
23
|
import { annotationSpec, getDoc } from "./doc-spec.js";
|
|
24
|
-
import { renderSourceGtype } from "./gtype-binding.js";
|
|
24
|
+
import { gtypeStaticMember, renderSourceGtype } from "./gtype-binding.js";
|
|
25
25
|
import { methodExportName } from "./method.js";
|
|
26
26
|
import {
|
|
27
27
|
type PropertyAccessorArgs,
|
|
@@ -378,7 +378,7 @@ const renderInterfaceClass = (context: ModuleContext, options: InterfaceClassOpt
|
|
|
378
378
|
const members: string[] = [];
|
|
379
379
|
|
|
380
380
|
if (gtypeExpr !== undefined) {
|
|
381
|
-
members.push(renderInterfaceHasInstance(context, className, gtypeExpr));
|
|
381
|
+
members.push(renderInterfaceHasInstance(context, className, gtypeExpr), gtypeStaticMember(context));
|
|
382
382
|
}
|
|
383
383
|
|
|
384
384
|
members.push(...renderStaticHead(context, callables, className), renderInterfaceBrand(context, implRef));
|
|
@@ -11,7 +11,7 @@ import { renderBlock, renderBracedOrEmpty } from "../../writer/emit.js";
|
|
|
11
11
|
import { type Callables, staticMembers } from "./callables.js";
|
|
12
12
|
import { getDoc } from "./doc-spec.js";
|
|
13
13
|
import { renderSourceGtype } from "./gtype-binding.js";
|
|
14
|
-
import { emitFieldWrite, isEmittableField, isInlineField } from "./record-field-accessor.js";
|
|
14
|
+
import { emitFieldWrite, isEmittableField, isInlineField, isStorableFieldType } from "./record-field-accessor.js";
|
|
15
15
|
import { computeRecordFieldSlots, type RecordFieldSlot } from "./record-layout.js";
|
|
16
16
|
import { isConstructibleRecord } from "./value-marshalable.js";
|
|
17
17
|
|
|
@@ -25,7 +25,9 @@ type RecordConstructorSpec = {
|
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
const isWritableFieldSlot = (context: ModuleContext, entry: RecordFieldSlot): entry is WritableFieldSlot =>
|
|
28
|
-
entry.field.writable &&
|
|
28
|
+
entry.field.writable &&
|
|
29
|
+
isEmittableField(context, entry.field) &&
|
|
30
|
+
isStorableFieldType(context, entry.field.type);
|
|
29
31
|
|
|
30
32
|
const renderRecordConstructorPropsInterface = (
|
|
31
33
|
context: ModuleContext,
|
|
@@ -9,6 +9,7 @@ import type { ModuleContext } from "../../writer/context.js";
|
|
|
9
9
|
import { isInlineCallbackRef, renderDescriptor } from "../../analysis/descriptor-render.js";
|
|
10
10
|
import { tStruct } from "../../analysis/descriptor.js";
|
|
11
11
|
import { renderTsType } from "../../analysis/ts-type.js";
|
|
12
|
+
import { isUnboundedArray } from "../../analysis/type-shape.js";
|
|
12
13
|
import { indent, renderBlock } from "../../writer/emit.js";
|
|
13
14
|
import { getDoc } from "./doc-spec.js";
|
|
14
15
|
import { bitMask, computeRecordFieldSlots, mergeBitfield, type RecordFieldSlot } from "./record-layout.js";
|
|
@@ -27,6 +28,10 @@ type AdmittedField = {
|
|
|
27
28
|
jsName: string;
|
|
28
29
|
};
|
|
29
30
|
|
|
31
|
+
type AccessibleField = AdmittedField & {
|
|
32
|
+
isSettable: boolean;
|
|
33
|
+
};
|
|
34
|
+
|
|
30
35
|
type RecordFieldEntry = {
|
|
31
36
|
jsName: string;
|
|
32
37
|
tsType: string;
|
|
@@ -167,12 +172,49 @@ const admitField = (
|
|
|
167
172
|
return { field, jsName };
|
|
168
173
|
};
|
|
169
174
|
|
|
175
|
+
const isNullTerminatedArrayField = (context: ModuleContext, ref: TypeId): boolean => {
|
|
176
|
+
const type = context.library.typeFor(ref);
|
|
177
|
+
|
|
178
|
+
return type?.kind === "carray" && isUnboundedArray(type) && type.elementCType?.endsWith("*") === true;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const isAccessibleFieldType = (context: ModuleContext, ref: TypeId): boolean =>
|
|
182
|
+
isAccessorEligibleType(context, ref) || isNullTerminatedArrayField(context, ref);
|
|
183
|
+
|
|
184
|
+
const isStorableFieldType = (context: ModuleContext, ref: TypeId): boolean => {
|
|
185
|
+
const kind = context.library.typeFor(ref)?.kind;
|
|
186
|
+
|
|
187
|
+
return kind !== "carray" && kind !== "list" && kind !== "hashtable";
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const admitAccessibleField = (
|
|
191
|
+
context: ModuleContext,
|
|
192
|
+
slot: RecordFieldSlot,
|
|
193
|
+
claimedNames: Set<string>,
|
|
194
|
+
siblingFields: GirField[],
|
|
195
|
+
): AccessibleField | undefined => {
|
|
196
|
+
const admitted = admitField(context, slot, claimedNames);
|
|
197
|
+
|
|
198
|
+
if (admitted === undefined) {
|
|
199
|
+
return undefined;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const { field, jsName } = admitted;
|
|
203
|
+
const target: StructArrayTarget = { field, jsName, slot: slot.slot, siblingFields };
|
|
204
|
+
const hasStructArray = resolveStructArray(context, target) !== undefined;
|
|
205
|
+
const hasAccessor = hasStructArray || isAccessibleFieldType(context, field.type);
|
|
206
|
+
const isSettable = field.writable && (hasStructArray || isStorableFieldType(context, field.type));
|
|
207
|
+
|
|
208
|
+
return hasAccessor ? { ...admitted, isSettable } : undefined;
|
|
209
|
+
};
|
|
210
|
+
|
|
170
211
|
const resolveRecordFieldEntry = (
|
|
171
212
|
context: ModuleContext,
|
|
172
213
|
slot: RecordFieldSlot,
|
|
173
214
|
claimedNames: Set<string>,
|
|
215
|
+
siblingFields: GirField[],
|
|
174
216
|
): RecordFieldEntry | undefined => {
|
|
175
|
-
const admitted =
|
|
217
|
+
const admitted = admitAccessibleField(context, slot, claimedNames, siblingFields);
|
|
176
218
|
|
|
177
219
|
if (admitted === undefined) {
|
|
178
220
|
return undefined;
|
|
@@ -181,7 +223,7 @@ const resolveRecordFieldEntry = (
|
|
|
181
223
|
return {
|
|
182
224
|
jsName: admitted.jsName,
|
|
183
225
|
tsType: renderTsType(context, admitted.field.type, false),
|
|
184
|
-
isWritable: admitted.
|
|
226
|
+
isWritable: admitted.isSettable,
|
|
185
227
|
doc: admitted.field.doc,
|
|
186
228
|
annotations: admitted.field.annotations,
|
|
187
229
|
};
|
|
@@ -193,7 +235,7 @@ const renderRecordFieldAccessor = (
|
|
|
193
235
|
claimedNames: Set<string>,
|
|
194
236
|
siblingFields: GirField[],
|
|
195
237
|
): string | undefined => {
|
|
196
|
-
const admitted =
|
|
238
|
+
const admitted = admitAccessibleField(context, slot, claimedNames, siblingFields);
|
|
197
239
|
|
|
198
240
|
if (admitted === undefined) {
|
|
199
241
|
return undefined;
|
|
@@ -207,12 +249,6 @@ const renderRecordFieldAccessor = (
|
|
|
207
249
|
return `${doc}${structArray}`;
|
|
208
250
|
}
|
|
209
251
|
|
|
210
|
-
if (!isAccessorEligibleType(context, field.type)) {
|
|
211
|
-
const tsType = renderTsType(context, field.type, false);
|
|
212
|
-
|
|
213
|
-
return `${doc}declare ${jsName}: ${tsType};`;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
252
|
const descriptor = context.hoistDescriptor(
|
|
217
253
|
renderDescriptor(context, field.type, "none", { isInline: isInlineField(context, field) }),
|
|
218
254
|
);
|
|
@@ -230,7 +266,7 @@ const renderRecordFieldAccessor = (
|
|
|
230
266
|
|
|
231
267
|
const blocks: string[] = [getterBlock(accessorOptions)];
|
|
232
268
|
|
|
233
|
-
if (
|
|
269
|
+
if (admitted.isSettable) {
|
|
234
270
|
blocks.push(setterBlock(accessorOptions));
|
|
235
271
|
}
|
|
236
272
|
|
|
@@ -654,6 +690,7 @@ const setterBlock = (options: AccessorOptions): string =>
|
|
|
654
690
|
export {
|
|
655
691
|
isEmittableField,
|
|
656
692
|
isInlineField,
|
|
693
|
+
isStorableFieldType,
|
|
657
694
|
emitFieldWrite,
|
|
658
695
|
resolveRecordFieldEntry,
|
|
659
696
|
renderRecordFieldAccessor,
|
package/src/store/gi/record.ts
CHANGED
|
@@ -12,6 +12,14 @@ import { computeRecordFieldSlots } from "./record-layout.js";
|
|
|
12
12
|
import { appendWrapperClassRegistration } from "./registration.js";
|
|
13
13
|
import { isConstructibleRecord } from "./value-marshalable.js";
|
|
14
14
|
|
|
15
|
+
type RecordMembersOptions = {
|
|
16
|
+
context: ModuleContext;
|
|
17
|
+
record: GirRecord;
|
|
18
|
+
className: string;
|
|
19
|
+
callables: Callables;
|
|
20
|
+
gtypeExpr: string | undefined;
|
|
21
|
+
};
|
|
22
|
+
|
|
15
23
|
const isGErrorRecord = (context: ModuleContext, record: GirRecord): boolean =>
|
|
16
24
|
context.namespace.name === "GLib" && record.glibGetType === "g_error_get_type";
|
|
17
25
|
|
|
@@ -30,7 +38,8 @@ const generateRecord = (context: ModuleContext, record: GirRecord): void => {
|
|
|
30
38
|
};
|
|
31
39
|
|
|
32
40
|
generateBindings(context, callables);
|
|
33
|
-
const
|
|
41
|
+
const gtypeExpr = renderSourceGtype(context, record);
|
|
42
|
+
const members = renderRecordMembers({ context, record, className, callables, gtypeExpr });
|
|
34
43
|
const body = indentMembers(members);
|
|
35
44
|
const heritage = isErrorSubclass ? " extends globalThis.Error" : "";
|
|
36
45
|
const doc = getDoc(record);
|
|
@@ -50,29 +59,16 @@ const generateRecord = (context: ModuleContext, record: GirRecord): void => {
|
|
|
50
59
|
});
|
|
51
60
|
}
|
|
52
61
|
|
|
53
|
-
const gtypeExpr = renderSourceGtype(context, record);
|
|
54
|
-
|
|
55
62
|
appendWrapperClassRegistration(context, {
|
|
56
63
|
className,
|
|
57
64
|
gtypeExpr,
|
|
58
65
|
});
|
|
59
66
|
};
|
|
60
67
|
|
|
61
|
-
const renderRecordMembers = (
|
|
62
|
-
context
|
|
63
|
-
record: GirRecord,
|
|
64
|
-
className: string,
|
|
65
|
-
callables: Callables,
|
|
66
|
-
): string[] => {
|
|
68
|
+
const renderRecordMembers = (options: RecordMembersOptions): string[] => {
|
|
69
|
+
const { context, record, className, callables, gtypeExpr } = options;
|
|
67
70
|
const isErrorSubclass = isGErrorRecord(context, record);
|
|
68
|
-
|
|
69
|
-
const { members, claimedNames } = renderPlainTypeMembers({
|
|
70
|
-
context,
|
|
71
|
-
className,
|
|
72
|
-
callables,
|
|
73
|
-
hasGtype: record.glibGetType !== undefined,
|
|
74
|
-
});
|
|
75
|
-
|
|
71
|
+
const { members, claimedNames } = renderPlainTypeMembers({ context, className, callables, gtypeExpr });
|
|
76
72
|
members.unshift(renderRecordConstructor(context, { record, className, callables, isErrorSubclass }));
|
|
77
73
|
const { slots } = computeRecordFieldSlots(context, record.fields, record.isUnion);
|
|
78
74
|
|
package/src/store/gi/signal.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { camelCase, sourceStringLiteral } from "@gtkx/utils";
|
|
2
|
-
import type { GirClass } from "../../gir/class.js";
|
|
2
|
+
import type { GirClass, GirSignal } from "../../gir/class.js";
|
|
3
3
|
import type { GirCallable, GirParameter, GirReturnValue } from "../../gir/parameter.js";
|
|
4
4
|
import type { GirProperty } from "../../gir/property.js";
|
|
5
5
|
import type { ModuleContext } from "../../writer/context.js";
|
|
@@ -139,16 +139,20 @@ const renderSignalMap = (spec: SignalMapSpec): string => {
|
|
|
139
139
|
const { context, klass, className, isParentlessObjectSubclass, suffix, renderEntry } = spec;
|
|
140
140
|
const extendsRefs = signalMapParentRefs(context, klass, isParentlessObjectSubclass, suffix);
|
|
141
141
|
const extendsClause = extendsRefs.length === 0 ? "" : ` extends ${extendsRefs.join(", ")}`;
|
|
142
|
+
const signals = collectClassSignals(context, klass);
|
|
142
143
|
|
|
143
|
-
const signalEntries =
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
const signalEntries = signals.flatMap((signal) => {
|
|
145
|
+
const value = renderEntry(context, signal);
|
|
146
|
+
const entry = `${signalDoc(signal)}${sourceStringLiteral(signal.name)}: ${value};`;
|
|
146
147
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
148
|
+
if (!signal.isDetailed) {
|
|
149
|
+
return [entry];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return [entry, `[detail: \`${signal.name}::\${string}\`]: ${value};`];
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
const entries = [...signalEntries, ...renderNotifyDetailEntries(context, klass, suffix)];
|
|
152
156
|
|
|
153
157
|
return renderBracedOrEmpty(`export interface ${className}${suffix}${extendsClause}`, entries.join("\n"));
|
|
154
158
|
};
|
|
@@ -156,14 +160,6 @@ const renderSignalMap = (spec: SignalMapSpec): string => {
|
|
|
156
160
|
const signalDoc = (signal: GirCallable): string =>
|
|
157
161
|
renderJsDoc(signal.doc, undefined, handlerSpec(signal, signal.parameters));
|
|
158
162
|
|
|
159
|
-
const renderCustomNotifyEntry = (context: ModuleContext, klass: GirClass, suffix: string): string[] => {
|
|
160
|
-
if (context.namespace.name !== "GObject" || klass.name !== "Object") {
|
|
161
|
-
return [];
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return [`[detail: \`notify::\${string}\`]: ${gobjectObjectMapRef(context, suffix)}["notify"];`];
|
|
165
|
-
};
|
|
166
|
-
|
|
167
163
|
const renderNotifyDetailEntries = (context: ModuleContext, klass: GirClass, suffix: string): string[] => {
|
|
168
164
|
const notifyValue = `${gobjectObjectMapRef(context, suffix)}["notify"]`;
|
|
169
165
|
|
|
@@ -219,10 +215,11 @@ const renderSignalConnectInterface = (className: string, isRootObject: boolean):
|
|
|
219
215
|
`__signals__?: ${map};`,
|
|
220
216
|
`connect<K extends keyof ${map}>(signal: K, handler: ${map}[K], isAfter?: boolean): number;`,
|
|
221
217
|
`emit<K extends keyof ${emitMap}>(sigName: K, ...args: ${emitMap}[K]["args"]): ${emitMap}[K]["result"];`,
|
|
222
|
-
"emit(sigName: string, ...args: unknown[]): unknown;",
|
|
223
218
|
];
|
|
224
219
|
|
|
225
|
-
if (
|
|
220
|
+
if (isRootObject) {
|
|
221
|
+
lines.push("emit(sigName: string, ...args: unknown[]): unknown;");
|
|
222
|
+
} else {
|
|
226
223
|
const chainable = (methods: string[], trailing: string): void => {
|
|
227
224
|
for (const method of methods) {
|
|
228
225
|
lines.push(
|
|
@@ -382,7 +379,7 @@ const renderCallback = (context: ModuleContext, signal: GirCallable): string =>
|
|
|
382
379
|
const forEachInterfaceSignal = (
|
|
383
380
|
context: ModuleContext,
|
|
384
381
|
klass: GirClass,
|
|
385
|
-
consider: (signal:
|
|
382
|
+
consider: (signal: GirSignal) => void,
|
|
386
383
|
): void => {
|
|
387
384
|
for (const iface of resolveInterfaces(context.library, context.namespace.name, klass.implements)) {
|
|
388
385
|
for (const signal of iface.klass.signals) {
|
|
@@ -391,12 +388,12 @@ const forEachInterfaceSignal = (
|
|
|
391
388
|
}
|
|
392
389
|
};
|
|
393
390
|
|
|
394
|
-
const collectClassSignals = (context: ModuleContext, klass: GirClass):
|
|
391
|
+
const collectClassSignals = (context: ModuleContext, klass: GirClass): GirSignal[] => {
|
|
395
392
|
const inheritedNames = collectInheritedSignalNames(context, klass);
|
|
396
393
|
const seen: Set<string> = new Set();
|
|
397
|
-
const result:
|
|
394
|
+
const result: GirSignal[] = [];
|
|
398
395
|
|
|
399
|
-
const consider = (signal:
|
|
396
|
+
const consider = (signal: GirSignal): void => {
|
|
400
397
|
const name = camelCase(signal.name);
|
|
401
398
|
|
|
402
399
|
if (!signal.introspectable || inheritedNames.has(name) || seen.has(name)) {
|