I am in the process of updating a NodeJS package, due to a breakage in NodeJS 14. This library makes use of C++ code. In NodeJS 12 the same code appears as a deprecation warning:
warning: ‘v8::Local<v8::Value> v8::Object::Get(v8::Local<v8::Value>)’ is deprecated: Use maybe version
With the code in question being:
v8::Local<v8::Object> options = v8::Local<v8::Object>::Cast(info[0]);
v8::Local<v8::Value> debug = options->Get(Nan::New<v8::String>("debug").ToLocalChecked());
if (true) {
v8::Local<v8::Value> leds = options->Get(Nan::New<v8::String>("leds").ToLocalChecked());
if (!leds->IsUndefined())
ws2811.channel[0].count = Nan::To<int>(leds).FromMaybe(ws2811.channel[0].count);
else
return Nan::ThrowTypeError("configure(): leds must be defined");
}
I did try the following and while it does compile, runtime suggests this may be wrong, since I get failure which didn't exist before this code change:
v8::Local<v8::Object> options = v8::Local<v8::Object>::Cast(info[0]);
Nan::MaybeLocal<v8::Value> debug = Nan::Get(options, Nan::New<v8::String>("debug").ToLocalChecked());
if (true) {
Nan::MaybeLocal<v8::Value> maybe_leds = Nan::Get(options, Nan::New<v8::String>("leds").ToLocalChecked());
v8::Local<v8::Value> leds;
if (!maybe_leds.IsEmpty() && maybe_leds.ToLocal(&leds))
ws2811.channel[0].count = Nan::To<int>(leds).FromMaybe(ws2811.channel[0].count);
else
return Nan::ThrowTypeError("configure(): leds must be defined");
}
Being pretty rusty with C++ and new to V8, I am a little confused as to what the right replacement for the Get
method is, in this context. What I do think I understand is that we need to use MaybeLocal
instead of Local
. Doing a search turns up a lot of other people with similar issues, but nothing that I can use as a solution.
BTW this project does depend on nan.
The key insight is that most operations that involve JavaScript can throw an exception instead of returning a value. The MaybeLocal
convention makes this explicit: a MaybeLocal
is either a Local (if the function/operation returned a value), or empty (if there was an exception). If you have a v8::TryCatch
or Nan::TryCatch
, it will have caught the exception in the latter case.
There are several ways for embedding code to deal with MaybeLocals; the most elegant is the bool
-returning .ToLocal(...)
method. It is equivalent to checking .IsEmpty()
, so you don't need to do both.
So that would give you:
Nan::TryCatch try_catch;
v8::Local<v8::String> leds_string = Nan::New<v8::String>("leds").ToLocalChecked();
Nan::MaybeLocal<v8::Value> maybe_leds = Nan::Get(options, leds_string);
v8::Local<v8::Value> leds;
if (!maybe_leds.ToLocal(&leds)) {
// An exception was thrown while reading `options["leds"]`.
// This is the same as `maybe_leds.IsEmpty() == true`.
// It is also the same as `try_catch.HasCaught() == true`.
return try_catch.ReThrow();
}
// Now follows your original code.
if (leds->IsUndefined()) {
// The `options` object didn't have a `leds` property, or it was undefined.
return Nan::ThrowTypeError("configure(): leds must be defined");
}
// Success case: all good.
ws2811.channel[0].count = Nan::To<int>(leds).FromMaybe(ws2811.channel[0].count);
See documentation at https://github.com/nodejs/nan/blob/master/doc/maybe_types.md.