@gtkx/codegen 1.1.0 → 1.2.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.
Files changed (149) hide show
  1. package/dist/analysis/descriptor-render.d.ts.map +1 -1
  2. package/dist/analysis/descriptor-render.js +14 -10
  3. package/dist/analysis/descriptor-render.js.map +1 -1
  4. package/dist/analysis/descriptor.d.ts +11 -5
  5. package/dist/analysis/descriptor.d.ts.map +1 -1
  6. package/dist/analysis/descriptor.js +25 -9
  7. package/dist/analysis/descriptor.js.map +1 -1
  8. package/dist/analysis/interface-conflicts.d.ts +3 -1
  9. package/dist/analysis/interface-conflicts.d.ts.map +1 -1
  10. package/dist/analysis/interface-conflicts.js +3 -8
  11. package/dist/analysis/interface-conflicts.js.map +1 -1
  12. package/dist/analysis/ts-type.d.ts +3 -2
  13. package/dist/analysis/ts-type.d.ts.map +1 -1
  14. package/dist/analysis/ts-type.js +16 -9
  15. package/dist/analysis/ts-type.js.map +1 -1
  16. package/dist/analysis/type-shape.d.ts +3 -2
  17. package/dist/analysis/type-shape.d.ts.map +1 -1
  18. package/dist/analysis/type-shape.js +2 -1
  19. package/dist/analysis/type-shape.js.map +1 -1
  20. package/dist/compile.d.ts +4 -5
  21. package/dist/compile.d.ts.map +1 -1
  22. package/dist/compile.js +56 -4
  23. package/dist/compile.js.map +1 -1
  24. package/dist/docs/api-reference.d.ts +2 -0
  25. package/dist/docs/api-reference.d.ts.map +1 -1
  26. package/dist/docs/api-reference.js +1 -1
  27. package/dist/docs/api-reference.js.map +1 -1
  28. package/dist/docs/pipeline.d.ts +1 -0
  29. package/dist/docs/pipeline.d.ts.map +1 -1
  30. package/dist/docs/pipeline.js +10 -3
  31. package/dist/docs/pipeline.js.map +1 -1
  32. package/dist/docs/symbol-page.d.ts.map +1 -1
  33. package/dist/docs/symbol-page.js +1 -3
  34. package/dist/docs/symbol-page.js.map +1 -1
  35. package/dist/fingerprint.d.ts +11 -5
  36. package/dist/fingerprint.d.ts.map +1 -1
  37. package/dist/fingerprint.js +22 -19
  38. package/dist/fingerprint.js.map +1 -1
  39. package/dist/gi.d.ts +1 -0
  40. package/dist/gi.d.ts.map +1 -1
  41. package/dist/gi.js +7 -2
  42. package/dist/gi.js.map +1 -1
  43. package/dist/gir/gir-path.d.ts +1 -1
  44. package/dist/gir/gir-path.js +1 -1
  45. package/dist/gir/gir-path.js.map +1 -1
  46. package/dist/gir/library.d.ts +5 -1
  47. package/dist/gir/library.d.ts.map +1 -1
  48. package/dist/gir/library.js +8 -1
  49. package/dist/gir/library.js.map +1 -1
  50. package/dist/gir/parse.d.ts.map +1 -1
  51. package/dist/gir/parse.js +4 -1
  52. package/dist/gir/parse.js.map +1 -1
  53. package/dist/gir/primitives.js +1 -1
  54. package/dist/gir/primitives.js.map +1 -1
  55. package/dist/khronos/args.d.ts.map +1 -1
  56. package/dist/khronos/args.js +8 -6
  57. package/dist/khronos/args.js.map +1 -1
  58. package/dist/khronos/render.d.ts.map +1 -1
  59. package/dist/khronos/render.js +8 -4
  60. package/dist/khronos/render.js.map +1 -1
  61. package/dist/runner.d.ts +2 -0
  62. package/dist/runner.d.ts.map +1 -1
  63. package/dist/runner.js +5 -3
  64. package/dist/runner.js.map +1 -1
  65. package/dist/staging.d.ts.map +1 -1
  66. package/dist/staging.js +1 -1
  67. package/dist/staging.js.map +1 -1
  68. package/dist/store/compile-store.d.ts +0 -1
  69. package/dist/store/compile-store.d.ts.map +1 -1
  70. package/dist/store/compile-store.js +7 -34
  71. package/dist/store/compile-store.js.map +1 -1
  72. package/dist/store/gi/callables.d.ts +1 -3
  73. package/dist/store/gi/callables.d.ts.map +1 -1
  74. package/dist/store/gi/callables.js +19 -4
  75. package/dist/store/gi/callables.js.map +1 -1
  76. package/dist/store/gi/class.d.ts.map +1 -1
  77. package/dist/store/gi/class.js +48 -9
  78. package/dist/store/gi/class.js.map +1 -1
  79. package/dist/store/gi/constant.js +1 -1
  80. package/dist/store/gi/constant.js.map +1 -1
  81. package/dist/store/gi/enum.d.ts.map +1 -1
  82. package/dist/store/gi/enum.js +2 -5
  83. package/dist/store/gi/enum.js.map +1 -1
  84. package/dist/store/gi/interface.js +2 -2
  85. package/dist/store/gi/interface.js.map +1 -1
  86. package/dist/store/gi/method.d.ts.map +1 -1
  87. package/dist/store/gi/method.js +4 -7
  88. package/dist/store/gi/method.js.map +1 -1
  89. package/dist/store/gi/property-accessor.d.ts +0 -3
  90. package/dist/store/gi/property-accessor.d.ts.map +1 -1
  91. package/dist/store/gi/property-accessor.js +15 -108
  92. package/dist/store/gi/property-accessor.js.map +1 -1
  93. package/dist/store/gi/record-constructor.js +3 -3
  94. package/dist/store/gi/record-constructor.js.map +1 -1
  95. package/dist/store/gi/record-field-accessor.d.ts.map +1 -1
  96. package/dist/store/gi/record-field-accessor.js +15 -3
  97. package/dist/store/gi/record-field-accessor.js.map +1 -1
  98. package/dist/store/gi/return-wrap.js +1 -1
  99. package/dist/store/gi/return-wrap.js.map +1 -1
  100. package/dist/store/gi/signal.d.ts.map +1 -1
  101. package/dist/store/gi/signal.js +25 -4
  102. package/dist/store/gi/signal.js.map +1 -1
  103. package/dist/store/jsx-store.d.ts.map +1 -1
  104. package/dist/store/jsx-store.js +0 -1
  105. package/dist/store/jsx-store.js.map +1 -1
  106. package/dist/store/store-fs.d.ts +0 -1
  107. package/dist/store/store-fs.d.ts.map +1 -1
  108. package/dist/store/store-fs.js +2 -7
  109. package/dist/store/store-fs.js.map +1 -1
  110. package/dist/xml.d.ts +1 -0
  111. package/dist/xml.d.ts.map +1 -1
  112. package/dist/xml.js +28 -1
  113. package/dist/xml.js.map +1 -1
  114. package/overrides/gobject/object.ts.ejs +2 -0
  115. package/package.json +3 -3
  116. package/src/analysis/descriptor-render.ts +19 -10
  117. package/src/analysis/descriptor.ts +43 -9
  118. package/src/analysis/interface-conflicts.ts +6 -8
  119. package/src/analysis/ts-type.ts +30 -11
  120. package/src/analysis/type-shape.ts +5 -2
  121. package/src/compile.ts +87 -6
  122. package/src/docs/api-reference.ts +3 -1
  123. package/src/docs/pipeline.ts +13 -7
  124. package/src/docs/symbol-page.ts +0 -4
  125. package/src/fingerprint.ts +31 -38
  126. package/src/gi.ts +9 -2
  127. package/src/gir/gir-path.ts +1 -1
  128. package/src/gir/library.ts +9 -1
  129. package/src/gir/parse.ts +6 -1
  130. package/src/gir/primitives.ts +1 -1
  131. package/src/khronos/args.ts +9 -6
  132. package/src/khronos/render.ts +8 -6
  133. package/src/runner.ts +7 -3
  134. package/src/staging.ts +1 -3
  135. package/src/store/compile-store.ts +7 -40
  136. package/src/store/gi/callables.ts +26 -7
  137. package/src/store/gi/class.ts +63 -7
  138. package/src/store/gi/constant.ts +1 -1
  139. package/src/store/gi/enum.ts +2 -6
  140. package/src/store/gi/interface.ts +2 -2
  141. package/src/store/gi/method.ts +4 -9
  142. package/src/store/gi/property-accessor.ts +22 -193
  143. package/src/store/gi/record-constructor.ts +3 -3
  144. package/src/store/gi/record-field-accessor.ts +18 -3
  145. package/src/store/gi/return-wrap.ts +1 -1
  146. package/src/store/gi/signal.ts +30 -4
  147. package/src/store/jsx-store.ts +0 -1
  148. package/src/store/store-fs.ts +3 -9
  149. package/src/xml.ts +43 -1
