util: introduce util.types.is[…] type checks

Provide public APIs for native typechecking that is actually useful.
The motivation for this is providing alternatives to userland
modules that would currently rely on `process.binding('util')`.

PR-URL: https://github.com/nodejs/node/pull/18415
Reviewed-By: Evan Lucas <evanlucas@me.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Сковорода Никита Андреевич <chalkerx@gmail.com>
This commit is contained in:
Anna Henningsen 2018-01-27 22:01:32 +01:00
parent bd6e0be0df
commit b20af8088a
No known key found for this signature in database
GPG Key ID: 9C63F3A6CD2AD8F9
15 changed files with 919 additions and 125 deletions

View File

@ -932,6 +932,14 @@ Using the `noAssert` argument has no functionality anymore. All input is going
to be verified, no matter if it is set to true or not. Skipping the verification
could lead to hard to find errors and crashes.
<a id="DEP0XXX"></a>
### DEP0XXX: process.binding('util').is[...] typechecks
Type: Documentation-only (supports [`--pending-deprecation`][])
Using `process.binding()` in general should be avoided. The type checking
methods in particular can be replaced by using [`util.types`][].
[`--pending-deprecation`]: cli.html#cli_pending_deprecation
[`Buffer.allocUnsafeSlow(size)`]: buffer.html#buffer_class_method_buffer_allocunsafeslow_size
[`Buffer.from(array)`]: buffer.html#buffer_class_method_buffer_from_array
@ -1000,6 +1008,7 @@ could lead to hard to find errors and crashes.
[`util.log()`]: util.html#util_util_log_string
[`util.print()`]: util.html#util_util_print_strings
[`util.puts()`]: util.html#util_util_puts_strings
[`util.types`]: util.html#util_util_types
[`util`]: util.html
[`worker.exitedAfterDisconnect`]: cluster.html#cluster_worker_exitedafterdisconnect
[alloc]: buffer.html#buffer_class_method_buffer_alloc_size_fill_encoding

View File

