@gtkx/runtime 1.0.0-rc.2 → 1.0.0-rc.4

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 (86) hide show
  1. package/README.md +4 -5
  2. package/dist/arg.d.ts +7 -2
  3. package/dist/arg.d.ts.map +1 -1
  4. package/dist/arg.js +2 -2
  5. package/dist/arg.js.map +1 -1
  6. package/dist/callback.js +1 -1
  7. package/dist/callback.js.map +1 -1
  8. package/dist/descriptors.d.ts +33 -5
  9. package/dist/descriptors.d.ts.map +1 -1
  10. package/dist/descriptors.js +12 -12
  11. package/dist/descriptors.js.map +1 -1
  12. package/dist/error.d.ts +6 -0
  13. package/dist/error.d.ts.map +1 -1
  14. package/dist/error.js +1 -1
  15. package/dist/error.js.map +1 -1
  16. package/dist/fn.d.ts +5 -1
  17. package/dist/fn.d.ts.map +1 -1
  18. package/dist/fn.js +12 -12
  19. package/dist/fn.js.map +1 -1
  20. package/dist/index.d.ts +17 -3
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +15 -1
  23. package/dist/index.js.map +1 -1
  24. package/dist/lifecycle.d.ts +14 -4
  25. package/dist/lifecycle.d.ts.map +1 -1
  26. package/dist/lifecycle.js +3 -2
  27. package/dist/lifecycle.js.map +1 -1
  28. package/dist/listeners.d.ts +6 -0
  29. package/dist/listeners.d.ts.map +1 -1
  30. package/dist/listeners.js.map +1 -1
  31. package/dist/mixin.d.ts +13 -0
  32. package/dist/mixin.d.ts.map +1 -1
  33. package/dist/mixin.js +5 -5
  34. package/dist/mixin.js.map +1 -1
  35. package/dist/native-value.d.ts +8 -0
  36. package/dist/native-value.d.ts.map +1 -1
  37. package/dist/native-value.js +8 -0
  38. package/dist/native-value.js.map +1 -1
  39. package/dist/promisify.d.ts +3 -5
  40. package/dist/promisify.d.ts.map +1 -1
  41. package/dist/promisify.js +1 -1
  42. package/dist/promisify.js.map +1 -1
  43. package/dist/properties.d.ts +1 -0
  44. package/dist/properties.d.ts.map +1 -1
  45. package/dist/properties.js.map +1 -1
  46. package/dist/register-class.d.ts +5 -5
  47. package/dist/register-class.d.ts.map +1 -1
  48. package/dist/register-class.js +1 -4
  49. package/dist/register-class.js.map +1 -1
  50. package/dist/registry.d.ts +16 -2
  51. package/dist/registry.d.ts.map +1 -1
  52. package/dist/registry.js +4 -2
  53. package/dist/registry.js.map +1 -1
  54. package/dist/signal.d.ts +13 -1
  55. package/dist/signal.d.ts.map +1 -1
  56. package/dist/signal.js +2 -2
  57. package/dist/signal.js.map +1 -1
  58. package/dist/t.d.ts +44 -0
  59. package/dist/t.d.ts.map +1 -1
  60. package/dist/t.js.map +1 -1
  61. package/dist/type.d.ts +0 -1
  62. package/dist/type.d.ts.map +1 -1
  63. package/dist/type.js.map +1 -1
  64. package/dist/value.d.ts +2 -9
  65. package/dist/value.d.ts.map +1 -1
  66. package/dist/value.js +2 -9
  67. package/dist/value.js.map +1 -1
  68. package/package.json +4 -4
  69. package/src/arg.ts +9 -4
  70. package/src/callback.ts +1 -1
  71. package/src/descriptors.ts +54 -19
  72. package/src/error.ts +7 -1
  73. package/src/fn.ts +18 -14
  74. package/src/index.ts +17 -3
  75. package/src/lifecycle.ts +14 -4
  76. package/src/listeners.ts +6 -0
  77. package/src/mixin.ts +12 -6
  78. package/src/native-value.ts +8 -0
  79. package/src/promisify.ts +4 -6
  80. package/src/properties.ts +1 -0
  81. package/src/register-class.ts +6 -8
  82. package/src/registry.ts +16 -2
  83. package/src/signal.ts +18 -4
  84. package/src/t.ts +44 -0
  85. package/src/type.ts +0 -1
  86. package/src/value.ts +2 -9
