diff options
author | Jarrod Connolly <jarrod@nestedquotes.ca> | 2019-02-03 23:26:33 -0800 |
---|---|---|
committer | Beth Griggs <Bethany.Griggs@uk.ibm.com> | 2019-09-03 16:58:59 +0100 |
commit | 4f41e4f471180e9b86c92e51814b9aa7c5fe00dc (patch) | |
tree | 644389ae84fd587fa7bea021197b54af8c102c02 | |
parent | 55692ba1605dd6a39c85171847fdbe391573989e (diff) | |
download | node-new-4f41e4f471180e9b86c92e51814b9aa7c5fe00dc.tar.gz |
n-api: implement date object
Implements `napi_create_date()` as well as `napi_is_date()` to
allow working with JavaScript Date objects.
Backport-PR-URL: https://github.com/nodejs/node/pull/28298
PR-URL: https://github.com/nodejs/node/pull/25917
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
-rw-r--r-- | doc/api/n-api.md | 73 | ||||
-rw-r--r-- | src/node_api.cc | 45 | ||||
-rw-r--r-- | src/node_api.h | 14 | ||||
-rw-r--r-- | src/node_api_types.h | 1 | ||||
-rw-r--r-- | test/addons-napi/test_date/binding.gyp | 10 | ||||
-rw-r--r-- | test/addons-napi/test_date/test.js | 21 | ||||
-rw-r--r-- | test/addons-napi/test_date/test_date.c | 67 |
7 files changed, 230 insertions, 1 deletions
diff --git a/doc/api/n-api.md b/doc/api/n-api.md index db29ef20e3..c9bed390b1 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -184,6 +184,7 @@ typedef enum { napi_queue_full, napi_closing, napi_bigint_expected, + napi_date_expected, } napi_status; ``` If additional information is required upon an API returning a failed status, @@ -1468,6 +1469,31 @@ This API allocates a `node::Buffer` object and initializes it with data copied from the passed-in buffer. While this is still a fully-supported data structure, in most cases using a `TypedArray` will suffice. +#### napi_create_date +<!-- YAML +added: REPLACEME +napiVersion: 4 +--> + +> Stability: 1 - Experimental + +```C +napi_status napi_create_date(napi_env env, + double time, + napi_value* result); +``` + +- `[in] env`: The environment that the API is invoked under. +- `[in] time`: ECMAScript time value in milliseconds since 01 January, 1970 UTC. +- `[out] result`: A `napi_value` representing a JavaScript `Date`. + +Returns `napi_ok` if the API succeeded. + +This API allocates a JavaScript `Date` object. + +JavaScript `Date` objects are described in +[Section 20.3][] of the ECMAScript Language Specification. + #### napi_create_external <!-- YAML added: v8.0.0 @@ -2088,6 +2114,31 @@ Returns `napi_ok` if the API succeeded. This API returns various properties of a `DataView`. +#### napi_get_date_value +<!-- YAML +added: REPLACEME +napiVersion: 4 +--> + +> Stability: 1 - Experimental + +```C +napi_status napi_get_date_value(napi_env env, + napi_value value, + double* result) +``` + +- `[in] env`: The environment that the API is invoked under. +- `[in] value`: `napi_value` representing a JavaScript `Date`. +- `[out] result`: Time value as a `double` represented as milliseconds +since midnight at the beginning of 01 January, 1970 UTC. + +Returns `napi_ok` if the API succeeded. If a non-date `napi_value` is passed +in it returns `napi_date_expected`. + +This API returns the C double primitive of time value for the given JavaScript +`Date`. + #### napi_get_value_bool <!-- YAML added: v8.0.0 @@ -2672,6 +2723,27 @@ Returns `napi_ok` if the API succeeded. This API checks if the `Object` passed in is a buffer. +### napi_is_date +<!-- YAML +added: REPLACEME +napiVersion: 4 +--> + +> Stability: 1 - Experimental + +```C +napi_status napi_is_date(napi_env env, napi_value value, bool* result) +``` + +- `[in] env`: The environment that the API is invoked under. +- `[in] value`: The JavaScript value to check. +- `[out] result`: Whether the given `napi_value` represents a JavaScript `Date` +object. + +Returns `napi_ok` if the API succeeded. + +This API checks if the `Object` passed in is a date. + ### napi_is_error <!-- YAML added: v8.0.0 @@ -4653,6 +4725,7 @@ This API may only be called from the main thread. [Object Lifetime Management]: #n_api_object_lifetime_management [Object Wrap]: #n_api_object_wrap [Section 12.5.5]: https://tc39.github.io/ecma262/#sec-typeof-operator +[Section 20.3]: https://tc39.github.io/ecma262/#sec-date-objects [Section 22.1]: https://tc39.github.io/ecma262/#sec-array-objects [Section 22.2]: https://tc39.github.io/ecma262/#sec-typedarray-objects [Section 24.1]: https://tc39.github.io/ecma262/#sec-arraybuffer-objects diff --git a/src/node_api.cc b/src/node_api.cc index 0618b3f7bf..e892d1e76b 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -1376,6 +1376,7 @@ const char* error_messages[] = {nullptr, "Thread-safe function queue is full", "Thread-safe function handle is closing", "A bigint was expected", + "A date was expected", }; static inline napi_status napi_clear_last_error(napi_env env) { @@ -1407,7 +1408,7 @@ napi_status napi_get_last_error_info(napi_env env, // We don't have a napi_status_last as this would result in an ABI // change each time a message was added. static_assert( - node::arraysize(error_messages) == napi_bigint_expected + 1, + node::arraysize(error_messages) == napi_date_expected + 1, "Count of error messages must match count of error values"); CHECK_LE(env->last_error.error_code, napi_callback_scope_mismatch); @@ -4085,6 +4086,48 @@ napi_status napi_is_promise(napi_env env, return napi_clear_last_error(env); } +napi_status napi_create_date(napi_env env, + double time, + napi_value* result) { + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); + + v8::MaybeLocal<v8::Value> maybe_date = v8::Date::New(env->context(), time); + CHECK_MAYBE_EMPTY(env, maybe_date, napi_generic_failure); + + *result = v8impl::JsValueFromV8LocalValue(maybe_date.ToLocalChecked()); + + return GET_RETURN_STATUS(env); +} + +napi_status napi_is_date(napi_env env, + napi_value value, + bool* is_date) { + CHECK_ENV(env); + CHECK_ARG(env, value); + CHECK_ARG(env, is_date); + + *is_date = v8impl::V8LocalValueFromJsValue(value)->IsDate(); + + return napi_clear_last_error(env); +} + +napi_status napi_get_date_value(napi_env env, + napi_value value, + double* result) { + NAPI_PREAMBLE(env); + CHECK_ARG(env, value); + CHECK_ARG(env, result); + + v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); + RETURN_STATUS_IF_FALSE(env, val->IsDate(), napi_date_expected); + + v8::Local<v8::Date> date = val.As<v8::Date>(); + *result = date->ValueOf(); + + return GET_RETURN_STATUS(env); +} + napi_status napi_run_script(napi_env env, napi_value script, napi_value* result) { diff --git a/src/node_api.h b/src/node_api.h index 54aa739fa9..f00e66ac15 100644 --- a/src/node_api.h +++ b/src/node_api.h @@ -676,6 +676,20 @@ napi_ref_threadsafe_function(napi_env env, napi_threadsafe_function func); #ifdef NAPI_EXPERIMENTAL +// Dates +NAPI_EXTERN napi_status napi_create_date(napi_env env, + double time, + napi_value* result); + +NAPI_EXTERN napi_status napi_is_date(napi_env env, + napi_value value, + bool* is_date); + +NAPI_EXTERN napi_status napi_get_date_value(napi_env env, + napi_value value, + double* result); + +// BigInt NAPI_EXTERN napi_status napi_create_bigint_int64(napi_env env, int64_t value, napi_value* result); diff --git a/src/node_api_types.h b/src/node_api_types.h index db1d830dff..0aece04aee 100644 --- a/src/node_api_types.h +++ b/src/node_api_types.h @@ -82,6 +82,7 @@ typedef enum { napi_queue_full, napi_closing, napi_bigint_expected, + napi_date_expected, } napi_status; #if NAPI_VERSION >= 4 diff --git a/test/addons-napi/test_date/binding.gyp b/test/addons-napi/test_date/binding.gyp new file mode 100644 index 0000000000..6039d122c7 --- /dev/null +++ b/test/addons-napi/test_date/binding.gyp @@ -0,0 +1,10 @@ +{ + "targets": [ + { + "target_name": "test_date", + "sources": [ + "test_date.c" + ] + } + ] +} diff --git a/test/addons-napi/test_date/test.js b/test/addons-napi/test_date/test.js new file mode 100644 index 0000000000..e504208520 --- /dev/null +++ b/test/addons-napi/test_date/test.js @@ -0,0 +1,21 @@ +'use strict'; + +const common = require('../../common'); + +// This tests the date-related n-api calls + +const assert = require('assert'); +const test_date = require(`./build/${common.buildType}/test_date`); + +const dateTypeTestDate = test_date.createDate(1549183351); +assert.strictEqual(test_date.isDate(dateTypeTestDate), true); + +assert.strictEqual(test_date.isDate(new Date(1549183351)), true); + +assert.strictEqual(test_date.isDate(2.4), false); +assert.strictEqual(test_date.isDate('not a date'), false); +assert.strictEqual(test_date.isDate(undefined), false); +assert.strictEqual(test_date.isDate(null), false); +assert.strictEqual(test_date.isDate({}), false); + +assert.strictEqual(test_date.getDateValue(new Date(1549183351)), 1549183351); diff --git a/test/addons-napi/test_date/test_date.c b/test/addons-napi/test_date/test_date.c new file mode 100644 index 0000000000..8cc1c23aff --- /dev/null +++ b/test/addons-napi/test_date/test_date.c @@ -0,0 +1,67 @@ +#define NAPI_EXPERIMENTAL + +#include <node_api.h> +#include "../common.h" + +static napi_value createDate(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NAPI_ASSERT(env, argc >= 1, "Wrong number of arguments"); + + napi_valuetype valuetype0; + NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0)); + + NAPI_ASSERT(env, valuetype0 == napi_number, + "Wrong type of arguments. Expects a number as first argument."); + + double time; + NAPI_CALL(env, napi_get_value_double(env, args[0], &time)); + + napi_value date; + NAPI_CALL(env, napi_create_date(env, time, &date)); + + return date; +} + +static napi_value isDate(napi_env env, napi_callback_info info) { + napi_value date, result; + size_t argc = 1; + bool is_date; + + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &date, NULL, NULL)); + NAPI_CALL(env, napi_is_date(env, date, &is_date)); + NAPI_CALL(env, napi_get_boolean(env, is_date, &result)); + + return result; +} + +static napi_value getDateValue(napi_env env, napi_callback_info info) { + napi_value date, result; + size_t argc = 1; + double value; + + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &date, NULL, NULL)); + NAPI_CALL(env, napi_get_date_value(env, date, &value)); + NAPI_CALL(env, napi_create_double(env, value, &result)); + + return result; +} + +EXTERN_C_START +napi_value Init(napi_env env, napi_value exports) { + napi_property_descriptor descriptors[] = { + DECLARE_NAPI_PROPERTY("createDate", createDate), + DECLARE_NAPI_PROPERTY("isDate", isDate), + DECLARE_NAPI_PROPERTY("getDateValue", getDateValue), + }; + + NAPI_CALL(env, napi_define_properties( + env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors)); + + return exports; +} +EXTERN_C_END + +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) |