@@ -1,52 +1,19 @@
1
- import { rmSync, writeFileSync } from "node:fs";
1
+ import { rmSync } from "node:fs";
2
2
  import { join } from "node:path";
3
- import { compileProject, type ProjectFile, type SourceModule } from "../compile.js";
3
+ import { emitModules, type SourceModule } from "../compile.js";
4
4
 
5
5
  type CompileStoreParams = {
6
6
  storeDir: string;
7
7
  files: SourceModule[];
8
8
  packageName: string;
9
- requiresEnvReference?: boolean;
10
- };
11
-
12
- const EMIT_OPTIONS = {
13
- declaration: true,
14
- removeComments: false,
15
- sourceMap: false,
16
- declarationMap: false,
17
- rootDir: ".",
18
- outDir: ".",
19
- };
20
-
21
- const ENV_REFERENCE_FILE = "__gtkx-env__.d.ts";
22
-
23
- const writeEnvReference = (storeDir: string): (() => void) => {
24
- writeFileSync(join(storeDir, ENV_REFERENCE_FILE), "/// <reference types=\"@gtkx/react/env\" />\n");
25
-
26
- return () => {
27
- rmSync(join(storeDir, ENV_REFERENCE_FILE), { force: true });
28
- };
29
9
  };
30
10
 
