summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/api/deprecations.md9
-rw-r--r--doc/api/util.md587
-rw-r--r--lib/buffer.js9
-rw-r--r--lib/internal/bootstrap_node.js22
-rw-r--r--lib/internal/encoding.js2
-rw-r--r--lib/internal/util/comparisons.js2
-rw-r--r--lib/internal/util/types.js42
-rw-r--r--lib/util.js15
-rw-r--r--node.gyp1
-rw-r--r--src/node_internals.h1
-rw-r--r--src/node_types.cc69
-rw-r--r--src/node_util.cc40
-rw-r--r--test/parallel/test-types.js57
-rw-r--r--test/parallel/test-util-types.js162
-rw-r--r--test/parallel/test-util.js26
15 files changed, 919 insertions, 125 deletions
diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md
index 097fdfd079..b1cad2d701 100644
--- a/doc/api/deprecations.md
+++ b/doc/api/deprecations.md
@@ -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
diff --git a/doc/api/util.md b/doc/api/util.md
index 03ef10ba1a..524372a6fe 100644
--- a/doc/api/util.md
+++ b/doc/api/util.md
@@ -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
diff --git a/lib/buffer.js b/lib/buffer.js
index 593e10d741..add3303824 100644
--- a/lib/buffer.js
+++ b/lib/buffer.js
@@ -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,
diff --git a/lib/internal/bootstrap_node.js b/lib/internal/bootstrap_node.js
index a0d508c5b1..2444c11781 100644
--- a/lib/internal/bootstrap_node.js
+++ b/lib/internal/bootstrap_node.js
@@ -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
diff --git a/lib/internal/encoding.js b/lib/internal/encoding.js
index fa178f3a8c..f80bdcdf2b 100644
--- a/lib/internal/encoding.js
+++ b/lib/internal/encoding.js
@@ -19,7 +19,7 @@ const { isArrayBufferView } = require('internal/util/types');
const {
isArrayBuffer
-} = process.binding('util');
+} = internalBinding('types');
const {
encodeUtf8String
diff --git a/lib/internal/util/comparisons.js b/lib/internal/util/comparisons.js
index 1145bc7d99..23d8488fbd 100644
--- a/lib/internal/util/comparisons.js
+++ b/lib/internal/util/comparisons.js
@@ -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);
diff --git a/lib/internal/util/types.js b/lib/internal/util/types.js
index c990bea6db..4df62554d1 100644
--- a/lib/internal/util/types.js
+++ b/lib/internal/util/types.js
@@ -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
};
diff --git a/lib/util.js b/lib/util.js
index df117782ca..888c005f2f 100644
--- a/lib/util.js
+++ b/lib/util.js
@@ -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,
diff --git a/node.gyp b/node.gyp
index 827c81692a..977cef33ff 100644
--- a/node.gyp
+++ b/node.gyp
@@ -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',
diff --git a/src/node_internals.h b/src/node_internals.h
index 140826bb7c..43c2b5f112 100644
--- a/src/node_internals.h
+++ b/src/node_internals.h
@@ -126,6 +126,7 @@ struct sockaddr;
V(timer_wrap) \
V(trace_events) \
V(tty_wrap) \
+ V(types) \
V(udp_wrap) \
V(url) \
V(util) \
diff --git a/src/node_types.cc b/src/node_types.cc
new file mode 100644
index 0000000000..4b9f86f0d5
--- /dev/null
+++ b/src/node_types.cc
@@ -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)
diff --git a/src/node_util.cc b/src/node_util.cc
index 1542b533f3..662809fb85 100644
--- a/src/node_util.cc
+++ b/src/node_util.cc
@@ -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), \
diff --git a/test/parallel/test-types.js b/test/parallel/test-types.js
deleted file mode 100644
index ea8adc6cb1..0000000000
--- a/test/parallel/test-types.js
+++ /dev/null
@@ -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]);
-}
diff --git a/test/parallel/test-util-types.js b/test/parallel/test-util-types.js
new file mode 100644
index 0000000000..f9211ddf42
--- /dev/null
+++ b/test/parallel/test-util-types.js
@@ -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]}`);
+}
diff --git a/test/parallel/test-util.js b/test/parallel/test-util.js
index 3b2729c107..72d4b16b35 100644
--- a/test/parallel/test-util.js
+++ b/test/parallel/test-util.js
@@ -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
);
}