@gtkx/runtime 2.0.0-beta.1 → 2.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/internal.d.ts +16 -0
  2. package/dist/internal.d.ts.map +1 -1
  3. package/dist/internal.js +12 -0
  4. package/dist/internal.js.map +1 -1
  5. package/dist/listeners.d.ts +3 -13
  6. package/dist/listeners.d.ts.map +1 -1
  7. package/dist/listeners.js +12 -12
  8. package/dist/listeners.js.map +1 -1
  9. package/dist/mixin.d.ts +5 -3
  10. package/dist/mixin.d.ts.map +1 -1
  11. package/dist/mixin.js +36 -9
  12. package/dist/mixin.js.map +1 -1
  13. package/dist/object.d.ts +11 -0
  14. package/dist/object.d.ts.map +1 -1
  15. package/dist/object.js +18 -25
  16. package/dist/object.js.map +1 -1
  17. package/dist/properties.d.ts +4 -2
  18. package/dist/properties.d.ts.map +1 -1
  19. package/dist/properties.js +69 -16
  20. package/dist/properties.js.map +1 -1
  21. package/dist/property-brand.d.ts +5 -0
  22. package/dist/property-brand.d.ts.map +1 -0
  23. package/dist/property-brand.js +5 -0
  24. package/dist/property-brand.js.map +1 -0
  25. package/dist/register-class.d.ts +102 -20
  26. package/dist/register-class.d.ts.map +1 -1
  27. package/dist/register-class.js +19 -37
  28. package/dist/register-class.js.map +1 -1
  29. package/dist/registry.d.ts +1 -1
  30. package/dist/registry.d.ts.map +1 -1
  31. package/dist/registry.js +4 -4
  32. package/dist/registry.js.map +1 -1
  33. package/dist/signal-brand.d.ts +12 -0
  34. package/dist/signal-brand.d.ts.map +1 -0
  35. package/dist/signal-brand.js +6 -0
  36. package/dist/signal-brand.js.map +1 -0
  37. package/dist/signal.d.ts +39 -2
  38. package/dist/signal.d.ts.map +1 -1
  39. package/dist/signal.js +75 -5
  40. package/dist/signal.js.map +1 -1
  41. package/dist/type.d.ts.map +1 -1
  42. package/dist/type.js +1 -1
  43. package/dist/type.js.map +1 -1
  44. package/package.json +4 -4
  45. package/src/internal.ts +41 -0
  46. package/src/listeners.ts +21 -26
  47. package/src/mixin.ts +55 -9
  48. package/src/object.ts +55 -5
  49. package/src/properties.ts +94 -17
  50. package/src/property-brand.ts +5 -0
  51. package/src/register-class.ts +296 -95
  52. package/src/registry.ts +4 -4
  53. package/src/signal-brand.ts +29 -0
  54. package/src/signal.ts +177 -6
  55. package/src/type.ts +1 -1