@ -891,6 +891,555 @@ encoded bytes.
The encoding supported by the `TextEncoder` instance. Always set to `'utf-8'`.
## util.types
<!-- YAML
added: REPLACEME
-->
`util.types` provides a number of type checks for different kinds of built-in
objects. Unlike `instanceof` or `Object.prototype.toString.call(value)`,
these checks do not inspect properties of the object that are accessible from
JavaScript (like their prototype), and usually have the overhead of
calling into C++.
The result generally does not make any guarantees about what kinds of
properties or behavior a value exposes in JavaScript. They are primarily
useful for addon developers who prefer to do type checking in JavaScript.
### util.types.isAnyArrayBuffer(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a built-in [`ArrayBuffer`][] or
[`SharedArrayBuffer`][] instance.
See also [`util.types.isArrayBuffer()`][] and
[`util.types.isSharedArrayBuffer()`][].
For example:
```js
util.types.isAnyArrayBuffer(new ArrayBuffer()); // Returns true
util.types.isAnyArrayBuffer(new SharedArrayBuffer()); // Returns true
```
### util.types.isArgumentsObject(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is an `arguments` object.
For example:
<!-- eslint-disable prefer-rest-params -->
```js
function foo() {
util.types.isArgumentsObject(arguments); // Returns true
}
```
### util.types.isArrayBuffer(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a built-in [`ArrayBuffer`][] instance.
This does *not* include [`SharedArrayBuffer`][] instances. Usually, it is
desirable to test for both; See [`util.types.isAnyArrayBuffer()`][] for that.
For example:
```js
util.types.isArrayBuffer(new ArrayBuffer()); // Returns true
util.types.isArrayBuffer(new SharedArrayBuffer()); // Returns false
```
### util.types.isAsyncFunction(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is an [async function][].
Note that this only reports back what the JavaScript engine is seeing;
in particular, the return value may not match the original source code if
a transpilation tool was used.
For example:
```js
util.types.isAsyncFunction(function foo() {}); // Returns false
util.types.isAsyncFunction(async function foo() {}); // Returns true
```
### util.types.isBooleanObject(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a boolean object, e.g. created
by `new Boolean()`.
For example:
```js
util.types.isBooleanObject(false); // Returns false
util.types.isBooleanObject(true); // Returns false
util.types.isBooleanObject(new Boolean(false)); // Returns true
util.types.isBooleanObject(new Boolean(true)); // Returns true
util.types.isBooleanObject(Boolean(false)); // Returns false
util.types.isBooleanObject(Boolean(true)); // Returns false
```
### util.types.isDataView(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a built-in [`DataView`][] instance.
For example:
```js
const ab = new ArrayBuffer(20);
util.types.isDataView(new DataView(ab)); // Returns true
util.types.isDataView(new Float64Array()); // Returns false
```
See also [`ArrayBuffer.isView()`][].
### util.types.isDate(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a built-in [`Date`][] instance.
For example:
```js
util.types.isDate(new Date()); // Returns true
```
### util.types.isExternal(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a native `External` value.
### util.types.isFloat32Array(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a built-in [`Float32Array`][] instance.
For example:
```js
util.types.isFloat32Array(new ArrayBuffer()); // Returns false
util.types.isFloat32Array(new Float32Array()); // Returns true
util.types.isFloat32Array(new Float64Array()); // Returns false
```
### util.types.isFloat64Array(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a built-in [`Float64Array`][] instance.
For example:
```js
util.types.isFloat64Array(new ArrayBuffer()); // Returns false
util.types.isFloat64Array(new Uint8Array()); // Returns false
util.types.isFloat64Array(new Float64Array()); // Returns true
```
### util.types.isGeneratorFunction(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a generator function.
Note that this only reports back what the JavaScript engine is seeing;
in particular, the return value may not match the original source code if
a transpilation tool was used.
For example:
```js
util.types.isGeneratorFunction(function foo() {}); // Returns false
util.types.isGeneratorFunction(function* foo() {}); // Returns true
```
### util.types.isGeneratorObject(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a generator object as returned from a
built-in generator function.
Note that this only reports back what the JavaScript engine is seeing;
in particular, the return value may not match the original source code if
a transpilation tool was used.
For example:
```js
function* foo() {}
const generator = foo();
util.types.isGeneratorObject(generator); // Returns true
```
### util.types.isInt8Array(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a built-in [`Int8Array`][] instance.
For example:
```js
util.types.isInt8Array(new ArrayBuffer()); // Returns false
util.types.isInt8Array(new Int8Array()); // Returns true
util.types.isInt8Array(new Float64Array()); // Returns false
```
### util.types.isInt16Array(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a built-in [`Int16Array`][] instance.
For example:
```js
util.types.isInt16Array(new ArrayBuffer()); // Returns false
util.types.isInt16Array(new Int16Array()); // Returns true
util.types.isInt16Array(new Float64Array()); // Returns false
```
### util.types.isInt32Array(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a built-in [`Int32Array`][] instance.
For example:
```js
util.types.isInt32Array(new ArrayBuffer()); // Returns false
util.types.isInt32Array(new Int32Array()); // Returns true
util.types.isInt32Array(new Float64Array()); // Returns false
```
### util.types.isMap(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a built-in [`Map`][] instance.
For example:
```js
util.types.isMap(new Map()); // Returns true
```
### util.types.isMapIterator(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is an iterator returned for a built-in
[`Map`][] instance.
For example:
```js
const map = new Map();
util.types.isMapIterator(map.keys()); // Returns true
util.types.isMapIterator(map.values()); // Returns true
util.types.isMapIterator(map.entries()); // Returns true
util.types.isMapIterator(map[Symbol.iterator]()); // Returns true
```
### util.types.isNativeError(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is an instance of a built-in [`Error`][] type.
For example:
```js
util.types.isNativeError(new Error()); // Returns true
util.types.isNativeError(new TypeError()); // Returns true
util.types.isNativeError(new RangeError()); // Returns true
```
### util.types.isNumberObject(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a number object, e.g. created
by `new Number()`.
For example:
```js
util.types.isNumberObject(0); // Returns false
util.types.isNumberObject(new Number(0)); // Returns true
```
### util.types.isPromise(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a built-in [`Promise`][].
For example:
```js
util.types.isPromise(Promise.resolve(42)); // Returns true
```
### util.types.isProxy(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a [`Proxy`][] instance.
For example:
```js
const target = {};
const proxy = new Proxy(target, {});
util.types.isProxy(target); // Returns false
util.types.isProxy(proxy); // Returns true
```
### util.types.isRegExp(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a regular expression object.
For example:
```js
util.types.isRegExp(/abc/); // Returns true
util.types.isRegExp(new RegExp('abc')); // Returns true
```
### util.types.isSet(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a built-in [`Set`][] instance.
For example:
```js
util.types.isSet(new Set()); // Returns true
```
### util.types.isSetIterator(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is an iterator returned for a built-in
[`Set`][] instance.
For example:
```js
const set = new Set();
util.types.isSetIterator(set.keys()); // Returns true
util.types.isSetIterator(set.values()); // Returns true
util.types.isSetIterator(set.entries()); // Returns true
util.types.isSetIterator(set[Symbol.iterator]()); // Returns true
```
### util.types.isSharedArrayBuffer(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a built-in [`SharedArrayBuffer`][] instance.
This does *not* include [`ArrayBuffer`][] instances. Usually, it is
desirable to test for both; See [`util.types.isAnyArrayBuffer()`][] for that.
For example:
```js
util.types.isSharedArrayBuffer(new ArrayBuffer()); // Returns false
util.types.isSharedArrayBuffer(new SharedArrayBuffer()); // Returns true
```
### util.types.isStringObject(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a string object, e.g. created
by `new String()`.
For example:
```js
util.types.isStringObject('foo'); // Returns false
util.types.isStringObject(new String('foo')); // Returns true
```
### util.types.isSymbolObject(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a symbol object, created
by calling `Object()` on a `Symbol` primitive.
For example:
```js
const symbol = Symbol('foo');
util.types.isSymbolObject(symbol); // Returns false
util.types.isSymbolObject(Object(symbol)); // Returns true
```
### util.types.isTypedArray(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a built-in [`TypedArray`][] instance.
For example:
```js
util.types.isTypedArray(new ArrayBuffer()); // Returns false
util.types.isTypedArray(new Uint8Array()); // Returns true
util.types.isTypedArray(new Float64Array()); // Returns true
```
See also [`ArrayBuffer.isView()`][].
### util.types.isUint8Array(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a built-in [`Uint8Array`][] instance.
For example:
```js
util.types.isUint8Array(new ArrayBuffer()); // Returns false
util.types.isUint8Array(new Uint8Array()); // Returns true
util.types.isUint8Array(new Float64Array()); // Returns false
```
### util.types.isUint8ClampedArray(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a built-in [`Uint8ClampedArray`][] instance.
For example:
```js
util.types.isUint8ClampedArray(new ArrayBuffer()); // Returns false
util.types.isUint8ClampedArray(new Uint8ClampedArray()); // Returns true
util.types.isUint8ClampedArray(new Float64Array()); // Returns false
```
### util.types.isUint16Array(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a built-in [`Uint16Array`][] instance.
For example:
```js
util.types.isUint16Array(new ArrayBuffer()); // Returns false
util.types.isUint16Array(new Uint16Array()); // Returns true
util.types.isUint16Array(new Float64Array()); // Returns false
```
### util.types.isUint32Array(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a built-in [`Uint32Array`][] instance.
For example:
```js
util.types.isUint32Array(new ArrayBuffer()); // Returns false
util.types.isUint32Array(new Uint32Array()); // Returns true
util.types.isUint32Array(new Float64Array()); // Returns false
```
### util.types.isWeakMap(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a built-in [`WeakMap`][] instance.
For example:
```js
util.types.isWeakMap(new WeakMap()); // Returns true
```
### util.types.isWeakSet(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a built-in [`WeakSet`][] instance.
For example:
```js
util.types.isWeakSet(new WeakSet()); // Returns true
```
### util.types.isWebAssemblyCompiledModule(value)
<!-- YAML
added: REPLACEME
-->
Returns `true` if the value is a built-in [`WebAssembly.Module`][] instance.
For example:
```js
const module = new WebAssembly.Module(wasmBuffer);
util.types.isWebAssemblyCompiledModule(module); // Returns true
```
## Deprecated APIs
The following APIs have been deprecated and should no longer be used. Existing
@ -1014,7 +1563,7 @@ added: v0.6.0
deprecated: v4.0.0
-->
> Stability: 0 - Deprecated
> Stability: 0 - Deprecated: Use [`util.types.isDate()`][] instead.
* `object` {any}
* Returns: {boolean}
@ -1038,7 +1587,7 @@ added: v0.6.0
deprecated: v4.0.0
-->
> Stability: 0 - Deprecated
> Stability: 0 - Deprecated: Use [`util.types.isNativeError()`][] instead.
* `object` {any}
* Returns: {boolean}
@ -1385,14 +1934,42 @@ Deprecated predecessor of `console.log`.
[`'uncaughtException'`]: process.html#process_event_uncaughtexception
[`Array.isArray()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
[`Buffer.isBuffer()`]: buffer.html#buffer_class_method_buffer_isbuffer_obj
[`Error`]: errors.html#errors_class_error
[`Object.assign()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
[`ArrayBuffer`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer
[`ArrayBuffer.isView()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/isView
[async function]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
[`assert.deepStrictEqual()`]: assert.html#assert_assert_deepstrictequal_actual_expected_message
[`Buffer.isBuffer()`]: buffer.html#buffer_class_method_buffer_isbuffer_obj
[`console.error()`]: console.html#console_console_error_data_args
[`console.log()`]: console.html#console_console_log_data_args
[`DataView`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView
[`Date`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date
[`Error`]: errors.html#errors_class_error
[`Float32Array`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array
[`Float64Array`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float64Array
[`Int8Array`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int8Array
[`Int16Array`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int16Array
[`Int32Array`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int32Array
[`Map`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
[`Object.assign()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
[`Promise`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
[`Proxy`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
[`Set`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
[`SharedArrayBuffer`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer
[`TypedArray`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray
[`util.inspect()`]: #util_util_inspect_object_options
[`util.promisify()`]: #util_util_promisify_original
[`util.types.isAnyArrayBuffer()`]: #util_util_types_isanyarraybuffer_value
[`util.types.isArrayBuffer()`]: #util_util_types_isarraybuffer_value
[`util.types.isDate()`]: #util_util_types_isdate_value
[`util.types.isNativeError()`]: #util_util_types_isnativeerror_value
[`util.types.isSharedArrayBuffer()`]: #util_util_types_issharedarraybuffer_value
[`Uint8Array`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array
[`Uint8ClampedArray`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8ClampedArray
[`Uint16Array`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint16Array
[`Uint32Array`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint32Array
[`WeakMap`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap
[`WeakSet`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet
[`WebAssembly.Module`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module
[Custom inspection functions on Objects]: #util_custom_inspection_functions_on_objects
[Custom promisified functions]: #util_custom_promisified_functions
[Customizing `util.inspect` colors]: #util_customizing_util_inspect_colors

View File

@ -37,7 +37,14 @@ const {
kMaxLength,
kStringMaxLength
} = process.binding('buffer');
const { isAnyArrayBuffer } = process.binding('util');
// We cannot use internalBinding unconditionally here because of the way
// that test/parallel/test-buffer-bindingobj-no-zerofill.js is written.
let isAnyArrayBuffer;
try {
isAnyArrayBuffer = internalBinding('types').isAnyArrayBuffer;
} catch (e) {
isAnyArrayBuffer = require('util').types.isAnyArrayBuffer;
}
const {
customInspectSymbol,
normalizeEncoding,

View File

@ -110,6 +110,28 @@
NativeModule.require('internal/process/modules').setup();
}
{
// Install legacy getters on the `util` binding for typechecking.
// TODO(addaleax): Turn into a full runtime deprecation.
const { pendingDeprecation } = process.binding('config');
const { deprecate } = NativeModule.require('internal/util');
const utilBinding = process.binding('util');
const types = internalBinding('types');
for (const name of [
'isArrayBuffer', 'isArrayBufferView', 'isAsyncFunction',
'isDataView', 'isDate', 'isExternal', 'isMap', 'isMapIterator',
'isNativeError', 'isPromise', 'isRegExp', 'isSet', 'isSetIterator',
'isTypedArray', 'isUint8Array', 'isAnyArrayBuffer'
]) {
utilBinding[name] = pendingDeprecation ?
deprecate(types[name],
'Accessing native typechecking bindings of Node ' +
'directly is deprecated. ' +
`Please use \`util.types.${name}\` instead.`,
'DEP0XXX') :
types[name];
}
}
// There are various modes that Node can run in. The most common two
// are running from a script and running the REPL - but there are a few

View File

@ -19,7 +19,7 @@ const { isArrayBufferView } = require('internal/util/types');
const {
isArrayBuffer
} = process.binding('util');
} = internalBinding('types');
const {
encodeUtf8String

View File

@ -2,7 +2,7 @@
const { compare } = process.binding('buffer');
const { isArrayBufferView } = require('internal/util/types');
const { isDate, isMap, isRegExp, isSet } = process.binding('util');
const { isDate, isMap, isRegExp, isSet } = internalBinding('types');
function objectToString(o) {
return Object.prototype.toString.call(o);

View File

@ -29,8 +29,48 @@ function isUint8Array(value) {
return TypedArrayProto_toStringTag(value) === 'Uint8Array';
}
function isUint8ClampedArray(value) {
return TypedArrayProto_toStringTag(value) === 'Uint8ClampedArray';
}
function isUint16Array(value) {
return TypedArrayProto_toStringTag(value) === 'Uint16Array';
}
function isUint32Array(value) {
return TypedArrayProto_toStringTag(value) === 'Uint32Array';
}
function isInt8Array(value) {
return TypedArrayProto_toStringTag(value) === 'Int8Array';
}
function isInt16Array(value) {
return TypedArrayProto_toStringTag(value) === 'Int16Array';
}
function isInt32Array(value) {
return TypedArrayProto_toStringTag(value) === 'Int32Array';
}
function isFloat32Array(value) {
return TypedArrayProto_toStringTag(value) === 'Float32Array';
}
function isFloat64Array(value) {
return TypedArrayProto_toStringTag(value) === 'Float64Array';
}
module.exports = {
isArrayBufferView,
isTypedArray,
isUint8Array
isUint8Array,
isUint8ClampedArray,
isUint16Array,
isUint32Array,
isInt8Array,
isInt16Array,
isInt32Array,
isFloat32Array,
isFloat64Array
};

View File

@ -30,6 +30,13 @@ const { previewMapIterator, previewSetIterator } = require('internal/v8');
const {
getPromiseDetails,
getProxyDetails,
kPending,
kRejected,
} = process.binding('util');
const types = internalBinding('types');
Object.assign(types, require('internal/util/types'));
const {
isAnyArrayBuffer,
isDataView,
isExternal,
@ -40,13 +47,8 @@ const {
isSetIterator,
isRegExp,
isDate,
kPending,
kRejected,
} = process.binding('util');
const {
isTypedArray
} = require('internal/util/types');
} = types;
const {
isDeepStrictEqual
@ -1149,6 +1151,7 @@ module.exports = exports = {
promisify,
TextDecoder,
TextEncoder,
types,
// Deprecated Old Stuff
debug: deprecate(debug,

View File

@ -320,6 +320,7 @@
'src/node_postmortem_metadata.cc',
'src/node_serdes.cc',
'src/node_trace_events.cc',
'src/node_types.cc',
'src/node_url.cc',
'src/node_util.cc',
'src/node_v8.cc',

View File

@ -126,6 +126,7 @@ struct sockaddr;
V(timer_wrap) \
V(trace_events) \
V(tty_wrap) \
V(types) \
V(udp_wrap) \
V(url) \
V(util) \

69
src/node_types.cc Normal file
View File

@ -0,0 +1,69 @@
#include "node_internals.h"
using v8::Context;
using v8::FunctionCallbackInfo;
using v8::Local;
using v8::Object;
using v8::Value;
namespace node {
namespace {
#define VALUE_METHOD_MAP(V) \
V(External) \
V(Date) \
V(ArgumentsObject) \
V(BooleanObject) \
V(NumberObject) \
V(StringObject) \
V(SymbolObject) \
V(NativeError) \
V(RegExp) \
V(AsyncFunction) \
V(GeneratorFunction) \
V(GeneratorObject) \
V(Promise) \
V(Map) \
V(Set) \
V(MapIterator) \
V(SetIterator) \
V(WeakMap) \
V(WeakSet) \
V(ArrayBuffer) \
V(DataView) \
V(SharedArrayBuffer) \
V(Proxy) \
V(WebAssemblyCompiledModule) \
#define V(type) \
static void Is##type(const FunctionCallbackInfo<Value>& args) { \
args.GetReturnValue().Set(args[0]->Is##type()); \
}
VALUE_METHOD_MAP(V)
#undef V
static void IsAnyArrayBuffer(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(
args[0]->IsArrayBuffer() || args[0]->IsSharedArrayBuffer());
}
void InitializeTypes(Local<Object> target,
Local<Value> unused,
Local<Context> context) {
Environment* env = Environment::GetCurrent(context);
#define V(type) env->SetMethod(target, \
"is" #type, \
Is##type);
VALUE_METHOD_MAP(V)
#undef V
env->SetMethod(target, "isAnyArrayBuffer", IsAnyArrayBuffer);
}
} // anonymous namespace
} // namespace node
NODE_MODULE_CONTEXT_AWARE_INTERNAL(types, node::InitializeTypes)

View File

@ -17,40 +17,6 @@ using v8::Proxy;
using v8::String;
using v8::Value;
#define VALUE_METHOD_MAP(V) \
V(isArrayBuffer, IsArrayBuffer) \
V(isArrayBufferView, IsArrayBufferView) \
V(isAsyncFunction, IsAsyncFunction) \
V(isDataView, IsDataView) \
V(isDate, IsDate) \
V(isExternal, IsExternal) \
V(isMap, IsMap) \
V(isMapIterator, IsMapIterator) \
V(isNativeError, IsNativeError) \
V(isPromise, IsPromise) \
V(isRegExp, IsRegExp) \
V(isSet, IsSet) \
V(isSetIterator, IsSetIterator) \
V(isTypedArray, IsTypedArray) \
V(isUint8Array, IsUint8Array)
#define V(_, ucname) \
static void ucname(const FunctionCallbackInfo<Value>& args) { \
CHECK_EQ(1, args.Length()); \
args.GetReturnValue().Set(args[0]->ucname()); \
}
VALUE_METHOD_MAP(V)
#undef V
static void IsAnyArrayBuffer(const FunctionCallbackInfo<Value>& args) {
CHECK_EQ(1, args.Length());
args.GetReturnValue().Set(
args[0]->IsArrayBuffer() || args[0]->IsSharedArrayBuffer());
}
static void GetPromiseDetails(const FunctionCallbackInfo<Value>& args) {
// Return undefined if it's not a Promise.
if (!args[0]->IsPromise())
@ -191,12 +157,6 @@ void Initialize(Local<Object> target,
Local<Context> context) {
Environment* env = Environment::GetCurrent(context);
#define V(lcname, ucname) env->SetMethod(target, #lcname, ucname);
VALUE_METHOD_MAP(V)
#undef V
env->SetMethod(target, "isAnyArrayBuffer", IsAnyArrayBuffer);
#define V(name, _) \
target->Set(context, \
FIXED_ONE_BYTE_STRING(env->isolate(), #name), \

View File

@ -1,57 +0,0 @@
'use strict';
// Flags: --expose-internals
require('../common');
const assert = require('assert');
const types = require('internal/util/types');
const primitive = true;
const arrayBuffer = new ArrayBuffer();
const dataView = new DataView(arrayBuffer);
const int32Array = new Int32Array(arrayBuffer);
const uint8Array = new Uint8Array(arrayBuffer);
const buffer = Buffer.from(arrayBuffer);
const fakeDataView = Object.create(DataView.prototype);
const fakeInt32Array = Object.create(Int32Array.prototype);
const fakeUint8Array = Object.create(Uint8Array.prototype);
const fakeBuffer = Object.create(Buffer.prototype);
const stealthyDataView =
Object.setPrototypeOf(new DataView(arrayBuffer), Uint8Array.prototype);
const stealthyInt32Array =
Object.setPrototypeOf(new Int32Array(arrayBuffer), uint8Array);
const stealthyUint8Array =
Object.setPrototypeOf(new Uint8Array(arrayBuffer), ArrayBuffer.prototype);
const all = [
primitive, arrayBuffer, dataView, int32Array, uint8Array, buffer,
fakeDataView, fakeInt32Array, fakeUint8Array, fakeBuffer,
stealthyDataView, stealthyInt32Array, stealthyUint8Array
];
const expected = {
isArrayBufferView: [
dataView, int32Array, uint8Array, buffer,
stealthyDataView, stealthyInt32Array, stealthyUint8Array
],
isTypedArray: [
int32Array, uint8Array, buffer, stealthyInt32Array, stealthyUint8Array
],
isUint8Array: [
uint8Array, buffer, stealthyUint8Array
]
};
for (const testedFunc of Object.keys(expected)) {
const func = types[testedFunc];
const yup = [];
for (const value of all) {
if (func(value)) {
yup.push(value);
}
}
console.log('Testing', testedFunc);
assert.deepStrictEqual(yup, expected[testedFunc]);
}

View File

@ -0,0 +1,162 @@
/*global SharedArrayBuffer*/
'use strict';
const common = require('../common');
const fixtures = require('../common/fixtures');
const assert = require('assert');
const { types, inspect } = require('util');
const path = require('path');
const fs = require('fs');
const vm = require('vm');
const { JSStream } = process.binding('js_stream');
common.crashOnUnhandledRejection();
const external = (new JSStream())._externalStream;
const wasmBuffer = fixtures.readSync('test.wasm');
for (const [ value, _method ] of [
[ external, 'isExternal' ],
[ new Date() ],
[ (function() { return arguments; })(), 'isArgumentsObject' ],
[ new Boolean(), 'isBooleanObject' ],
[ new Number(), 'isNumberObject' ],
[ new String(), 'isStringObject' ],
[ Object(Symbol()), 'isSymbolObject' ],
[ new Error(), 'isNativeError' ],
[ new RegExp() ],
[ async function() {}, 'isAsyncFunction' ],
[ function*() {}, 'isGeneratorFunction' ],
[ (function*() {})(), 'isGeneratorObject' ],
[ Promise.resolve() ],
[ new Map() ],
[ new Set() ],
[ (new Map())[Symbol.iterator](), 'isMapIterator' ],
[ (new Set())[Symbol.iterator](), 'isSetIterator' ],
[ new WeakMap() ],
[ new WeakSet() ],
[ new ArrayBuffer() ],
[ new Uint8Array() ],
[ new Uint8ClampedArray() ],
[ new Uint16Array() ],
[ new Uint32Array() ],
[ new Int8Array() ],
[ new Int16Array() ],
[ new Int32Array() ],
[ new Float32Array() ],
[ new Float64Array() ],
[ Object.defineProperty(new Uint8Array(),
Symbol.toStringTag,
{ value: 'foo' }) ],
[ new DataView(new ArrayBuffer()) ],
[ new SharedArrayBuffer() ],
[ new Proxy({}, {}), 'isProxy' ],
[ new WebAssembly.Module(wasmBuffer), 'isWebAssemblyCompiledModule' ],
]) {
const method = _method || `is${value.constructor.name}`;
assert(method in types, `Missing ${method} for ${inspect(value)}`);
assert(types[method](value), `Want ${inspect(value)} to match ${method}`);
for (const key of Object.keys(types)) {
if ((types.isArrayBufferView(value) ||
types.isAnyArrayBuffer(value)) && key.includes('Array')) {
continue;
}
assert.strictEqual(types[key](value),
key === method,
`${inspect(value)}: ${key}, ` +
`${method}, ${types[key](value)}`);
}
}
{
assert(!types.isUint8Array({ [Symbol.toStringTag]: 'Uint8Array' }));
assert(types.isUint8Array(vm.runInNewContext('new Uint8Array')));
}
{
const primitive = true;
const arrayBuffer = new ArrayBuffer();
const dataView = new DataView(arrayBuffer);
const int32Array = new Int32Array(arrayBuffer);
const uint8Array = new Uint8Array(arrayBuffer);
const buffer = Buffer.from(arrayBuffer);
const fakeDataView = Object.create(DataView.prototype);
const fakeInt32Array = Object.create(Int32Array.prototype);
const fakeUint8Array = Object.create(Uint8Array.prototype);
const fakeBuffer = Object.create(Buffer.prototype);
const stealthyDataView =
Object.setPrototypeOf(new DataView(arrayBuffer), Uint8Array.prototype);
const stealthyInt32Array =
Object.setPrototypeOf(new Int32Array(arrayBuffer), uint8Array);
const stealthyUint8Array =
Object.setPrototypeOf(new Uint8Array(arrayBuffer), ArrayBuffer.prototype);
const all = [
primitive, arrayBuffer, dataView, int32Array, uint8Array, buffer,
fakeDataView, fakeInt32Array, fakeUint8Array, fakeBuffer,
stealthyDataView, stealthyInt32Array, stealthyUint8Array
];
const expected = {
isArrayBufferView: [
dataView, int32Array, uint8Array, buffer,
stealthyDataView, stealthyInt32Array, stealthyUint8Array
],
isTypedArray: [
int32Array, uint8Array, buffer, stealthyInt32Array, stealthyUint8Array
],
isUint8Array: [
uint8Array, buffer, stealthyUint8Array
]
};
for (const testedFunc of Object.keys(expected)) {
const func = types[testedFunc];
const yup = [];
for (const value of all) {
if (func(value)) {
yup.push(value);
}
}
console.log('Testing', testedFunc);
assert.deepStrictEqual(yup, expected[testedFunc]);
}
}
// Try reading the v8.h header to verify completeness.
let v8_h;
try {
v8_h = fs.readFileSync(path.resolve(
__dirname, '..', '..', 'deps', 'v8', 'include', 'v8.h'), 'utf8');
} catch (e) {
// If loading the header fails, it should fail because we did not find it.
assert.strictEqual(e.code, 'ENOENT');
common.skip('Could not read v8.h');
return;
}
// Exclude a number of checks that make sense on the C++ side but have
// much faster/better JS equivalents, so they should not be exposed.
const exclude = [
'Undefined', 'Null', 'NullOrUndefined', 'True', 'False', 'Name', 'String',
'Symbol', 'Function', 'Array', 'Object', 'Boolean', 'Number', 'Int32',
'Uint32'
];
const start = v8_h.indexOf('Value : public Data');
const end = v8_h.indexOf('};', start);
const valueDefinition = v8_h.substr(start, end - start);
const re = /bool Is(\w+)\(\)/g;
let match;
while (match = re.exec(valueDefinition)) {
if (exclude.includes(match[1]))
continue;
assert(`is${match[1]}` in types,
`util.types should provide check for Is${match[1]}`);
}

View File

@ -25,7 +25,6 @@ const common = require('../common');
const assert = require('assert');
const util = require('util');
const errors = require('internal/errors');
const binding = process.binding('util');
const context = require('vm').runInNewContext;
// isArray
@ -155,22 +154,23 @@ util.debug('test');
util.error('test');
{
// binding.isNativeError()
assert.strictEqual(binding.isNativeError(new Error()), true);
assert.strictEqual(binding.isNativeError(new TypeError()), true);
assert.strictEqual(binding.isNativeError(new SyntaxError()), true);
assert.strictEqual(binding.isNativeError(new (context('Error'))()), true);
assert.strictEqual(binding.isNativeError(new (context('TypeError'))()), true);
assert.strictEqual(binding.isNativeError(new (context('SyntaxError'))()),
assert.strictEqual(util.types.isNativeError(new Error()), true);
assert.strictEqual(util.types.isNativeError(new TypeError()), true);
assert.strictEqual(util.types.isNativeError(new SyntaxError()), true);
assert.strictEqual(util.types.isNativeError(new (context('Error'))()),
true);
assert.strictEqual(binding.isNativeError({}), false);
assert.strictEqual(binding.isNativeError({ name: 'Error', message: '' }),
assert.strictEqual(util.types.isNativeError(new (context('TypeError'))()),
true);
assert.strictEqual(util.types.isNativeError(new (context('SyntaxError'))()),
true);
assert.strictEqual(util.types.isNativeError({}), false);
assert.strictEqual(util.types.isNativeError({ name: 'Error', message: '' }),
false);
assert.strictEqual(binding.isNativeError([]), false);
assert.strictEqual(binding.isNativeError(Object.create(Error.prototype)),
assert.strictEqual(util.types.isNativeError([]), false);
assert.strictEqual(util.types.isNativeError(Object.create(Error.prototype)),
false);
assert.strictEqual(
binding.isNativeError(new errors.Error('ERR_IPC_CHANNEL_CLOSED')),
util.types.isNativeError(new errors.Error('ERR_IPC_CHANNEL_CLOSED')),
true
);
}