aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/bun.js/bindings/ModuleLoader.cpp8
-rw-r--r--src/bun.js/bindings/exports.zig1
-rw-r--r--src/bun.js/bindings/headers-handwritten.h1
-rw-r--r--src/bun.js/bindings/node_util_types.cpp352
-rw-r--r--src/bun.js/bindings/node_util_types.h11
-rw-r--r--src/bun.js/module_loader.zig5
-rw-r--r--test/bun.js/test-util-types.test.js281
7 files changed, 659 insertions, 0 deletions
diff --git a/src/bun.js/bindings/ModuleLoader.cpp b/src/bun.js/bindings/ModuleLoader.cpp
index c35627f25..40e41b083 100644
--- a/src/bun.js/bindings/ModuleLoader.cpp
+++ b/src/bun.js/bindings/ModuleLoader.cpp
@@ -34,6 +34,7 @@
#include "../modules/ObjectModule.h"
#include "../modules/NodeModuleModule.h"
#include "../modules/TTYModule.h"
+#include "node_util_types.h"
namespace Bun {
using namespace Zig;
@@ -426,6 +427,13 @@ static JSValue fetchSourceCode(
return rejectOrResolve(JSSourceCode::create(vm, WTFMove(source)));
}
+ case SyntheticModuleType::NodeUtilTypes: {
+ auto source = JSC::SourceCode(
+ JSC::SyntheticSourceProvider::create(Bun::generateNodeUtilTypesSourceCode,
+ JSC::SourceOrigin(), WTFMove(moduleKey)));
+
+ return rejectOrResolve(JSSourceCode::create(vm, WTFMove(source)));
+ }
case SyntheticModuleType::Process: {
auto source = JSC::SourceCode(
JSC::SyntheticSourceProvider::create(generateProcessSourceCode,
diff --git a/src/bun.js/bindings/exports.zig b/src/bun.js/bindings/exports.zig
index 953c2e807..2e187e302 100644
--- a/src/bun.js/bindings/exports.zig
+++ b/src/bun.js/bindings/exports.zig
@@ -235,6 +235,7 @@ pub const ResolvedSource = extern struct {
@"node:string_decoder" = 1027,
@"node:module" = 1028,
@"node:tty" = 1029,
+ @"node:util/types" = 1030,
};
};
diff --git a/src/bun.js/bindings/headers-handwritten.h b/src/bun.js/bindings/headers-handwritten.h
index 5ce164a69..0a2619187 100644
--- a/src/bun.js/bindings/headers-handwritten.h
+++ b/src/bun.js/bindings/headers-handwritten.h
@@ -207,6 +207,7 @@ enum SyntheticModuleType : uint64_t {
StringDecoder = 1027,
Module = 1028,
TTY = 1029,
+ NodeUtilTypes = 1030,
};
extern "C" const char* Bun__userAgent;
diff --git a/src/bun.js/bindings/node_util_types.cpp b/src/bun.js/bindings/node_util_types.cpp
new file mode 100644
index 000000000..54fcca78b
--- /dev/null
+++ b/src/bun.js/bindings/node_util_types.cpp
@@ -0,0 +1,352 @@
+#include "root.h"
+#include "node_util_types.h"
+
+#include "webcrypto/JSCryptoKey.h"
+#include "napi_external.h"
+#include "JavaScriptCore/CallFrame.h"
+#include "JavaScriptCore/CallFrameInlines.h"
+#include "JavaScriptCore/AggregateError.h"
+#include "JavaScriptCore/JSArrayBuffer.h"
+#include "webcrypto/JSJsonWebKey.h"
+#include "JavaScriptCore/ObjectConstructor.h"
+#include "JavaScriptCore/GeneratorFunctionPrototype.h"
+#include "JavaScriptCore/AsyncFunctionPrototype.h"
+
+using namespace JSC;
+
+#define GET_FIRST_VALUE \
+ if (callframe->argumentCount() < 1) \
+ return JSValue::encode(jsBoolean(false)); \
+ JSValue value = callframe->uncheckedArgument(0);
+
+#define GET_FIRST_CELL \
+ if (callframe->argumentCount() < 1) \
+ return JSValue::encode(jsBoolean(false)); \
+ JSValue value = callframe->uncheckedArgument(0); \
+ if (!value.isCell()) \
+ return JSValue::encode(jsBoolean(false)); \
+ JSCell* cell = value.asCell();
+
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsExternal, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_VALUE
+ return JSValue::encode(jsBoolean(value.isCell() && jsDynamicCast<Bun::NapiExternal*>(value) != nullptr));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsDate, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() == JSDateType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsArgumentsObject, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_VALUE
+ if (!value.isCell())
+ return JSValue::encode(jsBoolean(false));
+
+ auto type = value.asCell()->type();
+ switch (type) {
+ case DirectArgumentsType:
+ case ScopedArgumentsType:
+ case ClonedArgumentsType:
+ return JSValue::encode(jsBoolean(true));
+ default:
+ return JSValue::encode(jsBoolean(false));
+ }
+
+ __builtin_unreachable();
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsBigIntObject, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(globalObject->bigIntObjectStructure() == cell->structure()));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsBooleanObject, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_VALUE
+ return JSValue::encode(jsBoolean(value.isCell() && value.asCell()->type() == BooleanObjectType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsNumberObject, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_VALUE
+ return JSValue::encode(jsBoolean(value.isCell() && value.asCell()->type() == NumberObjectType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsStringObject, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_VALUE
+ return JSValue::encode(jsBoolean(value.isCell() && (value.asCell()->type() == StringObjectType || value.asCell()->type() == DerivedStringObjectType)));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsSymbolObject, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+
+ return JSValue::encode(jsBoolean(globalObject->symbolObjectStructure() == cell->structure()));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsNativeError, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_VALUE
+ return JSValue::encode(jsBoolean(value.isCell() && jsDynamicCast<ErrorInstance*>(value) != nullptr));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsRegExp, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_VALUE
+ return JSValue::encode(jsBoolean(value.isCell() && value.asCell()->type() == RegExpObjectType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsAsyncFunction, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(JSValue::strictEqual(globalObject, JSValue(globalObject->asyncFunctionPrototype()), cell->getObject()->getPrototype(cell->getObject(), globalObject))));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsGeneratorFunction, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_VALUE
+ auto* function = jsDynamicCast<JSFunction*>(value);
+ if (!function)
+ return JSValue::encode(jsBoolean(false));
+
+ auto* executable = function->jsExecutable();
+ if (!executable)
+ return JSValue::encode(jsBoolean(false));
+
+ return JSValue::encode(jsBoolean(executable->isGenerator()));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsGeneratorObject, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+
+ return JSValue::encode(jsBoolean(cell->type() == JSGeneratorType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsPromise, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() == JSPromiseType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsMap, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() == JSMapType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsSet, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() == JSSetType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsMapIterator, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() == JSMapIteratorType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsSetIterator, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() == JSSetIteratorType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsWeakMap, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() == JSWeakMapType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsWeakSet, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() == JSWeakSetType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsArrayBuffer, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(jsDynamicCast<JSArrayBuffer*>(cell) != nullptr));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsDataView, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() == DataViewType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsSharedArrayBuffer, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ auto* arrayBuffer = jsDynamicCast<JSArrayBuffer*>(cell);
+ if (!arrayBuffer)
+ return JSValue::encode(jsBoolean(false));
+ return JSValue::encode(jsBoolean(arrayBuffer->isShared()));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsProxy, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() == PureForwardingProxyType || cell->type() == ProxyObjectType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsModuleNamespaceObject, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() == ModuleNamespaceObjectType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsAnyArrayBuffer, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ auto* arrayBuffer = jsDynamicCast<JSArrayBuffer*>(cell);
+ return JSValue::encode(jsBoolean(arrayBuffer != nullptr));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsBoxedPrimitive, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ switch (cell->type()) {
+ case JSC::BooleanObjectType:
+ case JSC::NumberObjectType:
+ case JSC::StringObjectType:
+ case JSC::DerivedStringObjectType:
+ return JSValue::encode(jsBoolean(true));
+
+ default: {
+ if (cell->structure() == globalObject->symbolObjectStructure())
+ return JSValue::encode(jsBoolean(true));
+
+ if (cell->structure() == globalObject->bigIntObjectStructure())
+ return JSValue::encode(jsBoolean(true));
+ }
+ }
+
+ return JSValue::encode(jsBoolean(false));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsArrayBufferView, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() >= Int8ArrayType && cell->type() <= DataViewType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsTypedArray, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() >= Int8ArrayType && cell->type() <= BigUint64ArrayType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsUint8Array, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() == Uint8ArrayType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsUint8ClampedArray, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() == Uint8ClampedArrayType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsUint16Array, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() == Uint16ArrayType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsUint32Array, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() == Uint32ArrayType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsInt8Array, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() == Int8ArrayType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsInt16Array, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() == Int16ArrayType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsInt32Array, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() == Int32ArrayType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsFloat32Array, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() == Float32ArrayType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsFloat64Array, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() == Float64ArrayType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsBigInt64Array, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() == BigInt64ArrayType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsBigUint64Array, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->type() == BigUint64ArrayType));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsKeyObject, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ // Not implemented
+ return JSValue::encode(jsBoolean(false));
+}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionIsCryptoKey, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ GET_FIRST_CELL
+ return JSValue::encode(jsBoolean(cell->inherits<WebCore::JSCryptoKey>()));
+}
+
+namespace Bun {
+void generateNodeUtilTypesSourceCode(JSC::JSGlobalObject* lexicalGlobalObject,
+ JSC::Identifier moduleKey,
+ Vector<JSC::Identifier, 4>& exportNames,
+ JSC::MarkedArgumentBuffer& exportValues)
+{
+ Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+
+ JSC::VM& vm = globalObject->vm();
+
+ JSC::JSObject* defaultObject = constructEmptyObject(globalObject, globalObject->objectPrototype(), 43);
+ exportNames.reserveCapacity(43);
+ exportValues.ensureCapacity(43);
+
+ auto putBoth = [&](JSC::Identifier identifier, NativeFunction functionPtr) {
+ JSC::JSFunction* function = JSC::JSFunction::create(vm, globalObject, 1, identifier.string(), functionPtr, ImplementationVisibility::Public, NoIntrinsic, functionPtr);
+ defaultObject->putDirect(vm, identifier, function, 0);
+ exportNames.append(identifier);
+ exportValues.append(function);
+ };
+
+ putBoth(Identifier::fromString(vm, "isExternal"_s), jsFunctionIsExternal);
+ putBoth(Identifier::fromString(vm, "isDate"_s), jsFunctionIsDate);
+ putBoth(Identifier::fromString(vm, "isArgumentsObject"_s), jsFunctionIsArgumentsObject);
+ putBoth(Identifier::fromString(vm, "isBigIntObject"_s), jsFunctionIsBigIntObject);
+ putBoth(Identifier::fromString(vm, "isBooleanObject"_s), jsFunctionIsBooleanObject);
+ putBoth(Identifier::fromString(vm, "isNumberObject"_s), jsFunctionIsNumberObject);
+ putBoth(Identifier::fromString(vm, "isStringObject"_s), jsFunctionIsStringObject);
+ putBoth(Identifier::fromString(vm, "isSymbolObject"_s), jsFunctionIsSymbolObject);
+ putBoth(Identifier::fromString(vm, "isNativeError"_s), jsFunctionIsNativeError);
+ putBoth(Identifier::fromString(vm, "isRegExp"_s), jsFunctionIsRegExp);
+ putBoth(Identifier::fromString(vm, "isAsyncFunction"_s), jsFunctionIsAsyncFunction);
+ putBoth(Identifier::fromString(vm, "isGeneratorFunction"_s), jsFunctionIsGeneratorFunction);
+ putBoth(Identifier::fromString(vm, "isGeneratorObject"_s), jsFunctionIsGeneratorObject);
+ putBoth(Identifier::fromString(vm, "isPromise"_s), jsFunctionIsPromise);
+ putBoth(Identifier::fromString(vm, "isMap"_s), jsFunctionIsMap);
+ putBoth(Identifier::fromString(vm, "isSet"_s), jsFunctionIsSet);
+ putBoth(Identifier::fromString(vm, "isMapIterator"_s), jsFunctionIsMapIterator);
+ putBoth(Identifier::fromString(vm, "isSetIterator"_s), jsFunctionIsSetIterator);
+ putBoth(Identifier::fromString(vm, "isWeakMap"_s), jsFunctionIsWeakMap);
+ putBoth(Identifier::fromString(vm, "isWeakSet"_s), jsFunctionIsWeakSet);
+ putBoth(Identifier::fromString(vm, "isArrayBuffer"_s), jsFunctionIsArrayBuffer);
+ putBoth(Identifier::fromString(vm, "isDataView"_s), jsFunctionIsDataView);
+ putBoth(Identifier::fromString(vm, "isSharedArrayBuffer"_s), jsFunctionIsSharedArrayBuffer);
+ putBoth(Identifier::fromString(vm, "isProxy"_s), jsFunctionIsProxy);
+ putBoth(Identifier::fromString(vm, "isModuleNamespaceObject"_s), jsFunctionIsModuleNamespaceObject);
+ putBoth(Identifier::fromString(vm, "isAnyArrayBuffer"_s), jsFunctionIsAnyArrayBuffer);
+ putBoth(Identifier::fromString(vm, "isBoxedPrimitive"_s), jsFunctionIsBoxedPrimitive);
+ putBoth(Identifier::fromString(vm, "isArrayBufferView"_s), jsFunctionIsArrayBufferView);
+ putBoth(Identifier::fromString(vm, "isTypedArray"_s), jsFunctionIsTypedArray);
+ putBoth(Identifier::fromString(vm, "isUint8Array"_s), jsFunctionIsUint8Array);
+ putBoth(Identifier::fromString(vm, "isUint8ClampedArray"_s), jsFunctionIsUint8ClampedArray);
+ putBoth(Identifier::fromString(vm, "isUint16Array"_s), jsFunctionIsUint16Array);
+ putBoth(Identifier::fromString(vm, "isUint32Array"_s), jsFunctionIsUint32Array);
+ putBoth(Identifier::fromString(vm, "isInt8Array"_s), jsFunctionIsInt8Array);
+ putBoth(Identifier::fromString(vm, "isInt16Array"_s), jsFunctionIsInt16Array);
+ putBoth(Identifier::fromString(vm, "isInt32Array"_s), jsFunctionIsInt32Array);
+ putBoth(Identifier::fromString(vm, "isFloat32Array"_s), jsFunctionIsFloat32Array);
+ putBoth(Identifier::fromString(vm, "isFloat64Array"_s), jsFunctionIsFloat64Array);
+ putBoth(Identifier::fromString(vm, "isBigInt64Array"_s), jsFunctionIsBigInt64Array);
+ putBoth(Identifier::fromString(vm, "isBigUint64Array"_s), jsFunctionIsBigUint64Array);
+ putBoth(Identifier::fromString(vm, "isKeyObject"_s), jsFunctionIsKeyObject);
+ putBoth(Identifier::fromString(vm, "isCryptoKey"_s), jsFunctionIsCryptoKey);
+ defaultObject->putDirect(vm, JSC::PropertyName(Identifier::fromUid(vm.symbolRegistry().symbolForKey("CommonJS"_s))), jsNumber(0), 0);
+
+ exportNames.append(JSC::Identifier::fromString(vm, "default"_s));
+ exportValues.append(defaultObject);
+}
+} \ No newline at end of file
diff --git a/src/bun.js/bindings/node_util_types.h b/src/bun.js/bindings/node_util_types.h
new file mode 100644
index 000000000..adf0cd0ea
--- /dev/null
+++ b/src/bun.js/bindings/node_util_types.h
@@ -0,0 +1,11 @@
+#include "JavaScriptCore/JSGlobalObject.h"
+#include "ZigGlobalObject.h"
+
+namespace Bun {
+using namespace WebCore;
+
+void generateNodeUtilTypesSourceCode(JSC::JSGlobalObject* lexicalGlobalObject,
+ JSC::Identifier moduleKey,
+ Vector<JSC::Identifier, 4>& exportNames,
+ JSC::MarkedArgumentBuffer& exportValues);
+}
diff --git a/src/bun.js/module_loader.zig b/src/bun.js/module_loader.zig
index a9e2dca5e..f36884014 100644
--- a/src/bun.js/module_loader.zig
+++ b/src/bun.js/module_loader.zig
@@ -1627,6 +1627,7 @@ pub const ModuleLoader = struct {
.@"node:events" => return jsSyntheticModule(.@"node:events"),
.@"node:process" => return jsSyntheticModule(.@"node:process"),
.@"node:tty" => return jsSyntheticModule(.@"node:tty"),
+ .@"node:util/types" => return jsSyntheticModule(.@"node:util/types"),
.@"node:stream" => {
return ResolvedSource{
.allocator = null,
@@ -1984,6 +1985,7 @@ pub const HardcodedModule = enum {
@"node:timers/promises",
@"node:tty",
@"node:url",
+ @"node:util/types",
@"undici",
@"ws",
/// Already resolved modules go in here.
@@ -2024,6 +2026,7 @@ pub const HardcodedModule = enum {
.{ "node:timers/promises", HardcodedModule.@"node:timers/promises" },
.{ "node:tty", HardcodedModule.@"node:tty" },
.{ "node:url", HardcodedModule.@"node:url" },
+ .{ "node:util/types", HardcodedModule.@"node:util/types" },
.{ "undici", HardcodedModule.@"undici" },
.{ "ws", HardcodedModule.@"ws" },
},
@@ -2074,6 +2077,7 @@ pub const HardcodedModule = enum {
.{ "node:timers/promises", "node:timers/promises" },
.{ "node:tty", "node:tty" },
.{ "node:url", "node:url" },
+ .{ "node:util", "node:util" },
.{ "os", "node:os" },
.{ "path", "node:path" },
.{ "path/posix", "node:path/posix" },
@@ -2092,6 +2096,7 @@ pub const HardcodedModule = enum {
.{ "tty", "node:tty" },
.{ "undici", "undici" },
.{ "url", "node:url" },
+ .{ "util", "node:util" },
.{ "ws", "ws" },
.{ "ws/lib/websocket", "ws" },
},
diff --git a/test/bun.js/test-util-types.test.js b/test/bun.js/test-util-types.test.js
new file mode 100644
index 000000000..ce10713e4
--- /dev/null
+++ b/test/bun.js/test-util-types.test.js
@@ -0,0 +1,281 @@
+const assert = require("assert");
+import { test, expect } from "bun:test";
+const types = require("util/types");
+
+function inspect(val) {
+ return Bun.inspect(val);
+}
+
+for (const [value, _method] of [
+ [new Date()],
+ [
+ (function () {
+ return arguments;
+ })(),
+ "isArgumentsObject",
+ ],
+ [new Boolean(), "isBooleanObject"],
+ [new Number(), "isNumberObject"],
+ [new String(), "isStringObject"],
+ [Object(Symbol()), "isSymbolObject"],
+ [Object(BigInt(0)), "isBigIntObject"],
+ [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()],
+ [new BigInt64Array()],
+ [new BigUint64Array()],
+ [new DataView(new ArrayBuffer())],
+ [new SharedArrayBuffer()],
+ [new Proxy({}, {}), "isProxy"],
+]) {
+ const method = _method || `is${value.constructor.name}`;
+ test(method, () => {
+ 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")) ||
+ key === "isBoxedPrimitive"
+ ) {
+ continue;
+ }
+
+ expect(types[key](value)).toBe(key === method);
+ }
+ });
+}
+
+// Check boxed primitives.
+test("isBoxedPrimitive", () => {
+ [
+ new Boolean(),
+ new Number(),
+ new String(),
+ Object(Symbol()),
+ Object(BigInt(0)),
+ ].forEach((entry) => assert(types.isBoxedPrimitive(entry)));
+});
+
+{
+ const primitive = true;
+ const arrayBuffer = new ArrayBuffer();
+ const buffer = Buffer.from(arrayBuffer);
+ const dataView = new DataView(arrayBuffer);
+ const uint8Array = new Uint8Array(arrayBuffer);
+ const uint8ClampedArray = new Uint8ClampedArray(arrayBuffer);
+ const uint16Array = new Uint16Array(arrayBuffer);
+ const uint32Array = new Uint32Array(arrayBuffer);
+ const int8Array = new Int8Array(arrayBuffer);
+ const int16Array = new Int16Array(arrayBuffer);
+ const int32Array = new Int32Array(arrayBuffer);
+ const float32Array = new Float32Array(arrayBuffer);
+ const float64Array = new Float64Array(arrayBuffer);
+ const bigInt64Array = new BigInt64Array(arrayBuffer);
+ const bigUint64Array = new BigUint64Array(arrayBuffer);
+
+ const fakeBuffer = Object.create(Buffer.prototype);
+ const fakeDataView = Object.create(DataView.prototype);
+ const fakeUint8Array = Object.create(Uint8Array.prototype);
+ const fakeUint8ClampedArray = Object.create(Uint8ClampedArray.prototype);
+ const fakeUint16Array = Object.create(Uint16Array.prototype);
+ const fakeUint32Array = Object.create(Uint32Array.prototype);
+ const fakeInt8Array = Object.create(Int8Array.prototype);
+ const fakeInt16Array = Object.create(Int16Array.prototype);
+ const fakeInt32Array = Object.create(Int32Array.prototype);
+ const fakeFloat32Array = Object.create(Float32Array.prototype);
+ const fakeFloat64Array = Object.create(Float64Array.prototype);
+ const fakeBigInt64Array = Object.create(BigInt64Array.prototype);
+ const fakeBigUint64Array = Object.create(BigUint64Array.prototype);
+
+ const stealthyDataView = Object.setPrototypeOf(
+ new DataView(arrayBuffer),
+ Uint8Array.prototype,
+ );
+ const stealthyUint8Array = Object.setPrototypeOf(
+ new Uint8Array(arrayBuffer),
+ ArrayBuffer.prototype,
+ );
+ const stealthyUint8ClampedArray = Object.setPrototypeOf(
+ new Uint8ClampedArray(arrayBuffer),
+ ArrayBuffer.prototype,
+ );
+ const stealthyUint16Array = Object.setPrototypeOf(
+ new Uint16Array(arrayBuffer),
+ Uint16Array.prototype,
+ );
+ const stealthyUint32Array = Object.setPrototypeOf(
+ new Uint32Array(arrayBuffer),
+ Uint32Array.prototype,
+ );
+ const stealthyInt8Array = Object.setPrototypeOf(
+ new Int8Array(arrayBuffer),
+ Int8Array.prototype,
+ );
+ const stealthyInt16Array = Object.setPrototypeOf(
+ new Int16Array(arrayBuffer),
+ Int16Array.prototype,
+ );
+ const stealthyInt32Array = Object.setPrototypeOf(
+ new Int32Array(arrayBuffer),
+ Int32Array.prototype,
+ );
+ const stealthyFloat32Array = Object.setPrototypeOf(
+ new Float32Array(arrayBuffer),
+ Float32Array.prototype,
+ );
+ const stealthyFloat64Array = Object.setPrototypeOf(
+ new Float64Array(arrayBuffer),
+ Float64Array.prototype,
+ );
+ const stealthyBigInt64Array = Object.setPrototypeOf(
+ new BigInt64Array(arrayBuffer),
+ BigInt64Array.prototype,
+ );
+ const stealthyBigUint64Array = Object.setPrototypeOf(
+ new BigUint64Array(arrayBuffer),
+ BigUint64Array.prototype,
+ );
+
+ const all = [
+ primitive,
+ arrayBuffer,
+ buffer,
+ fakeBuffer,
+ dataView,
+ fakeDataView,
+ stealthyDataView,
+ uint8Array,
+ fakeUint8Array,
+ stealthyUint8Array,
+ uint8ClampedArray,
+ fakeUint8ClampedArray,
+ stealthyUint8ClampedArray,
+ uint16Array,
+ fakeUint16Array,
+ stealthyUint16Array,
+ uint32Array,
+ fakeUint32Array,
+ stealthyUint32Array,
+ int8Array,
+ fakeInt8Array,
+ stealthyInt8Array,
+ int16Array,
+ fakeInt16Array,
+ stealthyInt16Array,
+ int32Array,
+ fakeInt32Array,
+ stealthyInt32Array,
+ float32Array,
+ fakeFloat32Array,
+ stealthyFloat32Array,
+ float64Array,
+ fakeFloat64Array,
+ stealthyFloat64Array,
+ bigInt64Array,
+ fakeBigInt64Array,
+ stealthyBigInt64Array,
+ bigUint64Array,
+ fakeBigUint64Array,
+ stealthyBigUint64Array,
+ ];
+
+ const expected = {
+ isArrayBufferView: [
+ buffer,
+ dataView,
+ stealthyDataView,
+ uint8Array,
+ stealthyUint8Array,
+ uint8ClampedArray,
+ stealthyUint8ClampedArray,
+ uint16Array,
+ stealthyUint16Array,
+ uint32Array,
+ stealthyUint32Array,
+ int8Array,
+ stealthyInt8Array,
+ int16Array,
+ stealthyInt16Array,
+ int32Array,
+ stealthyInt32Array,
+ float32Array,
+ stealthyFloat32Array,
+ float64Array,
+ stealthyFloat64Array,
+ bigInt64Array,
+ stealthyBigInt64Array,
+ bigUint64Array,
+ stealthyBigUint64Array,
+ ],
+ isTypedArray: [
+ buffer,
+ uint8Array,
+ stealthyUint8Array,
+ uint8ClampedArray,
+ stealthyUint8ClampedArray,
+ uint16Array,
+ stealthyUint16Array,
+ uint32Array,
+ stealthyUint32Array,
+ int8Array,
+ stealthyInt8Array,
+ int16Array,
+ stealthyInt16Array,
+ int32Array,
+ stealthyInt32Array,
+ float32Array,
+ stealthyFloat32Array,
+ float64Array,
+ stealthyFloat64Array,
+ bigInt64Array,
+ stealthyBigInt64Array,
+ bigUint64Array,
+ stealthyBigUint64Array,
+ ],
+ isUint8Array: [buffer, uint8Array, stealthyUint8Array],
+ isUint8ClampedArray: [uint8ClampedArray, stealthyUint8ClampedArray],
+ isUint16Array: [uint16Array, stealthyUint16Array],
+ isUint32Array: [uint32Array, stealthyUint32Array],
+ isInt8Array: [int8Array, stealthyInt8Array],
+ isInt16Array: [int16Array, stealthyInt16Array],
+ isInt32Array: [int32Array, stealthyInt32Array],
+ isFloat32Array: [float32Array, stealthyFloat32Array],
+ isFloat64Array: [float64Array, stealthyFloat64Array],
+ isBigInt64Array: [bigInt64Array, stealthyBigInt64Array],
+ isBigUint64Array: [bigUint64Array, stealthyBigUint64Array],
+ };
+
+ for (const testedFunc of Object.keys(expected)) {
+ test(testedFunc, () => {
+ const func = types[testedFunc];
+ const yup = [];
+ for (const value of all) {
+ if (func(value)) {
+ yup.push(value);
+ }
+ }
+ expect(yup).toEqual(expected[testedFunc]);
+ });
+ }
+}