package/src/mixin.ts CHANGED
@@ -1,7 +1,13 @@
1
1
  import type { AnyClass } from "@gtkx/utils";
2
2
 
3
+ /**
4
+ * The signal plumbing every base class passed to a {@link Mixin} provides, so mixed-in interface
5
+ * members can connect and emit without knowing the concrete class.
6
+ */
3
7
  type MixinReceiver = {
8
+ /** Connects a handler to a signal and returns its handler id. */
4
9
  connect(signal: string, handler: (...args: unknown[]) => unknown, isAfter?: boolean): number;
10
+ /** Emits a signal with the given arguments and returns whatever the emission produced. */
5
11
  emit(signal: string, ...args: unknown[]): unknown;
6
12
  };
7
13
 
@@ -41,6 +47,12 @@ function copyLayerMember(target: AnyClass, layer: object, key: string): void {
41
47
  }
42
48
  }
43
49
 
50
+ function copyLayerMembers(target: AnyClass, layer: object): void {
51
+ for (const key of Object.getOwnPropertyNames(layer)) {
52
+ copyLayerMember(target, layer, key);
53
+ }
54
+ }
55
+
44
56
  /**
45
57
  * Copies each mixin's prototype members onto the target class prototype, skipping
46
58
  * any member already defined anywhere in the target's class chain.
@@ -48,12 +60,6 @@ function copyLayerMember(target: AnyClass, layer: object, key: string): void {
48
60
  * @param target The class whose prototype receives the mixin members.
49
61
  * @param mixins The mixins to apply, in order.
50
62
  */
51
- function copyLayerMembers(target: AnyClass, layer: object): void {
52
- for (const key of Object.getOwnPropertyNames(layer)) {
53
- copyLayerMember(target, layer, key);
54
- }
55
- }
56
-
57
63
  function installMixins(target: AnyClass, mixins: Mixin[]): void {
58
64
  const empty: AnyClass<MixinReceiver> = class {
59
65
  connect(): number {
@@ -111,6 +111,14 @@ function hashTableToNative(descriptor: HashTableDescriptor, value: unknown): unk
111
111
  ]);
112
112
  }
113
113
 
