aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/bun.js')
-rw-r--r--src/bun.js/bindings/BunJSCModule.cpp33
-rw-r--r--src/bun.js/bindings/JSEnvironmentVariableMap.cpp72
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.cpp12
-rw-r--r--src/bun.js/bindings/bindings.zig5
-rw-r--r--src/bun.js/bun-jsc.exports.js2
5 files changed, 124 insertions, 0 deletions
diff --git a/src/bun.js/bindings/BunJSCModule.cpp b/src/bun.js/bindings/BunJSCModule.cpp
index 63721a878..5809a9813 100644
--- a/src/bun.js/bindings/BunJSCModule.cpp
+++ b/src/bun.js/bindings/BunJSCModule.cpp
@@ -420,6 +420,38 @@ JSC_DEFINE_HOST_FUNCTION(functionDrainMicrotasks, (JSGlobalObject * globalObject
return JSValue::encode(jsUndefined());
}
+JSC_DEFINE_HOST_FUNCTION(functionSetTimeZone, (JSGlobalObject * globalObject, CallFrame* callFrame))
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ if (callFrame->argumentCount() < 1) {
+ throwTypeError(globalObject, scope, "setTimeZone requires a timezone string"_s);
+ return encodedJSValue();
+ }
+
+ if (!callFrame->argument(0).isString()) {
+ throwTypeError(globalObject, scope, "setTimeZone requires a timezone string"_s);
+ return encodedJSValue();
+ }
+
+ String timeZoneName = callFrame->argument(0).toWTFString(globalObject);
+ RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
+ double time = callFrame->argument(1).toNumber(globalObject);
+ RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
+ if (!WTF::setTimeZoneOverride(timeZoneName)) {
+ throwTypeError(globalObject, scope, makeString("Invalid timezone: \""_s, timeZoneName, "\""_s));
+ return encodedJSValue();
+ }
+ vm.dateCache.resetIfNecessarySlow();
+ WTF::Vector<UChar, 32> buffer;
+ WTF::getTimeZoneOverride(buffer);
+ WTF::String timeZoneString(buffer.data(), buffer.size());
+ return JSValue::encode(jsString(vm, timeZoneString));
+}
+
JSC_DEFINE_HOST_FUNCTION(functionRunProfiler, (JSGlobalObject * globalObject, CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
@@ -528,6 +560,7 @@ JSC::JSObject* createJSCModule(JSC::JSGlobalObject* globalObject)
object->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "getProtectedObjects"_s), 1, functionGetProtectedObjects, ImplementationVisibility::Public, NoIntrinsic, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete | 0);
object->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "generateHeapSnapshotForDebugging"_s), 0, functionGenerateHeapSnapshotForDebugging, ImplementationVisibility::Public, NoIntrinsic, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete | 0);
object->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "profile"_s), 0, functionRunProfiler, ImplementationVisibility::Public, NoIntrinsic, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete | 0);
+ object->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "setTimeZone"_s), 0, functionSetTimeZone, ImplementationVisibility::Public, NoIntrinsic, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete | 0);
}
return object;
diff --git a/src/bun.js/bindings/JSEnvironmentVariableMap.cpp b/src/bun.js/bindings/JSEnvironmentVariableMap.cpp
index b90d9f44c..5c0357066 100644
--- a/src/bun.js/bindings/JSEnvironmentVariableMap.cpp
+++ b/src/bun.js/bindings/JSEnvironmentVariableMap.cpp
@@ -50,6 +50,64 @@ JSC_DEFINE_CUSTOM_SETTER(jsSetterEnvironmentVariable, (JSGlobalObject * globalOb
return true;
}
+JSC_DEFINE_CUSTOM_GETTER(jsTimeZoneEnvironmentVariableGetter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName propertyName))
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* thisObject = jsDynamicCast<JSObject*>(JSValue::decode(thisValue));
+ if (UNLIKELY(!thisObject))
+ return JSValue::encode(jsUndefined());
+
+ auto* clientData = WebCore::clientData(vm);
+
+ ZigString name = toZigString(propertyName.publicName());
+ ZigString value = { nullptr, 0 };
+
+ if (auto hasExistingValue = thisObject->getIfPropertyExists(globalObject, clientData->builtinNames().dataPrivateName())) {
+ return JSValue::encode(hasExistingValue);
+ }
+
+ if (!Bun__getEnvValue(globalObject, &name, &value) || value.len == 0) {
+ return JSValue::encode(jsUndefined());
+ }
+
+ JSValue out = jsString(vm, Zig::toStringCopy(value));
+ thisObject->putDirect(vm, clientData->builtinNames().dataPrivateName(), out, 0);
+
+ return JSValue::encode(out);
+}
+
+// In Node.js, the "TZ" environment variable is special.
+// Setting it automatically updates the timezone.
+// We also expose an explicit setTimeZone function in bun:jsc
+JSC_DEFINE_CUSTOM_SETTER(jsTimeZoneEnvironmentVariableSetter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, EncodedJSValue value, PropertyName propertyName))
+{
+ VM& vm = globalObject->vm();
+ JSC::JSObject* object = JSValue::decode(thisValue).getObject();
+ if (!object)
+ return false;
+
+ JSValue decodedValue = JSValue::decode(value);
+ if (decodedValue.isString()) {
+ auto timeZoneName = decodedValue.toWTFString(globalObject);
+ if (timeZoneName.length() < 32) {
+ if (WTF::setTimeZoneOverride(timeZoneName)) {
+ vm.dateCache.resetIfNecessarySlow();
+ }
+ }
+ }
+
+ auto* clientData = WebCore::clientData(vm);
+ auto* builtinNames = &clientData->builtinNames();
+ auto privateName = builtinNames->dataPrivateName();
+ object->putDirect(vm, privateName, JSValue::decode(value), 0);
+
+ // Recreate this because the property visibility needs to be set correctly
+ object->putDirectCustomAccessor(vm, propertyName, JSC::CustomGetterSetter::create(vm, jsTimeZoneEnvironmentVariableGetter, jsTimeZoneEnvironmentVariableSetter), JSC::PropertyAttribute::CustomAccessor | 0);
+ return true;
+}
+
JSValue createEnvironmentVariablesMap(Zig::GlobalObject* globalObject)
{
VM& vm = globalObject->vm();
@@ -65,11 +123,25 @@ JSValue createEnvironmentVariablesMap(Zig::GlobalObject* globalObject)
object = constructEmptyObject(globalObject, globalObject->objectPrototype());
}
+ static NeverDestroyed<String> TZ = MAKE_STATIC_STRING_IMPL("TZ");
+ bool hasTZ = false;
for (size_t i = 0; i < count; i++) {
auto name = Zig::toStringCopy(names[i]);
+ if (name == TZ) {
+ hasTZ = true;
+ continue;
+ }
object->putDirectCustomAccessor(vm, Identifier::fromString(vm, name), JSC::CustomGetterSetter::create(vm, jsGetterEnvironmentVariable, jsSetterEnvironmentVariable), JSC::PropertyAttribute::CustomAccessor | 0);
}
+ unsigned int TZAttrs = JSC::PropertyAttribute::CustomAccessor | 0;
+ if (!hasTZ) {
+ TZAttrs |= JSC::PropertyAttribute::DontEnum;
+ }
+ object->putDirectCustomAccessor(
+ vm,
+ Identifier::fromString(vm, TZ), JSC::CustomGetterSetter::create(vm, jsTimeZoneEnvironmentVariableGetter, jsTimeZoneEnvironmentVariableSetter), TZAttrs);
+
return object;
}
} \ No newline at end of file
diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp
index 663c2a491..b3da8a98f 100644
--- a/src/bun.js/bindings/ZigGlobalObject.cpp
+++ b/src/bun.js/bindings/ZigGlobalObject.cpp
@@ -3768,6 +3768,18 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
visitor.addOpaqueRoot(context);
}
+extern "C" bool JSGlobalObject__setTimeZone(JSC::JSGlobalObject* globalObject, const ZigString* timeZone)
+{
+ auto& vm = globalObject->vm();
+
+ if (WTF::setTimeZoneOverride(Zig::toString(*timeZone))) {
+ vm.dateCache.resetIfNecessarySlow();
+ return true;
+ }
+
+ return false;
+}
+
extern "C" void JSGlobalObject__throwTerminationException(JSC::JSGlobalObject* globalObject)
{
globalObject->vm().setHasTerminationRequest();
diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig
index 373bca8ec..a03737119 100644
--- a/src/bun.js/bindings/bindings.zig
+++ b/src/bun.js/bindings/bindings.zig
@@ -2354,6 +2354,11 @@ pub const JSGlobalObject = extern struct {
extern fn JSGlobalObject__throwTerminationException(this: *JSGlobalObject) void;
pub const throwTerminationException = JSGlobalObject__throwTerminationException;
pub const clearTerminationException = JSGlobalObject__clearTerminationException;
+ extern fn JSGlobalObject__setTimeZone(this: *JSGlobalObject, timeZone: *const ZigString) bool;
+
+ pub fn setTimeZone(this: *JSGlobalObject, timeZone: *const ZigString) bool {
+ return JSGlobalObject__setTimeZone(this, timeZone);
+ }
pub fn throwInvalidArguments(
this: *JSGlobalObject,
diff --git a/src/bun.js/bun-jsc.exports.js b/src/bun.js/bun-jsc.exports.js
index 765f9aeb5..d49e41851 100644
--- a/src/bun.js/bun-jsc.exports.js
+++ b/src/bun.js/bun-jsc.exports.js
@@ -31,3 +31,5 @@ export const getProtectedObjects = jsc.getProtectedObjects;
export const generateHeapSnapshotForDebugging = jsc.generateHeapSnapshotForDebugging;
export const profile = jsc.profile;
export default jsc;
+export const setTimeZone = jsc.setTimeZone;
+export const setTimezone = setTimeZone;