Skip to content

Commit 4f41e4f

Browse files
jarrodconnollyBethGriggs
authored andcommittedSep 3, 2019
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: #28298 PR-URL: #25917 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Michael Dawson <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 55692ba commit 4f41e4f

File tree

7 files changed

+230
-1
lines changed

7 files changed

+230
-1
lines changed
 

‎doc/api/n-api.md

+73
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ typedef enum {
184184
napi_queue_full,
185185
napi_closing,
186186
napi_bigint_expected,
187+
napi_date_expected,
187188
} napi_status;
188189
```
189190
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
14681469
from the passed-in buffer. While this is still a fully-supported data
14691470
structure, in most cases using a `TypedArray` will suffice.
14701471

1472+
#### napi_create_date
1473+
<!-- YAML
1474+
added: REPLACEME
1475+
napiVersion: 4
1476+
-->
1477+
1478+
> Stability: 1 - Experimental
1479+
1480+
```C
1481+
napi_status napi_create_date(napi_env env,
1482+
double time,
1483+
napi_value* result);
1484+
```
1485+
1486+
- `[in] env`: The environment that the API is invoked under.
1487+
- `[in] time`: ECMAScript time value in milliseconds since 01 January, 1970 UTC.
1488+
- `[out] result`: A `napi_value` representing a JavaScript `Date`.
1489+
1490+
Returns `napi_ok` if the API succeeded.
1491+
1492+
This API allocates a JavaScript `Date` object.
1493+
1494+
JavaScript `Date` objects are described in
1495+
[Section 20.3][] of the ECMAScript Language Specification.
1496+
14711497
#### napi_create_external
14721498
<!-- YAML
14731499
added: v8.0.0
@@ -2088,6 +2114,31 @@ Returns `napi_ok` if the API succeeded.
20882114

20892115
This API returns various properties of a `DataView`.
20902116

2117+
#### napi_get_date_value
2118+
<!-- YAML
2119+
added: REPLACEME
2120+
napiVersion: 4
2121+
-->
2122+
2123+
> Stability: 1 - Experimental
2124+
2125+
```C
2126+
napi_status napi_get_date_value(napi_env env,
2127+
napi_value value,
2128+
double* result)
2129+
```
2130+
2131+
- `[in] env`: The environment that the API is invoked under.
2132+
- `[in] value`: `napi_value` representing a JavaScript `Date`.
2133+
- `[out] result`: Time value as a `double` represented as milliseconds
2134+
since midnight at the beginning of 01 January, 1970 UTC.
2135+
2136+
Returns `napi_ok` if the API succeeded. If a non-date `napi_value` is passed
2137+
in it returns `napi_date_expected`.
2138+
2139+
This API returns the C double primitive of time value for the given JavaScript
2140+
`Date`.
2141+
20912142
#### napi_get_value_bool
20922143
<!-- YAML
20932144
added: v8.0.0
@@ -2672,6 +2723,27 @@ Returns `napi_ok` if the API succeeded.
26722723

26732724
This API checks if the `Object` passed in is a buffer.
26742725

2726+
### napi_is_date
2727+
<!-- YAML
2728+
added: REPLACEME
2729+
napiVersion: 4
2730+
-->
2731+
2732+
> Stability: 1 - Experimental
2733+
2734+
```C
2735+
napi_status napi_is_date(napi_env env, napi_value value, bool* result)
2736+
```
2737+
2738+
- `[in] env`: The environment that the API is invoked under.
2739+
- `[in] value`: The JavaScript value to check.
2740+
- `[out] result`: Whether the given `napi_value` represents a JavaScript `Date`
2741+
object.
2742+
2743+
Returns `napi_ok` if the API succeeded.
2744+
2745+
This API checks if the `Object` passed in is a date.
2746+
26752747
### napi_is_error
26762748
<!-- YAML
26772749
added: v8.0.0
@@ -4653,6 +4725,7 @@ This API may only be called from the main thread.
46534725
[Object Lifetime Management]: #n_api_object_lifetime_management
46544726
[Object Wrap]: #n_api_object_wrap
46554727
[Section 12.5.5]: https://tc39.github.io/ecma262/#sec-typeof-operator
4728+
[Section 20.3]: https://tc39.github.io/ecma262/#sec-date-objects
46564729
[Section 22.1]: https://tc39.github.io/ecma262/#sec-array-objects
46574730
[Section 22.2]: https://tc39.github.io/ecma262/#sec-typedarray-objects
46584731
[Section 24.1]: https://tc39.github.io/ecma262/#sec-arraybuffer-objects

‎src/node_api.cc

+44-1
Original file line numberDiff line numberDiff line change
@@ -1376,6 +1376,7 @@ const char* error_messages[] = {nullptr,
13761376
"Thread-safe function queue is full",
13771377
"Thread-safe function handle is closing",
13781378
"A bigint was expected",
1379+
"A date was expected",
13791380
};
13801381

13811382
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,
14071408
// We don't have a napi_status_last as this would result in an ABI
14081409
// change each time a message was added.
14091410
static_assert(
1410-
node::arraysize(error_messages) == napi_bigint_expected + 1,
1411+
node::arraysize(error_messages) == napi_date_expected + 1,
14111412
"Count of error messages must match count of error values");
14121413
CHECK_LE(env->last_error.error_code, napi_callback_scope_mismatch);
14131414

@@ -4085,6 +4086,48 @@ napi_status napi_is_promise(napi_env env,
40854086
return napi_clear_last_error(env);
40864087
}
40874088

4089+
napi_status napi_create_date(napi_env env,
4090+
double time,
4091+
napi_value* result) {
4092+
NAPI_PREAMBLE(env);
4093+
CHECK_ARG(env, result);
4094+
4095+
v8::MaybeLocal<v8::Value> maybe_date = v8::Date::New(env->context(), time);
4096+
CHECK_MAYBE_EMPTY(env, maybe_date, napi_generic_failure);
4097+
4098+
*result = v8impl::JsValueFromV8LocalValue(maybe_date.ToLocalChecked());
4099+
4100+
return GET_RETURN_STATUS(env);
4101+
}
4102+
4103+
napi_status napi_is_date(napi_env env,
4104+
napi_value value,
4105+
bool* is_date) {
4106+
CHECK_ENV(env);
4107+
CHECK_ARG(env, value);
4108+
CHECK_ARG(env, is_date);
4109+
4110+
*is_date = v8impl::V8LocalValueFromJsValue(value)->IsDate();
4111+
4112+
return napi_clear_last_error(env);
4113+
}
4114+
4115+
napi_status napi_get_date_value(napi_env env,
4116+
napi_value value,
4117+
double* result) {
4118+
NAPI_PREAMBLE(env);
4119+
CHECK_ARG(env, value);
4120+
CHECK_ARG(env, result);
4121+
4122+
v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
4123+
RETURN_STATUS_IF_FALSE(env, val->IsDate(), napi_date_expected);
4124+
4125+
v8::Local<v8::Date> date = val.As<v8::Date>();
4126+
*result = date->ValueOf();
4127+
4128+
return GET_RETURN_STATUS(env);
4129+
}
4130+
40884131
napi_status napi_run_script(napi_env env,
40894132
napi_value script,
40904133
napi_value* result) {

‎src/node_api.h

+14
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,20 @@ napi_ref_threadsafe_function(napi_env env, napi_threadsafe_function func);
676676

677677
#ifdef NAPI_EXPERIMENTAL
678678

679+
// Dates
680+
NAPI_EXTERN napi_status napi_create_date(napi_env env,
681+
double time,
682+
napi_value* result);
683+
684+
NAPI_EXTERN napi_status napi_is_date(napi_env env,
685+
napi_value value,
686+
bool* is_date);
687+
688+
NAPI_EXTERN napi_status napi_get_date_value(napi_env env,
689+
napi_value value,
690+
double* result);
691+
692+
// BigInt
679693
NAPI_EXTERN napi_status napi_create_bigint_int64(napi_env env,
680694
int64_t value,
681695
napi_value* result);

‎src/node_api_types.h

+1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ typedef enum {
8282
napi_queue_full,
8383
napi_closing,
8484
napi_bigint_expected,
85+
napi_date_expected,
8586
} napi_status;
8687

8788
#if NAPI_VERSION >= 4
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"targets": [
3+
{
4+
"target_name": "test_date",
5+
"sources": [
6+
"test_date.c"
7+
]
8+
}
9+
]
10+
}

‎test/addons-napi/test_date/test.js

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
'use strict';
2+
3+
const common = require('../../common');
4+
5+
// This tests the date-related n-api calls
6+
7+
const assert = require('assert');
8+
const test_date = require(`./build/${common.buildType}/test_date`);
9+
10+
const dateTypeTestDate = test_date.createDate(1549183351);
11+
assert.strictEqual(test_date.isDate(dateTypeTestDate), true);
12+
13+
assert.strictEqual(test_date.isDate(new Date(1549183351)), true);
14+
15+
assert.strictEqual(test_date.isDate(2.4), false);
16+
assert.strictEqual(test_date.isDate('not a date'), false);
17+
assert.strictEqual(test_date.isDate(undefined), false);
18+
assert.strictEqual(test_date.isDate(null), false);
19+
assert.strictEqual(test_date.isDate({}), false);
20+
21+
assert.strictEqual(test_date.getDateValue(new Date(1549183351)), 1549183351);
+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#define NAPI_EXPERIMENTAL
2+
3+
#include <node_api.h>
4+
#include "../common.h"
5+
6+
static napi_value createDate(napi_env env, napi_callback_info info) {
7+
size_t argc = 1;
8+
napi_value args[1];
9+
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
10+
11+
NAPI_ASSERT(env, argc >= 1, "Wrong number of arguments");
12+
13+
napi_valuetype valuetype0;
14+
NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0));
15+
16+
NAPI_ASSERT(env, valuetype0 == napi_number,
17+
"Wrong type of arguments. Expects a number as first argument.");
18+
19+
double time;
20+
NAPI_CALL(env, napi_get_value_double(env, args[0], &time));
21+
22+
napi_value date;
23+
NAPI_CALL(env, napi_create_date(env, time, &date));
24+
25+
return date;
26+
}
27+
28+
static napi_value isDate(napi_env env, napi_callback_info info) {
29+
napi_value date, result;
30+
size_t argc = 1;
31+
bool is_date;
32+
33+
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &date, NULL, NULL));
34+
NAPI_CALL(env, napi_is_date(env, date, &is_date));
35+
NAPI_CALL(env, napi_get_boolean(env, is_date, &result));
36+
37+
return result;
38+
}
39+
40+
static napi_value getDateValue(napi_env env, napi_callback_info info) {
41+
napi_value date, result;
42+
size_t argc = 1;
43+
double value;
44+
45+
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &date, NULL, NULL));
46+
NAPI_CALL(env, napi_get_date_value(env, date, &value));
47+
NAPI_CALL(env, napi_create_double(env, value, &result));
48+
49+
return result;
50+
}
51+
52+
EXTERN_C_START
53+
napi_value Init(napi_env env, napi_value exports) {
54+
napi_property_descriptor descriptors[] = {
55+
DECLARE_NAPI_PROPERTY("createDate", createDate),
56+
DECLARE_NAPI_PROPERTY("isDate", isDate),
57+
DECLARE_NAPI_PROPERTY("getDateValue", getDateValue),
58+
};
59+
60+
NAPI_CALL(env, napi_define_properties(
61+
env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors));
62+
63+
return exports;
64+
}
65+
EXTERN_C_END
66+
67+
NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)

0 commit comments

Comments
 (0)
Please sign in to comment.