114
+ /**
115
+ * Converts a JavaScript value into the raw form native code expects, unwrapping
116
+ * object, struct, boxed, and fundamental wrappers back to their handles and
117
+ * recursively converting arrays and maps according to the descriptor.
118
+ *
119
+ * @param descriptor Describes the native type to convert to.
120
+ * @param value The JavaScript value to convert.
121
+ */
114
122
  function toNative(descriptor: Descriptor, value: unknown): unknown {
115
123
  if (!isMarshalledDescriptor(descriptor)) {
116
124
  return value;
package/src/promisify.ts CHANGED
@@ -1,10 +1,8 @@
1
1
  import { tryGetHandle } from "./registry.js";
2
2
 
3
3
  /**
4
- * Extracts the finished value from the async result a GIO-style operation completes with.
5
- *
6
- * @template R - The async result type passed to the completion callback.
7
- * @template T - The finished value type.
4
+ * Extracts the value of a completed asynchronous operation from its `GAsyncResult`, throwing when
5
+ * the operation failed.
8
6
  */
9
7
  type FinishResult<R extends object, T> = (result: R) => T;
10
8
 
@@ -57,11 +55,11 @@ const promisify = <R extends object, T>(
57
55
  ): Promise<T> =>
58
56
  new Promise<T>((resolve, reject) => {
59
57
  const creationStack =
60
- process.env.NODE_ENV === "production" ? undefined : new Error("gtkx async operation started here");
58
+ process.env.NODE_ENV === "production" ? undefined : new Error("GTKX async operation started here");
61
59
 
62
60
  asyncFn(...leading, tryGetHandle(cancellable), (_source: object | null, asyncResult: object) => {
63
61
  settle({ finish, creationStack, resolve, reject }, asyncResult);
64
62
  });
65
63
  });
66
64
 
67
- export { promisify, type FinishResult };
65
+ export { promisify };
package/src/properties.ts CHANGED
@@ -12,6 +12,7 @@ type PropertyAccessor = {
12
12
  pspec: object;
13
13
  };
14
14
 
15
+ /** A `GObject.ParamSpec` wrapper describing one property's name, type, flags and default. */
15
16
  type PropertySpec = object;
16
17
  type NotifyingObject = { notify?: (propertyName: string) => void };
17
18
 
@@ -23,13 +23,14 @@ import {
23
23
  } from "./registry.js";
24
24
  import { TYPE_INVALID, typeInterfaces } from "./type.js";
25
25
 
26
+ /** What {@link registerClass} adds to the new GType beyond the vtable slots it discovers on the class. */
26
27
  type RegisterClassOptions = {
28
+ /** Name to register the new GType under, defaulting to the class's own name. */
27
29
  typeName?: string;
28
30
  /**
29
- * Properties to install on the new type, keyed by canonical property name. Each value is the
30
- * `GObject.ParamSpec` describing it, for example `GObject.paramSpecString(...)`. Accessors are
31
- * generated on the prototype for the dashed, underscored and camelCased spellings of the name
32
- * unless the class already defines one, and writing through them emits `notify`.
31
+ * Properties to install on the new type, keyed by canonical name and valued with the
32
+ * `GObject.ParamSpec` describing each. Every property gains dashed, underscored and camelCased
33
+ * prototype accessors that emit `notify` on write, unless the class already defines that name.
33
34
  */
34
35
  properties?: Record<string, PropertySpec>;
35
36
  };
@@ -50,7 +51,6 @@ const VALUE_ARG_INDEX = 2;
50
51
  * unsupported construct-time vtable slot.
51
52
  *
52
53
  * @param klass The subclass to register.
53
- * @param options Registration options, such as an explicit type name.
54
54
  * @returns The same class, now registered.
55
55
  */
56
56
  function registerClass<T extends AnyClass>(klass: T, options: RegisterClassOptions = {}): T {
@@ -237,11 +237,9 @@ function propertyVfuncs(klass: AnyClass, accessors: PropertyAccessor[]): Discove
237
237
  ];
238
238
  }
239
239
 
240
- // `get_property` fills a GValue the caller owns, so the marshalled copy handed to JavaScript has to
241
- // be written back into it; `set_property` only reads its GValue and needs no copy back.
242
240
  function markValueCallerAllocated(argDescriptors: Descriptor[]): Descriptor[] {
243
241
  return argDescriptors.map((arg, index) =>
244
- index === VALUE_ARG_INDEX ? { ...arg, callerAllocated: true } : arg);
242
+ index === VALUE_ARG_INDEX ? { ...arg, isCallerAllocated: true } : arg);
245
243
  }
246
244
 