package/src/properties.ts CHANGED
@@ -55,7 +55,7 @@ type AccessorBase = PropertyCheck & {
55
55
  type DeclaredAccessor = AccessorBase & {
56
56
  isInterfaceProperty?: false;
57
57
  memberName: string;
58
- hasGeneratedMember: boolean;
58
+ hasMemberAccessor: boolean;
59
59
  };
60
60
 
61
61
  type InterfaceAccessor = AccessorBase & { isInterfaceProperty: true };
@@ -100,7 +100,7 @@ const paramSpecDefaultValue = bind(LIB, "g_param_spec_get_default_value", [PARAM
100
100
  const paramSpecName = bind(LIB, "g_param_spec_get_name", [PARAM_T], stringT("borrowed"));
101
101
  const typeClassRef = bind(LIB, "g_type_class_ref", [biguint64T], CLASS_T);
102
102
  const typeClassUnref = bind(LIB, "g_type_class_unref", [CLASS_T], voidT);
103
- const coercionChecks: Map<bigint, Map<string, PropertyCheck | null>> = new Map();
103
+ const propertyChecks: Map<bigint, Map<string, PropertyCheck | null>> = new Map();
104
104
  const classFindProperty = bind(LIB, "g_object_class_find_property", [CLASS_T, stringT("borrowed")], PARAM_T);
105
105
 
106
106
  const classListProperties = bind(
@@ -214,8 +214,11 @@ const findSourceSpec = (source: bigint | AnyClass, name: string): ExternalObject
214
214
  * @param source The GType, wrapper class or interface declaring the property.
215
215
  * @returns Handle of the override spec.
216
216
  */
217
- const newParamSpecOverride = (name: string, source: bigint | AnyClass): ExternalObject<Handle> =>
218
- paramSpecOverrideNew(name, findSourceSpec(source, name)) as ExternalObject<Handle>;
217
+ const newParamSpecOverride = (name: string, source: bigint | AnyClass): ExternalObject<Handle> => {
218
+ const canonicalName = canonicalCase(name);
219
+
220
+ return paramSpecOverrideNew(canonicalName, findSourceSpec(source, canonicalName)) as ExternalObject<Handle>;
221
+ };
219
222
 
220
223
  function describeValue(value: unknown): string {
221
224
  if (typeof value === "string") {
@@ -283,6 +286,24 @@ function assertWritable(instance: object, check: PropertyCheck, value: unknown):
283
286
  throw new TypeError(propertyMessage(instance, check, refusalTail(check, value, READ_ONLY_REASON)));
284
287
  }
285
288
 
289
+ function assertReadable(instance: object, check: PropertyCheck): void {
290
+ if (isParamReadable(check.flags)) {
291
+ return;
292
+ }
293
+
294
+ throw new TypeError(
295
+ propertyMessage(instance, check, `cannot read property '${check.propertyName}'; the property is write-only`),
296
+ );
297
+ }
298
+
299
+ function assertMutable(instance: object, check: PropertyCheck, value: unknown): void {
300
+ assertWritable(instance, check, value);
301
+
302
+ if (isParamConstructOnly(check.flags)) {
303
+ throw new TypeError(propertyMessage(instance, check, refusalTail(check, value, CONSTRUCT_ONLY_REASON)));
304
+ }
305
+ }
306
+
286
307
  function writeHeld(check: PropertyCheck, gValue: ExternalObject<Handle>, value: unknown): void {
287
308
  check.write ??= valueWriterFor(check.valueType);
288
309
  check.write(gValue, check.narrowValue(value));
@@ -333,7 +354,7 @@ function isReadableProperty(gtype: bigint, propertyName: string): boolean {
333
354
  }
334
355
  }
335
356
 
336
- function lookupCoercionCheck(gtype: bigint, name: string): PropertyCheck | null {
357
+ function lookupPropertyCheck(gtype: bigint, name: string): PropertyCheck | null {
337
358
  const klass = typeClassRef(gtype) as ExternalObject<Handle>;
338
359
 
339
360
  try {
@@ -345,10 +366,35 @@ function lookupCoercionCheck(gtype: bigint, name: string): PropertyCheck | null
345
366
  }
346
367
  }
347
368
 
348
- function coercionCheckFor(gtype: bigint, name: string): PropertyCheck | null {
349
- const checks = coercionChecks.getOrInsertComputed(gtype, () => new Map<string, PropertyCheck | null>());
369
+ function propertyCheckFor(gtype: bigint, name: string): PropertyCheck | null {
370
+ const checks = propertyChecks.getOrInsertComputed(gtype, () => new Map<string, PropertyCheck | null>());
371
+
372
+ return checks.getOrInsertComputed(name, () => lookupPropertyCheck(gtype, name));
373
+ }
374
+
375
+ function objectPropertyCheckFor(instance: object, name: string): PropertyCheck {
376
+ const gtype = getInstanceType(instance);
377
+ const check = typeIsA(gtype, TYPE_OBJECT) ? propertyCheckFor(gtype, name) : null;
378
+
379
+ if (check === null) {
380
+ throw new TypeError(`${instanceClassName(instance)} has no GObject property named '${name}'`);
381
+ }
350
382
 
351
- return checks.getOrInsertComputed(name, () => lookupCoercionCheck(gtype, name));
383
+ return check;
384
+ }
385
+
386
+ function readableObjectPropertyFor(instance: object, name: string): ConstructProperty {
387
+ const check = objectPropertyCheckFor(instance, name);
388
+ assertReadable(instance, check);
389
+
390
+ return { name: check.propertyName, value: newValueForType(check.valueType) };
391
+ }
392
+
393
+ function writableObjectPropertyFor(instance: object, name: string, value: unknown): ConstructProperty {
394
+ const check = objectPropertyCheckFor(instance, name);
395
+ assertMutable(instance, check, value);
396
+
397
+ return { name: check.propertyName, value: checkedValueFor(instance, check, value) };
352
398
  }
353
399
 
354
400
  function truncateToWhole(check: PropertyCheck, value: number): number {
@@ -384,7 +430,7 @@ function coercePropertyValue(gtype: bigint, propertyName: string, value: unknown
384
430
  return value;
385
431
  }
386
432
 
387
- const check = coercionCheckFor(gtype, propertyName);
433
+ const check = propertyCheckFor(gtype, propertyName);
388
434
 
389
435
  return check === null ? value : coerceNumber(check, value);
390
436
  }
@@ -499,12 +545,35 @@ function checkedSetter(accessor: DeclaredAccessor): (this: object, value: unknow
499
545
  };
500
546
  }
501
547
 
502
- function hasOwnMember(prototype: object, alias: string): boolean {
503
- return Object.getOwnPropertyDescriptor(prototype, alias) !== undefined;
548
+ function memberDescriptorFor(prototype: object, name: string): PropertyDescriptor | undefined {
549
+ let current: object | null = prototype;
550
+
551
+ while (current !== null) {
552
+ const descriptor = Object.getOwnPropertyDescriptor(current, name);
553
+
554
+ if (descriptor !== undefined) {
555
+ return descriptor;
556
+ }
557
+
558
+ current = Reflect.getPrototypeOf(current);
559
+ }
560
+
561
+ return undefined;
562
+ }
563
+
564
+ function isMemberAccessor(descriptor: PropertyDescriptor | undefined): boolean {
565
+ return descriptor !== undefined && ("get" in descriptor || "set" in descriptor);
504
566
  }
505
567
 
506
568
  function defineAccessor(prototype: object, descriptor: PropertyDescriptor, alias: string): void {
507
- if (hasOwnMember(prototype, alias)) {
569
+ if (Object.getOwnPropertyDescriptor(prototype, alias) !== undefined) {
570
+ return;
571
+ }
572
+
573
+ const parent = Reflect.getPrototypeOf(prototype);
574
+ const inherited = parent === null ? undefined : memberDescriptorFor(parent, alias);
575
+
576
+ if (inherited !== undefined && !isMemberAccessor(inherited)) {
508
577
  return;
509
578
  }
510
579
 
@@ -513,13 +582,13 @@ function defineAccessor(prototype: object, descriptor: PropertyDescriptor, alias
513
582
 
514
583
  function installAccessors(klass: AnyClass, accessor: DeclaredAccessor): void {
515
584
  const prototype = (klass as { prototype: object }).prototype;
516
- accessor.hasGeneratedMember = !hasOwnMember(prototype, accessor.memberName);
585
+ accessor.hasMemberAccessor = isMemberAccessor(Object.getOwnPropertyDescriptor(prototype, accessor.memberName));
517
586
 
518
587
  const descriptor: PropertyDescriptor = {
519
588
  configurable: true,
520
589
  enumerable: true,
521
- get: accessor.hasGeneratedMember ? storedGetter(accessor) : memberGetter(accessor),
522
- set: accessor.hasGeneratedMember ? checkedSetter(accessor) : memberSetter(accessor),
590
+ get: accessor.hasMemberAccessor ? memberGetter(accessor) : storedGetter(accessor),
591
+ set: accessor.hasMemberAccessor ? memberSetter(accessor) : checkedSetter(accessor),
523
592
  };
524
593
 
525
594
  for (const alias of accessorNames(accessor.name)) {
@@ -586,7 +655,13 @@ function callMember(instance: object, member: string, args: unknown[]): unknown
586
655
  }
587
656
 
588
657
  function backingMemberFor(instance: object, accessor: DeclaredAccessor): string | undefined {
589
- if (accessor.hasGeneratedMember && !Object.hasOwn(instance, accessor.memberName)) {
658
+ if (accessor.hasMemberAccessor) {
659
+ return accessor.memberName;
660
+ }
661
+
662
+ const descriptor = Object.getOwnPropertyDescriptor(instance, accessor.memberName);
663
+
664
+ if (descriptor === undefined || ("value" in descriptor && typeof descriptor.value === "function")) {
590
665
  return undefined;
591
666
  }
592
667
 
@@ -686,7 +761,7 @@ function buildAccessor(klass: AnyClass, name: string, pspec: PropertySpec): Decl
686
761
  ...checkFor(getHandle(pspec), name),
687
762
  memberName: camelCase(name),
688
763
  storage: Symbol(`gtkx:property:${name}`),
689
- hasGeneratedMember: false,
764
+ hasMemberAccessor: false,
690
765
  };
691
766
 
692
767
  installAccessors(klass, accessor);
@@ -770,8 +845,10 @@ export {
770
845
  makeGetProperty,
771
846
  makeSetProperty,
772
847
  newParamSpecOverride,
848
+ readableObjectPropertyFor,
773
849
  SET_PROPERTY_VFUNC,
774
850
  toNativeProperties,
851
+ writableObjectPropertyFor,
775
852
  type ConstructProperty,
776
853
  type PropertyDispatch,
777
854
  type PropertySpec,
@@ -0,0 +1,5 @@
1
+ const propertyMapOverride: unique symbol = Symbol("gtkx.propertyMapOverride");
2
+ const writablePropertyMapOverride: unique symbol = Symbol("gtkx.writablePropertyMapOverride");
3
+ const descriptorFreePropertySpec: unique symbol = Symbol("gtkx.descriptorFreePropertySpec");
4
+
5
+ export { descriptorFreePropertySpec, propertyMapOverride, writablePropertyMapOverride };