diff --git a/napi-inl.h b/napi-inl.h index f34ed7ad7..b71f834fb 100644 --- a/napi-inl.h +++ b/napi-inl.h @@ -371,6 +371,10 @@ inline bool Value::IsBuffer() const { return result; } +inline bool Value::IsExternal() const { + return Type() == napi_external; +} + template inline T Value::As() const { return T(_env, _value); diff --git a/napi.h b/napi.h index 3ec1fbfe2..9e39b7346 100644 --- a/napi.h +++ b/napi.h @@ -181,6 +181,7 @@ namespace Napi { bool IsDataView() const; ///< Tests if a value is a JavaScript data view. #endif bool IsBuffer() const; ///< Tests if a value is a Node buffer. + bool IsExternal() const; ///< Tests if a value is a pointer to external data. /// Casts to another type of `Napi::Value`, when the actual type is known or assumed. /// diff --git a/test/basic_types/value.cc b/test/basic_types/value.cc index 48cd46887..d18f8f30f 100644 --- a/test/basic_types/value.cc +++ b/test/basic_types/value.cc @@ -2,6 +2,17 @@ using namespace Napi; +namespace { + +int testData = 1; + +// Helpers for testing non-Javascript values. +Value CreateExternal(const CallbackInfo& info) { + return External::New(info.Env(), &testData); +} + +} // end anonymous namespace + static Value IsEmpty(const CallbackInfo& info) { Value value; return Boolean::New(info.Env(), value.IsEmpty()); @@ -59,6 +70,10 @@ static Value IsDataView(const CallbackInfo& info) { return Boolean::New(info.Env(), info[0].IsDataView()); } +static Value IsExternal(const CallbackInfo& info) { + return Boolean::New(info.Env(), info[0].IsExternal()); +} + static Value ToBoolean(const CallbackInfo& info) { return info[0].ToBoolean(); } @@ -92,10 +107,13 @@ Object InitBasicTypesValue(Env env) { exports["isFunction"] = Function::New(env, IsFunction); exports["isPromise"] = Function::New(env, IsPromise); exports["isDataView"] = Function::New(env, IsDataView); + exports["isExternal"] = Function::New(env, IsExternal); exports["toBoolean"] = Function::New(env, ToBoolean); exports["toNumber"] = Function::New(env, ToNumber); exports["toString"] = Function::New(env, ToString); exports["toObject"] = Function::New(env, ToObject); + exports["createExternal"] = Function::New(env, CreateExternal); + return exports; } diff --git a/test/basic_types/value.js b/test/basic_types/value.js index 0d67e7522..1cf0c023f 100644 --- a/test/basic_types/value.js +++ b/test/basic_types/value.js @@ -7,8 +7,11 @@ test(require(`../build/${buildType}/binding.node`)); test(require(`../build/${buildType}/binding_noexcept.node`)); function test(binding) { + const externalValue = binding.basic_types_value.createExternal(); + function isObject(value) { - return typeof value === 'object' || typeof value === 'function'; + return (typeof value === 'object' && value !== externalValue) || + (typeof value === 'function'); } function detailedTypeOf(value) { @@ -22,6 +25,9 @@ function test(binding) { if (Array.isArray(value)) return 'array'; + if (value === externalValue) + return 'external'; + if (!value.constructor) return type; @@ -56,7 +62,8 @@ function test(binding) { {}, function() {}, new Promise((resolve, reject) => {}), - new DataView(new ArrayBuffer(12)) + new DataView(new ArrayBuffer(12)), + externalValue ]; testValueList.forEach((testValue) => { @@ -110,6 +117,7 @@ function test(binding) { typeCheckerTest(value.isFunction, 'function'); typeCheckerTest(value.isPromise, 'promise'); typeCheckerTest(value.isDataView, 'dataview'); + typeCheckerTest(value.isExternal, 'external'); typeConverterTest(value.toBoolean, Boolean); assert.strictEqual(value.toBoolean(undefined), false);