247
245
  function buildPropertyVfunc(
package/src/registry.ts CHANGED
@@ -17,16 +17,28 @@ import { TYPE_INVALID, type TypedClass, typeInterfaces, typeIsA, typeName, typeP
17
17
  type StaticBase<C, K extends PropertyKey = "new"> = Omit<C, K> &
18
18
  (C extends new (...args: infer A) => infer R ? new (...args: A) => R : never);
19
19
 
20
+ /** One overridable vtable slot: where it sits in the vtable struct and how it is marshalled. */
20
21
  type VfuncDescriptor<K extends "class" | "interface"> = {
22
+ /** Whether the slot lives in a class struct or in an interface vtable. */
21
23
  kind: K;
24
+ /** GIR name of the type struct holding the slot, without its namespace, such as `WidgetClass`. */
22
25
  className: string;
26
+ /** Name of the slot's field in that struct. */
23
27
  vfuncName: string;
28
+ /** Byte offset of the slot within the struct. */
24
29
  byteOffset: number;
30
+ /** Byte size of the struct, used to bounds-check `VfuncDescriptor.byteOffset`. */
25
31
  vtableSize: number;
32
+ /** Descriptor for each argument the slot receives, starting with the instance. */
26
33
  argDescriptors: NativeRegisterClassVfunc["argDescriptors"];
34
+ /** Descriptor for the value the slot returns. */
27
35
  returnDescriptor: NativeRegisterClassVfunc["returnDescriptor"];
28
36
  };
29
37
 
38
+ /**
39
+ * The vtable slots a wrapper class or interface exposes, keyed by the JavaScript method name that
40
+ * overrides each one.
41
+ */
30
42
  type VfuncRegistry = Record<string, VfuncDescriptor<"class"> | VfuncDescriptor<"interface">>;
31
43
 
32
44
  const classRegistry: Map<bigint, AnyClass> = new Map();
@@ -65,7 +77,8 @@ function registerClassType(cls: AnyClass, type: bigint): void {
65
77
  * installing a registry of virtual functions.
66
78
  * @param cls Wrapper class to associate with the type.
67
79
  * @param type GType the class wraps.
68
- * @param vfuncs Virtual functions the class overrides.
80
+ * @param vfuncs Vtable slots the class exposes, so `registerClass` can bind the ones a subclass
81
+ * overrides.
69
82
  */
70
83
  function registerWrapperClass(cls: AnyClass, type: bigint, vfuncs?: VfuncRegistry): void {
71
84
  registerClassType(cls, type);
@@ -81,7 +94,8 @@ function registerWrapperClass(cls: AnyClass, type: bigint, vfuncs?: VfuncRegistr
81
94
  * @param cls Class carrying the interface's GType tag.
82
95
  * @param type GType of the interface.
83
96
  * @param mixin Mixin that applies the interface to a wrapper class.
84
- * @param vfuncs Virtual functions the interface exposes.
97
+ * @param vfuncs Vtable slots the interface exposes, so `registerClass` can bind the ones an
98
+ * implementing class overrides.
85
99
  */
86
100
  function registerInterface(cls: AnyClass, type: bigint, mixin: Mixin, vfuncs?: VfuncRegistry): void {
87
101
  if (type === TYPE_INVALID) {
package/src/signal.ts CHANGED
@@ -30,13 +30,27 @@ import {
30
30
  /** Function invoked when a connected GObject signal is emitted. */
31
31
  type SignalHandler = (...args: unknown[]) => unknown;
32
32
 
33
+ /** The marshalling and handler that make up a single signal connection. */
33
34
  type SignalConnectSpec = {
35
+ /**
36
+ * Marshalling for the emission, whose `argDescriptors` lead with the emitter and include the
37
+ * closure's user data slot.
38
+ */
34
39
  callback: CallbackDescriptor;
40
+ /** Called on each emission with the signal's own arguments, without the leading emitter. */
35
41
  handler: SignalHandler;
36
- after: boolean;
42
+ /** When true, run the handler after the class's default handler instead of before it. */
43
+ isAfter: boolean;
37
44
  };
38
45
 
39
- type EmitArg = Arg & { value?: unknown };
46
+ /** One argument of a signal emission: how to marshal it, plus the value to marshal. */
47
+ type EmitArg = Arg & {
48
+ /**
49
+ * The value to pass for an input or inout argument, or the caller-allocated storage to fill for
50
+ * a caller-allocated output argument; omitted for a plain output argument.
51
+ */
52
+ value?: unknown;
53
+ };
40
54
 
41
55
  const connectCache = createBindCache();
42
56
  const gQuarkFromString = bind(LIB, "g_quark_from_string", [stringT("borrowed")], uint32T);
@@ -108,12 +122,12 @@ function connectBind(type: bigint, signal: string, callback: CallbackDescriptor)
108
122
  * @param spec Callback descriptor, handler function, and whether to run after the default handler.
109
123
  */
110
124
  function connectSignal(instance: object, signal: string, spec: SignalConnectSpec): number {
111
- const { callback, handler, after } = spec;
125
+ const { callback, handler, isAfter } = spec;
112
126
  const wrapped = wrapCallback(handler, callback, "emitter");
113
127
  const type: bigint = (instance as TypedClass).__type__;
114
128
  const connect = connectBind(type, signal, callback);
115
129
 
116
- return connect(getHandle(instance), signal, wrapped, after ? 1 : 0) as number;
130
+ return connect(getHandle(instance), signal, wrapped, isAfter ? 1 : 0) as number;
117
131
  }
118
132
 
119
133
  function blockMatchedSignalHandlers(instance: object, signal: string): void {
package/src/t.ts CHANGED
@@ -2,43 +2,87 @@ import { bind } from "./bind.js";
2
2
  import * as helpers from "./descriptors.js";
3
3
  import { fn } from "./fn.js";
4
4
 
5
+ /** The descriptor factories and function binders exposed as {@link t}. */
5
6
  type T = {
7
+ /** Binds a symbol in a shared library to a callable that marshals its arguments and return value. */
6
8
  bind: typeof bind;
9
+ /** Descriptor for a `gint8`, marshalled as a number. */
7
10
  int8: typeof helpers.int8T;
11
+ /** Descriptor for a `guint8`, marshalled as a number. */
8
12
  uint8: typeof helpers.uint8T;
13
+ /** Descriptor for a `gint16`, marshalled as a number. */
9
14
  int16: typeof helpers.int16T;
15
+ /** Descriptor for a `guint16`, marshalled as a number. */
10
16
  uint16: typeof helpers.uint16T;
17
+ /** Descriptor for a `gint32`, marshalled as a number. */
11
18
  int32: typeof helpers.int32T;
19
+ /** Descriptor for a `guint32`, marshalled as a number. */
12
20
  uint32: typeof helpers.uint32T;
21
+ /** Descriptor for a `gint64`, marshalled as a number and rejected outside the 2^53 safe range. */
13
22
  int64: typeof helpers.int64T;
23
+ /** Descriptor for a `guint64`, marshalled as a number and rejected outside the 2^53 safe range. */
14
24
  uint64: typeof helpers.uint64T;
25
+ /** Descriptor for a `gint64`, marshalled as a bigint so the full 64-bit range survives. */
15
26
  bigint64: typeof helpers.bigint64T;
27
+ /** Descriptor for a `guint64`, marshalled as a bigint so the full 64-bit range survives. */
16
28
  biguint64: typeof helpers.biguint64T;
29
+ /** Descriptor for a `GType`, marshalled as a bigint and recognized as a GType by GValue conversion. */
17
30
  gtype: typeof helpers.gtypeT;
31
+ /** Descriptor for a `gfloat`. */
18
32
  float32: typeof helpers.float32T;
33
+ /** Descriptor for a `gdouble`. */
19
34
  float64: typeof helpers.float64T;
35
+ /** Descriptor for a `gboolean`, marshalled as a JavaScript boolean. */
20
36
  boolean: typeof helpers.booleanT;
37
+ /** Descriptor for the absence of a value, used as the return descriptor of a `void` function. */
21
38
  void: typeof helpers.voidT;
39
+ /** Descriptor for a `gunichar`, marshalled as a single-character string or a codepoint number. */
22
40
  unichar: typeof helpers.unicharT;
41
+ /** Descriptor for an opaque `gpointer` argument, taken from a typed array's memory or a numeric address. */
23
42
  buffer: typeof helpers.bufferT;
43
+ /**
44
+ * Builds a descriptor for a C string, whose optional length sizes the caller-allocated buffer
45
+ * used when the string is passed by reference.
46
+ */
24
47
  string: typeof helpers.stringT;
48
+ /** Builds a descriptor for a `GObject`, wrapped in the class registered for its runtime GType. */
25
49
  object: typeof helpers.objectT;
50
+ /** Builds a descriptor for a `GBoxed` value of the named type. */
26
51
  boxed: typeof helpers.boxedT;
52
+ /** Builds a descriptor for a plain C struct. */
27
53
  struct: typeof helpers.structT;
54
+ /** Builds a descriptor for a fundamental type whose lifetime is managed by named ref and unref functions. */
28
55
  fundamental: typeof helpers.fundamentalT;
56
+ /** Wraps a descriptor in a pointer to it, for an output or inout argument. */
29
57
  ref: typeof helpers.refT;
58
+ /** Builds a descriptor for a `GHashTable`, marshalled as an array of key/value pairs. */
30
59
  hashTable: typeof helpers.hashTableT;
60
+ /** Builds a descriptor for an enumeration, resolving its GType from the named `get_type` function. */
31
61
  enum: typeof helpers.enumT;
62
+ /** Builds a descriptor for a flags type, resolving its GType from the named `get_type` function. */
32
63
  flags: typeof helpers.flagsT;
64
+ /** Builds a descriptor for an array of items in one of the supported container layouts. */
33
65
  array: typeof helpers.arrayT;
66
+ /** Builds a descriptor for a `GList` of items. */
34
67
  list: typeof helpers.listT;
68
+ /** Builds a descriptor for a `GSList` of items. */
35
69
  slist: typeof helpers.slistT;
70
+ /** Builds a descriptor for a `GPtrArray` of items. */
36
71
  ptrArray: typeof helpers.ptrArrayT;
72
+ /** Builds a descriptor for a `GArray` of items, optionally with an explicit element size. */
37
73
  gArray: typeof helpers.gArrayT;
74
+ /** Builds a descriptor for a `GByteArray`. */
38
75
  byteArray: typeof helpers.byteArrayT;
76
+ /** Builds a descriptor for a C array whose length is carried by another argument. */
39
77
  sizedArray: typeof helpers.sizedArrayT;
78
+ /** Builds a descriptor for a C array of a fixed length. */
40
79
  fixedArray: typeof helpers.fixedArrayT;
80
+ /** Builds a descriptor for a function pointer, marshalling a JavaScript function into a native closure. */
41
81
  callback: typeof helpers.callbackT;
82
+ /**
83
+ * Binds a native function, wiring up argument directions, `GError` checking, and packing output
84
+ * arguments into the result.
85
+ */
42
86
  fn: typeof fn;
43
87
  };
44
88
 
package/src/type.ts CHANGED
@@ -19,7 +19,6 @@ type TypedClass = {
19
19
  };
20
20
 
21
21
  type ResolvableKind = "enum" | "flags" | "boxed" | "fundamental" | "array";
22
- /** Descriptor kinds whose GType is resolved from library metadata rather than a fixed fundamental type. */
23
22
  type ResolvableDescriptor = Extract<Descriptor, { kind: ResolvableKind }>;
24
23
 
25
24
  const resolvedTypeCache: Map<string, bigint> = new Map();
package/src/value.ts CHANGED
@@ -209,8 +209,8 @@ const newBoxedValue = (
209
209
  };
210
210
 
211
211
  /**
212
- * Reads the boxed pointer out of a GValue and returns it wrapped in its registered
213
- * class, or null when the value does not hold a boxed type.
212
+ * Duplicates the boxed value held by a GValue and returns the copy wrapped in the
213
+ * class registered for its GType, or null when the GValue holds no boxed type.
214
214
  */
215
215
  function getBoxedValue(value: ExternalObject<Handle>): object | null {
216
216
  const type = getValueType(value);
@@ -325,13 +325,6 @@ const resolveValueGetter = (fundamental: bigint): ValueGetter | undefined =>
325
325
  const resolveValueSetter = (fundamental: bigint): ValueType["set"] | undefined =>
326
326
  PLAIN_VALUE_SETTERS.get(fundamental) ?? WRAPPED_VALUE_SETTERS.get(fundamental);
327
327
 
328
- /**
329
- * Stores a JavaScript value into an already-initialized GValue, converting it to
330
- * whatever type the GValue holds.
331
- *
332
- * @param value The initialized GValue to write into.
333
- * @param jsValue The JavaScript value to store.
334
- */
335
328
  function intoValue(value: ExternalObject<Handle>, jsValue: unknown): void {
336
329
  const type = getValueType(value);
337
330
  const set = resolveValueSetter(typeFundamental(type));