31
11
  const compileStore = (params: CompileStoreParams): void => {
32
- const removeEnvReference = params.requiresEnvReference === true
33
- ? writeEnvReference(params.storeDir)
34
- : (): void => undefined;
35
-
36
- const files: ProjectFile[] = params.requiresEnvReference === true
37
- ? [{ fileName: ENV_REFERENCE_FILE }, ...params.files]
38
- : params.files;
39
-
40
- try {
41
- compileProject({
42
- projectDir: params.storeDir,
43
- files,
44
- compilerOptions: EMIT_OPTIONS,
45
- label: `the generated ${params.packageName} store`,
46
- });
47
- } finally {
48
- removeEnvReference();
49
- }
12
+ emitModules({
13
+ projectDir: params.storeDir,
14
+ files: params.files,
15
+ label: `the generated ${params.packageName} store`,
16
+ });
50
17
 
51
18
  for (const file of params.files) {
52
19
  rmSync(join(params.storeDir, file.fileName), { force: true });
@@ -69,6 +69,15 @@ type PlainTypeMembersOptions = {
69
69
  hasGtype: boolean;
70
70
  };
71
71
 
72
+ const RUNTIME_OWNED_LIFETIME_METHODS: Set<string> = new Set([
73
+ "force_floating",
74
+ "free",
75
+ "ref",
76
+ "ref_sink",
77
+ "take_ref",
78
+ "unref",
79
+ ]);
80
+
72
81
  const renderInstanceMethodSignature: InstanceMemberRenderer = instanceMemberRenderer(
73
82
  (context, callable, { name, finishFn }) =>
74
83
  `${memberDoc(context, callable, finishFn)}${memberSignatureText(context, callable, name, { finishFn })};`,
@@ -373,6 +382,7 @@ const isEmittableCallable = (context: ModuleContext, callable: GirFunction): boo
373
382
  callable.introspectable &&
374
383
  callable.shadowedBy === undefined &&
375
384
  callable.cIdentifier !== undefined &&
385
+ !RUNTIME_OWNED_LIFETIME_METHODS.has(callable.name) &&
376
386
  !hasUnmarshalableParam(context, callable);
377
387
 
378
388
  const constructorMemberName = (girName: string): string | undefined => {
@@ -408,6 +418,20 @@ const renderStaticSignature = (
408
418
  };
409
419
  };
410
420
 
421
+ const staticMemberName = (
422
+ context: ModuleContext,
423
+ callable: GirFunction,
424
+ resolveName: (girName: string) => string | undefined,
425
+ ): string | undefined => {
426
+ if (!isEmittableCallable(context, callable)) {
427
+ return undefined;
428
+ }
429
+
430
+ const name = resolveName(callable.name);
431
+
432
+ return name !== undefined && isEmittableMemberName(name) ? name : undefined;
433
+ };
434
+
411
435
  const collectStaticMembers = (
412
436
  context: ModuleContext,
413
437
  group: GirFunction[],
@@ -416,7 +440,7 @@ const collectStaticMembers = (
416
440
  const members: StaticMember[] = [];
417
441
 
418
442
  for (const callable of group) {
419
- const name = isEmittableCallable(context, callable) ? resolveName(callable.name) : undefined;
443
+ const name = staticMemberName(context, callable, resolveName);
420
444
 
421
445
  if (name !== undefined) {
422
446
  members.push({ callable, name });
@@ -427,13 +451,10 @@ const collectStaticMembers = (
427
451
  };
428
452
 
429
453
  const staticMembers = (context: ModuleContext, callables: Callables): StaticMember[] => [
430
- ...collectStaticMembers(context, callables.constructors, constructorMemberName),
454
+ ...collectStaticMembers(context, callables.constructors, memberName),
431
455
  ...collectStaticMembers(context, callables.functions, memberName),
432
456
  ];
433
457
 
434
- const constructorMemberNames = (context: ModuleContext, constructors: GirFunction[]): string[] =>
435
- collectStaticMembers(context, constructors, constructorMemberName).map((member) => member.name);
436
-
437
458
  const collectStaticEntries = (
438
459
  context: ModuleContext,
439
460
  group: GirFunction[],
@@ -513,10 +534,8 @@ export {
513
534
  dedupeCallables,
514
535
  generateBindings,
515
536
  matchStaticFinishFunction,
516
- indexMethodsByName,
517
537
  isEmittableCallable,
518
538
  renderStaticSignature,
519
- constructorMemberNames,
520
539
  renderStaticHead,
521
540
  renderPlainTypeMembers,
522
541
  staticMembers,
@@ -11,10 +11,12 @@ import {
11
11
  type InheritedMethods,
12
12
  } from "../../analysis/inheritance.js";
13
13
  import {
14
+ areCallablesAssignable,
14
15
  type ClaimedMembers,
15
16
  claimInterfaceMembers,
16
17
  inheritedMembers,
17
18
  interfaceConflicts,
19
+ omittedKeys,
18
20
  omittedTypeRef,
19
21
  } from "../../analysis/interface-conflicts.js";
20
22
  import { ancestorChain, getParentRef, type ResolvedAncestor } from "../../gir/ancestry.js";
@@ -22,13 +24,13 @@ import { isEmittableEntity } from "../../gir/emittable.js";
22
24
  import { indentMembers } from "../../writer/emit.js";
23
25
  import {
24
26
  type Callables,
25
- constructorMemberNames,
26
27
  dedupeCallables,
27
28
  generateBindings,
28
29
  type InstanceScope,
29
30
  instanceScope,
30
31
  renderClassInstanceMember,
31
32
  renderStaticHead,
33
+ staticMembers,
32
34
  } from "./callables.js";
33
35
  import { renderClassConstructor, renderConstructorPropsInterface } from "./constructor-props.js";
34
36
  import { getDoc } from "./doc-spec.js";
@@ -91,7 +93,7 @@ const generateClass = (context: ModuleContext, klass: GirClass): void => {
91
93
 
92
94
  generateBindings(context, callables);
93
95
  const parentExpression = resolveParent(context, klass);
94
- const extendsClause = renderExtendsClause(context, parentExpression, callables);
96
+ const extendsClause = renderExtendsClause(context, parentExpression, klass, callables);
95
97
  const implemented = resolveImplementedRefs(context, klass);
96
98
  const typeRefs = implemented.map((ref) => omittedTypeRef(ref.typeRef, ref.conflicts));
97
99
  const implementsClause = typeRefs.length === 0 ? "" : ` implements ${typeRefs.join(", ")}`;
@@ -189,7 +191,6 @@ const renderClassMembers = (
189
191
  context,
190
192
  property,
191
193
  claimedNames,
192
- methodByName: scope.methodByName,
193
194
  inheritedTypes,
194
195
  inheritedNames,
195
196
  });
@@ -336,25 +337,80 @@ const resolveImplementedRefs = (context: ModuleContext, klass: GirClass): Implem
336
337
  return refs;
337
338
  };
338
339
 
340
+ const classCallables = (klass: GirClass): Callables => ({
341
+ constructors: klass.constructors,
342
+ functions: klass.functions,
343
+ methods: klass.methods,
344
+ });
345
+
346
+ const resolveParentClass = (context: ModuleContext, klass: GirClass): ResolvedAncestor | undefined => {
347
+ const parent = getParentRef(klass);
348
+
349
+ if (parent === undefined) {
350
+ return undefined;
351
+ }
352
+
353
+ const resolved = context.library.resolveType(parent.namespaceName ?? context.namespace.name, parent.typeName);
354
+
355
+ return resolved?.kind === "class" ? { klass: resolved.value, namespaceName: resolved.namespace.name } : undefined;
356
+ };
357
+
358
+ const addAncestorStatics = (context: ModuleContext, klass: GirClass, table: Map<string, GirFunction>): void => {
359
+ const members = staticMembers(context, classCallables(klass));
360
+
361
+ for (const member of members) {
362
+ if (!table.has(member.name)) {
363
+ table.set(member.name, member.callable);
364
+ }
365
+ }
366
+ };
367
+
368
+ const inheritedStatics = (context: ModuleContext, klass: GirClass): Map<string, GirFunction> => {
369
+ const table: Map<string, GirFunction> = new Map();
370
+ const parent = resolveParentClass(context, klass);
371
+
372
+ if (parent === undefined) {
373
+ return table;
374
+ }
375
+
376
+ for (const ancestor of ancestorChain(context.library, parent.klass, parent.namespaceName)) {
377
+ addAncestorStatics(context, ancestor.klass, table);
378
+ }
379
+
380
+ return table;
381
+ };
382
+
383
+ const shadowedStaticNames = (context: ModuleContext, klass: GirClass, callables: Callables): string[] => {
384
+ const inherited = inheritedStatics(context, klass);
385
+
386
+ return staticMembers(context, callables)
387
+ .filter((member) => {
388
+ const shadowed = inherited.get(member.name);
389
+
390
+ return shadowed !== undefined && !areCallablesAssignable(context.library, member.callable, shadowed);
391
+ })
392
+ .map((member) => member.name);
393
+ };
394
+
339
395
  const renderExtendsClause = (
340
396
  context: ModuleContext,
341
397
  parentExpression: string | undefined,
398
+ klass: GirClass,
342
399
  callables: Callables,
343
400
  ): string => {
344
401
  if (parentExpression === undefined) {
345
402
  return "";
346
403
  }
347
404
 
348
- const constructorNames = constructorMemberNames(context, callables.constructors);
405
+ const staticNames = shadowedStaticNames(context, klass, callables);
349
406
 
350
- if (constructorNames.length === 0) {
407
+ if (staticNames.length === 0) {
351
408
  return ` extends ${parentExpression}`;
352
409
  }
353
410
 
354
411
  context.addRuntimeTypeImport("StaticBase");
355
- const omitted = constructorNames.map((name) => JSON.stringify(name)).join(" | ");
356
412
 
357
- return ` extends (${parentExpression} as StaticBase<typeof ${parentExpression}, ${omitted}>)`;
413
+ return ` extends (${parentExpression} as StaticBase<typeof ${parentExpression}, ${omittedKeys(staticNames)}>)`;
358
414
  };
359
415
 
360
416
  const resolveParent = (context: ModuleContext, klass: GirClass): string | undefined => {
@@ -7,7 +7,7 @@ import { isEmittableEntity } from "../../gir/emittable.js";
7
7
  import { getDoc } from "./doc-spec.js";
8
8
 
9
9
  const TRUE_VALUES: Set<string> = new Set(["true", "1"]);
10
- const BIGINT_CATEGORIES: Set<PrimitiveCategory> = new Set(["bigint64", "biguint64", "gtype"]);
10
+ const BIGINT_CATEGORIES: Set<PrimitiveCategory> = new Set(["bigint64", "biguint64", "gtype", "pointer"]);
11
11
 
12
12
  const generateConstant = (context: ModuleContext, constant: GirConstant): void => {
13
13
  if (!isEmittableEntity(constant)) {
@@ -1,4 +1,4 @@
1
- import { sanitizeTypeIdentifier, sourceStringLiteral, uniqBy } from "@gtkx/utils";
1
+ import { escapeIdentifierStart, sanitizeTypeIdentifier, sourceStringLiteral, uniqBy } from "@gtkx/utils";
2
2
  import type { EnumMember, GirEnum } from "../../gir/enum.js";
3
3
  import type { ModuleContext } from "../../writer/context.js";
4
4
  import { hasAnnotations } from "../../gir/annotations.js";
@@ -94,11 +94,7 @@ const appendEnumDeclaration = (context: ModuleContext, enumeration: GirEnum, mem
94
94
  });
95
95
  };
96
96
 
97
- const enumMemberKey = (name: string): string => {
98
- const upper = name.toUpperCase().replaceAll("-", "_");
99
-
100
- return /^\d/.test(upper) ? `_${upper}` : upper;
101
- };
97
+ const enumMemberKey = (name: string): string => escapeIdentifierStart(name.toUpperCase().replaceAll("-", "_"));
102
98
 
103
99
  const renderQuarkExpression = (context: ModuleContext, errorDomain: string): string => {
104
100
  if (context.namespace.name === "GLib") {
@@ -336,11 +336,11 @@ const collectMethodMembers = (options: MethodMemberOptions): string[] => {
336
336
  };
337
337
 
338
338
  const collectPropertyMembers = (options: PropertyMemberOptions): string[] => {
339
- const { context, iface, scope, renderers, claimedNames } = options;
339
+ const { context, iface, renderers, claimedNames } = options;
340
340
  const members: string[] = [];
341
341
 
342
342
  for (const property of iface.properties) {
343
- const block = renderers.renderProperty({ context, property, claimedNames, methodByName: scope.methodByName });
343
+ const block = renderers.renderProperty({ context, property, claimedNames });
344
344
 
345
345
  if (block !== undefined) {
346
346
  members.push(block);
@@ -1,4 +1,4 @@
1
- import { camelCase, sourceStringLiteral } from "@gtkx/utils";
1
+ import { camelCase, escapeIdentifierStart, sourceStringLiteral } from "@gtkx/utils";
2
2
  import type { GirFunction } from "../../gir/function.js";
3
3
  import type { GirType } from "../../gir/type.js";
4
4
  import type { ModuleContext } from "../../writer/context.js";
@@ -19,7 +19,7 @@ import {
19
19
  inputParameters,
20
20
  parameterIdentifier,
21
21
  } from "../../analysis/param-structure.js";
22
- import { renderTsType } from "../../analysis/ts-type.js";
22
+ import { renderParameterTsType, renderTsType } from "../../analysis/ts-type.js";
23
23
  import { type GirParameter, isCallerAllocatedOut, isInoutParameter, isOutParameter } from "../../gir/parameter.js";
24
24
  import { hasUnknownArrayLength, type TypeId } from "../../gir/type-id.js";
25
25
  import { areClosuresInvoked } from "./closure-invocation.js";
@@ -86,12 +86,7 @@ type PlanArgsContext = {
86
86
  folded: Set<number>;
87
87
  };
88
88
 
89
- const memberName = (girName: string): string => {
90
- const camel = camelCase(girName);
91
-
92
- return /^\d/.test(camel) ? `_${camel}` : camel;
93
- };
94
-
89
+ const memberName = (girName: string): string => escapeIdentifierStart(camelCase(girName));
95
90
  const methodExportName = (fn: GirFunction): string => memberName(fn.name);
96
91
 
97
92
  const arrayLengthArgument = (source: GirParameter, sourceIndex: number): string => {
@@ -125,7 +120,7 @@ const parameterAnnotation = (context: ModuleContext, fn: GirFunction, parameter:
125
120
  return comparator;
126
121
  }
127
122
 
128
- const base = renderTsType(context, parameter.type, parameter.nullable);
123
+ const base = renderParameterTsType(context, parameter.type, parameter.nullable);
129
124
 
130
125
  return requiresClosureAnnotation(context, fn, parameter) ? closureAnnotation(context, base) : base;
131
126
  };
@@ -1,21 +1,14 @@
1
- import { camelCase, sourceStringLiteral, toCamelIdentifier } from "@gtkx/utils";
1
+ import { sourceStringLiteral, toCamelIdentifier } from "@gtkx/utils";
2
2
  import type { GirFunction } from "../../gir/function.js";
3
3
  import type { TypeId } from "../../gir/type-id.js";
4
4
  import type { ModuleContext } from "../../writer/context.js";
5
5
  import { renderDescriptor } from "../../analysis/descriptor-render.js";
6
- import { inputParameters } from "../../analysis/param-structure.js";
7
6
  import { renderTsType } from "../../analysis/ts-type.js";
8
7
  import { type GirProperty, isConstructableProperty } from "../../gir/property.js";
9
- import { comparisonContextFor } from "../../writer/comparison-context.js";
10
8
  import { renderBlock } from "../../writer/emit.js";
11
9
  import { isEmittableCallable } from "./callables.js";
12
10
  import { getDoc } from "./doc-spec.js";
13
- import { methodExportName, renderMethodReturnType } from "./method.js";
14
-
15
- type AccessorTypes = {
16
- readType: string;
17
- writeType: string;
18
- };
11
+ import { methodExportName } from "./method.js";
19
12
 
20
13
  type InheritedAccessorTypes = {
21
14
  readType: string | undefined;
@@ -29,24 +22,17 @@ type ResolvedAccessor = {
29
22
  writeType: string;
30
23
  hasGetter: boolean;
31
24
  isWritable: boolean;
32
- getterMember: string | undefined;
33
- setterMember: string | undefined;
34
25
  };
35
26
 
36
27
  type PropertyAccessorArgs = {
37
28
  context: ModuleContext;
38
29
  property: GirProperty;
39
30
  claimedNames: Set<string>;
40
- methodByName: Map<string, GirFunction>;
41
31
  inheritedTypes?: InheritedAccessorTypes | undefined;
42
32
  inheritedNames?: Set<string> | undefined;
43
33
  };
44
34
 
45
- type AccessorDelegate = { member: string; method: GirFunction };
46
- type AccessorDelegates = { getter: AccessorDelegate | undefined; setter: AccessorDelegate | undefined };
47
- type TypedDelegates = { types: AccessorTypes; delegates: AccessorDelegates };
48
-
49
- const NULLABLE_SUFFIX = " | null";
35
+ const NON_NULLABLE_KINDS: Set<string> = new Set(["primitive", "enum"]);
50
36
 
51
37
  const isNullablePropertyType = (context: ModuleContext, type: TypeId | undefined): boolean => {
52
38
  if (type === undefined) {
@@ -59,141 +45,19 @@ const isNullablePropertyType = (context: ModuleContext, type: TypeId | undefined
59
45
  return true;
60
46
  }
61
47
 
62
- if (resolved.kind === "primitive") {
63
- return false;
64
- }
65
-
66
- if (resolved.kind === "enum") {
67
- return false;
68
- }
69
-
70
48
  if (resolved.kind === "alias") {
71
49
  return isNullablePropertyType(context, resolved.value.target);
72
50
  }
73
51
 
74
- return true;
75
- };
76
-
77
- const resolveDelegate = (
78
- args: PropertyAccessorArgs,
79
- attribute: string | undefined,
80
- member: string | undefined,
81
- isDelegatable: (method: GirFunction) => boolean,
82
- ): AccessorDelegate | undefined => {
83
- const method = member !== undefined && attribute !== undefined ? args.methodByName.get(attribute) : undefined;
84
-
85
- if (member === undefined || method === undefined || !isDelegatable(method)) {
86
- return undefined;
87
- }
88
-
89
- return { member, method };
90
- };
91
-
92
- const resolveGetterDelegate = (args: PropertyAccessorArgs, jsName: string): AccessorDelegate | undefined => {
93
- const { context, property, claimedNames } = args;
94
- const member = delegateMember(property.getter, jsName, claimedNames);
95
-
96
- return resolveDelegate(
97
- args,
98
- property.getter,
99
- member,
100
- (method) =>
101
- inputParameters(context.library, method).length === 0 &&
102
- !renderMethodReturnType(context, method).startsWith("["),
103
- );
104
- };
105
-
106
- const resolveSetterDelegate = (
107
- args: PropertyAccessorArgs,
108
- jsName: string,
109
- isWritable: boolean,
110
- ): AccessorDelegate | undefined => {
111
- const { context, property, claimedNames } = args;
112
- const member = isWritable ? delegateMember(property.setter, jsName, claimedNames) : undefined;
113
-
114
- return resolveDelegate(
115
- args,
116
- property.setter,
117
- member,
118
- (method) => inputParameters(context.library, method).length === 1,
119
- );
120
- };
121
-
122
- const baseTypeName = (type: string): string =>
123
- type.endsWith(NULLABLE_SUFFIX) ? type.slice(0, -NULLABLE_SUFFIX.length) : type;
124
-
125
- const areDelegateBaseTypesAgreeing = (
126
- context: ModuleContext,
127
- getter: AccessorDelegate | undefined,
128
- setter: AccessorDelegate | undefined,
129
- ): boolean => {
130
- const setterParam = setter?.method.parameters[0];
131
-
132
- if (setterParam === undefined || getter === undefined) {
133
- return true;
134
- }
135
-
136
- const scratch = comparisonContextFor(context);
137
- const read = baseTypeName(renderMethodReturnType(scratch, getter.method));
138
- const written = baseTypeName(renderTsType(scratch, setterParam.type, false));
139
-
140
- return read === written;
141
- };
142
-
143
- const resolveDelegates = (args: PropertyAccessorArgs, jsName: string, isWritable: boolean): AccessorDelegates => {
144
- const getter = resolveGetterDelegate(args, jsName);
145
- const setter = resolveSetterDelegate(args, jsName, isWritable);
146
-
147
- if (areDelegateBaseTypesAgreeing(args.context, getter, setter)) {
148
- return { getter, setter };
149
- }
150
-
151
- return { getter, setter: undefined };
52
+ return !NON_NULLABLE_KINDS.has(resolved.kind);
152
53
  };
153
54
 
154
55
  const declaredPropertyType = (context: ModuleContext, property: GirProperty): string =>
155
- renderTsType(context, property.type, isNullablePropertyType(context, property.type));
156
-
157
- const resolveOwnTypes = (
158
- context: ModuleContext,
159
- property: GirProperty,
160
- delegates: AccessorDelegates,
161
- ): AccessorTypes => {
162
- const getterMethod = delegates.getter?.method;
163
- const setterParam = delegates.setter?.method.parameters[0];
164
-
165
- return {
166
- readType: getterMethod === undefined
167
- ? declaredPropertyType(context, property)
168
- : renderMethodReturnType(context, getterMethod),
169
- writeType: setterParam === undefined
170
- ? declaredPropertyType(context, property)
171
- : renderTsType(context, setterParam.type, setterParam.nullable || setterParam.optional),
172
- };
173
- };
174
-
175
- const isAssignableType = (source: string, target: string): boolean =>
176
- source === target || baseTypeName(target) === source;
177
-
178
- const agreeingDelegates = (
179
- delegates: AccessorDelegates,
180
- ownTypes: AccessorTypes,
181
- declaredTypes: AccessorTypes,
182
- ): AccessorDelegates => ({
183
- getter: isAssignableType(ownTypes.readType, declaredTypes.readType) ? delegates.getter : undefined,
184
- setter: isAssignableType(declaredTypes.writeType, ownTypes.writeType) ? delegates.setter : undefined,
185
- });
186
-
187
- const resolveTypedDelegates = (args: PropertyAccessorArgs, resolved: AccessorDelegates): TypedDelegates => {
188
- const ownTypes = resolveOwnTypes(args.context, args.property, resolved);
189
-
190
- const types = {
191
- readType: args.inheritedTypes?.readType ?? ownTypes.readType,
192
- writeType: args.inheritedTypes?.writeType ?? ownTypes.writeType,
193
- };
194
-
195
- return { types, delegates: agreeingDelegates(resolved, ownTypes, types) };
196
- };
56
+ renderTsType(
57
+ context,
58
+ property.type,
59
+ property.defaultValue === "NULL" || isNullablePropertyType(context, property.type),
60
+ );
197
61
 
198
62
  const isSkippedAccessor = (args: PropertyAccessorArgs, jsName: string): boolean =>
199
63
  !args.property.introspectable ||
@@ -201,31 +65,28 @@ const isSkippedAccessor = (args: PropertyAccessorArgs, jsName: string): boolean
201
65
  args.inheritedNames?.has(jsName) === true ||
202
66
  jsName === "constructor";
203
67
 
68
+ const isAccessorEmittable = (args: PropertyAccessorArgs, jsName: string, isWritable: boolean): boolean =>
69
+ !isSkippedAccessor(args, jsName) && (args.property.readable || isWritable);
70
+
204
71
  const resolveAccessor = (args: PropertyAccessorArgs): ResolvedAccessor | undefined => {
205
72
  const { property } = args;
206
73
  const jsName = toCamelIdentifier(property.name);
207
-
208
- if (isSkippedAccessor(args, jsName)) {
209
- return undefined;
210
- }
211
-
212
74
  const isWritable = isConstructableProperty(property) && !property.constructOnly;
213
- const { types, delegates } = resolveTypedDelegates(args, resolveDelegates(args, jsName, isWritable));
214
- const hasGetter = property.readable || delegates.getter !== undefined;
215
75
 
216
- if (!hasGetter && !isWritable) {
76
+ if (!isAccessorEmittable(args, jsName, isWritable)) {
217
77
  return undefined;
218
78
  }
219
79
 
80
+ const declared = declaredPropertyType(args.context, property);
81
+ const hasGetter = property.readable;
82
+
220
83
  return {
221
84
  property,
222
85
  jsName,
223
- readType: types.readType,
224
- writeType: types.writeType,
86
+ readType: args.inheritedTypes?.readType ?? declared,
87
+ writeType: args.inheritedTypes?.writeType ?? declared,
225
88
  hasGetter,
226
89
  isWritable,
227
- getterMember: delegates.getter?.member,
228
- setterMember: delegates.setter?.member,
229
90
  };
230
91
  };
231
92
 
@@ -234,7 +95,6 @@ const resolveOwnerAccessor = (
234
95
  property: GirProperty,
235
96
  methods: GirFunction[],
236
97
  ): ResolvedAccessor | undefined => {
237
- const methodByName: Map<string, GirFunction> = new Map();
238
98
  const claimedNames: Set<string> = new Set();
239
99
 
240
100
  for (const method of methods) {
@@ -242,11 +102,10 @@ const resolveOwnerAccessor = (
242
102
  continue;
243
103
  }
244
104
 
245
- methodByName.set(method.name, method);
246
105
  claimedNames.add(methodExportName(method));
247
106
  }
248
107
 
249
- return resolveAccessor({ context, property, claimedNames, methodByName });
108
+ return resolveAccessor({ context, property, claimedNames });
250
109
  };
251
110
 
252
111
  const resolveAccessorTypes = (
@@ -284,18 +143,15 @@ const renderResolvedPropertyAccessor = (
284
143
  property: GirProperty,
285
144
  accessor: ResolvedAccessor,
286
145
  ): string => {
287
- const { jsName, readType, writeType, hasGetter, isWritable, setterMember } = accessor;
146
+ const { jsName, readType, writeType, hasGetter, isWritable } = accessor;
288
147
  const blocks: string[] = [];
289
148
 
290
149
  if (hasGetter) {
291
- blocks.push(renderBlock(`get ${jsName}(): ${readType}`, renderGetterBody(context, property, accessor)));
150
+ blocks.push(renderBlock(`get ${jsName}(): ${readType}`, renderGenericGetBody(context, property, readType)));
292
151
  }
293
152
 
294
153
  if (isWritable) {
295
- const setterBody =
296
- setterMember === undefined ? renderGenericSetBody(context, property) : `this.${setterMember}(value);`;
297
-
298
- blocks.push(renderBlock(`set ${jsName}(value: ${writeType})`, setterBody));
154
+ blocks.push(renderBlock(`set ${jsName}(value: ${writeType})`, renderGenericSetBody(context, property)));
299
155
  }
300
156
 
301
157
  return `${propertyDoc(property)}${blocks.join("\n\n")}`;
@@ -347,33 +203,6 @@ const renderGenericSetBody = (context: ModuleContext, property: GirProperty): st
347
203
  return `setObjectProperty(this, ${sourceStringLiteral(property.name)}, ${descriptor}, value);`;
348
204
  };
349
205
 
350
- const renderGetterBody = (context: ModuleContext, property: GirProperty, accessor: ResolvedAccessor): string =>
351
- accessor.getterMember === undefined
352
- ? renderGenericGetBody(context, property, accessor.readType)
353
- : `return this.${accessor.getterMember}();`;
354
-
355
- const delegateMember = (
356
- attribute: string | undefined,
357
- accessorName: string,
358
- claimedNames: Set<string>,
359
- ): string | undefined => {
360
- if (attribute === undefined) {
361
- return undefined;
362
- }
363
-
364
- const member = camelCase(attribute);
365
-
366
- if (member === accessorName) {
367
- return undefined;
368
- }
369
-
370
- if (!claimedNames.has(member)) {
371
- return undefined;
372
- }
373
-
374
- return member;
375
- };
376
-
377
206
  export {
378
207
  propertyDoc,
379
208
  resolveAccessor,
@@ -121,9 +121,9 @@ const renderRecordConstructor = (context: ModuleContext, spec: RecordConstructor
121
121
 
122
122
  const statements = [
123
123
  ...superCall,
124
- `const handle = alloc(${allocArgs(context, record, size).join(", ")});`,
124
+ `const __handle = alloc(${allocArgs(context, record, size).join(", ")});`,
125
125
  ...renderFieldWrites(context, slots),
126
- "setHandle(this, handle);",
126
+ "setHandle(this, __handle);",
127
127
  ];
128
128
 
129
129
  return renderBlock(`constructor(props: ${className}ConstructorProps = {})`, statements.join("\n"));
@@ -151,7 +151,7 @@ const renderFieldWrite = (context: ModuleContext, entry: WritableFieldSlot): str
151
151
  const write = emitFieldWrite(context, {
152
152
  descriptor,
153
153
  slot: entry.slot,
154
- targetExpr: "handle",
154
+ targetExpr: "__handle",
155
155
  valueExpr: `props.${name}`,
156
156
  });
157
157