@gjsify/node-gi 0.59.0 → 0.60.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/marshal.cc CHANGED
@@ -605,6 +605,40 @@ bool JsToGIArgument(Napi::Env env, Napi::Value v, GITypeInfo* type, GIArgument*
605
605
  out->v_string = const_cast<char*>(heldString->c_str());
606
606
  }
607
607
  return true;
608
+ case GI_TYPE_TAG_VOID:
609
+ // A bare `gpointer` IN argument: the `user_data` of the log handlers
610
+ // (`GLib.log_default_handler(domain, level, message, null)`), of
611
+ // `g_log_writer_default`, and of every introspected function that takes a
612
+ // closure's data separately. There is nothing to marshal INTO a void* from
613
+ // JS, so gjs installs Arg::NullIn for this tag (refs/gjs/gi/arg-cache.cpp
614
+ // ArgsCache::build_normal_in_arg) — it writes NULL and ignores the value
615
+ // entirely. Without this arm the whole CALL failed with "Unsupported IN
616
+ // argument type tag 0", which is how `GLib.log_default_handler` — the only
617
+ // introspectable way to make GLib write to fd 1/2, and so the only way to
618
+ // SEE the Android stdout/stderr redirect from JS — was unreachable.
619
+ //
620
+ // Deliberate divergence: a value that is not null/undefined is REFUSED here
621
+ // where gjs drops it silently. node-gi cannot turn a JS value into a
622
+ // gpointer, and a caller that passes one meant it to arrive; swallowing it
623
+ // hides the mistake at the only place that can still name the argument.
624
+ // (The nullability of the arg is not known at this level — JsToGIArgument
625
+ // sees the GITypeInfo, not the GIArgInfo — so a non-nullable void* gets
626
+ // NULL instead of gjs's "argument may not be null". In the introspected API
627
+ // such an argument is `allow-none` throughout.)
628
+ if (!gi_type_info_is_pointer(type)) return true; // plain `void`: no slot to fill
629
+ if (v.IsNull() || v.IsUndefined()) {
630
+ out->v_pointer = nullptr;
631
+ return true;
632
+ }
633
+ {
634
+ std::string msg = std::string("Expected null for pointer ") +
635
+ (argName != nullptr ? std::string("argument '") + argName + "'"
636
+ : std::string("argument")) +
637
+ " but got type " + InformalValueTypeName(v) +
638
+ " (node-gi cannot marshal a JS value into a gpointer)";
639
+ Napi::TypeError::New(env, msg).ThrowAsJavaScriptException();
640
+ }
641
+ return false;
608
642
  case GI_TYPE_TAG_INTERFACE: {
609
643
  // Object/interface instances arrive as opaque External<GObject> handles;
610
644
  // enums/flags as plain numbers. Other interface kinds (structs/unions/
package/src/signals.cc CHANGED
@@ -270,6 +270,19 @@ Napi::Value EmitSignal(const Napi::CallbackInfo& info) {
270
270
  g_signal_query(sigid, &query);
271
271
 
272
272
  guint n = query.n_params;
273
+ // ARITY, gjs's message verbatim ("Signal 'changed' on ArSig requires 2 args got 1",
274
+ // measured on gjs 1.88.1 — which rejects too MANY as well as too few). Without it a
275
+ // missing argument was marshalled from `undefined`: a signal declared (string, int)
276
+ // and emitted with one argument reached its handlers with a silent "" / 0 in the
277
+ // gap, so the caller's mistake surfaced as wrong data somewhere downstream instead
278
+ // of as a throw at the emit.
279
+ if (args.Length() != n) {
280
+ Napi::Error::New(env, std::string("Signal '") + name + "' on " + G_OBJECT_TYPE_NAME(obj) +
281
+ " requires " + std::to_string(n) + " args got " +
282
+ std::to_string(args.Length()))
283
+ .ThrowAsJavaScriptException();
284
+ return env.Null();
285
+ }
273
286
  std::vector<GValue> params(n + 1); // [0] = instance
274
287
  g_value_init(&params[0], gtype);
275
288
  g_value_set_object(&params[0], obj);
@@ -279,7 +292,7 @@ Napi::Value EmitSignal(const Napi::CallbackInfo& info) {
279
292
  GType pt = query.param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE;
280
293
  g_value_init(&params[i + 1], pt);
281
294
  initialised = i + 2;
282
- Napi::Value v = i < args.Length() ? args.Get(i) : env.Undefined();
295
+ Napi::Value v = args.Get(i);
283
296
  // An EMPTY v is the residue of a swallowed args.Get() failure (terminating
284
297
  // env / throwing getter): JsToGValue's coercions on it would abort via
285
298
  // Error::New(nullptr)'s fatal sites — bail before marshalling.