aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-11-28 15:55:02 -0800
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-11-28 15:55:02 -0800
commita6cadce6f6292b685cc4160052304b5dfc8cd3ad (patch)
treea1d4d676cfc04ddcf084e12b26c6b4c59093ebd1
parent51d0c3b79f63e5ca1965cb5280c58fc0a9bc4f73 (diff)
downloadbun-a6cadce6f6292b685cc4160052304b5dfc8cd3ad.tar.gz
bun-a6cadce6f6292b685cc4160052304b5dfc8cd3ad.tar.zst
bun-a6cadce6f6292b685cc4160052304b5dfc8cd3ad.zip
Fix process.env and Bun.env object spread
Fixes https://github.com/oven-sh/bun/issues/1512
-rw-r--r--src/bun.js/api/bun.zig197
-rw-r--r--src/bun.js/bindings/JSEnvironmentVariableMap.cpp71
-rw-r--r--src/bun.js/bindings/JSEnvironmentVariableMap.h15
-rw-r--r--src/bun.js/bindings/Process.cpp16
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.cpp18
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.h1
-rw-r--r--src/bun.js/bindings/exports.zig10
-rw-r--r--src/bun.js/javascript.zig3
8 files changed, 127 insertions, 204 deletions
diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig
index 1c60a7faf..f993bc86e 100644
--- a/src/bun.js/api/bun.zig
+++ b/src/bun.js/api/bun.zig
@@ -1241,10 +1241,6 @@ pub const Class = NewClass(
.argv = .{
.get = getArgv,
},
- .env = .{
- .get = EnvironmentVariables.getter,
- },
-
.enableANSIColors = .{
.get = enableANSIColors,
},
@@ -3285,189 +3281,34 @@ pub const UnsafeCString = struct {
/// Also, you can't iterate over process.env normally since it only exists at build-time otherwise
// This is aliased to Bun.env
pub const EnvironmentVariables = struct {
- pub const Class = NewClass(
- void,
- .{
- .name = "DotEnv",
- },
- .{
- .getProperty = .{
- .rfn = getProperty,
- },
- .setProperty = .{
- .rfn = setProperty,
- },
- .deleteProperty = .{
- .rfn = deleteProperty,
- },
- .getPropertyNames = .{
- .rfn = getPropertyNames,
- },
- },
- .{},
- );
-
- pub fn getter(
- _: void,
- ctx: js.JSContextRef,
- _: js.JSValueRef,
- _: js.JSStringRef,
- _: js.ExceptionRef,
- ) js.JSValueRef {
- var existing = ctx.ptr().getCachedObject(ZigString.static("Bun.env"));
- if (existing.isEmpty()) {
- return ctx.ptr().putCachedObject(
- ZigString.static("Bun.env"),
- JSValue.fromRef(js.JSObjectMake(ctx, EnvironmentVariables.Class.get().*, null)),
- ).asObjectRef();
- }
-
- return existing.asObjectRef();
+ pub export fn Bun__getEnvNames(globalObject: *JSC.JSGlobalObject, names: [*]ZigString, max: usize) usize {
+ return getEnvNames(globalObject, names[0..max]);
}
- pub const BooleanString = struct {
- pub const @"true": string = "true";
- pub const @"false": string = "false";
- };
-
- pub fn getProperty(
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- propertyName: js.JSStringRef,
- _: js.ExceptionRef,
- ) callconv(.C) js.JSValueRef {
- var name_slice = propertyName.toZigString().toSlice(ctx.allocator());
- defer name_slice.deinit();
- var name = name_slice.slice();
- if (strings.eqlComptime(name, "toJSON")) {
- var existing = ctx.ptr().getCachedObject(ZigString.static("Bun.env.toJSON"));
- if (existing.isEmpty()) {
- return ctx.ptr().putCachedObject(
- ZigString.static("Bun.env.toJSON"),
- // TODO: stage2 change this to a ptr
- JSC.NewFunction(ctx, ZigString.static("toJSON"), 0, toJSON, false),
- ).asObjectRef();
- }
-
- return existing.asObjectRef();
- }
-
- if (VirtualMachine.vm.bundler.env.map.get(name)) |value| {
- return ZigString.initUTF8(value).toValueGC(ctx).asObjectRef();
- }
-
- if (Output.enable_ansi_colors) {
- // https://github.com/chalk/supports-color/blob/main/index.js
- if (strings.eqlComptime(name, "FORCE_COLOR")) {
- return ZigString.static("\"true\"").toValue(ctx).asObjectRef();
- }
- }
-
- return js.JSValueMakeUndefined(ctx);
- }
-
- pub fn toJSON(
- globalThis: *JSC.JSGlobalObject,
- _: *JSC.CallFrame,
- ) callconv(.C) JSC.JSValue {
- var map = globalThis.bunVM().bundler.env.map.map;
- var keys = map.keys();
- var values = map.values();
- const StackFallback = std.heap.StackFallbackAllocator(32 * 2 * @sizeOf(ZigString));
- var stack = StackFallback{
- .buffer = undefined,
- .fallback_allocator = bun.default_allocator,
- .fixed_buffer_allocator = undefined,
- };
- var allocator = stack.get();
- var key_strings_ = allocator.alloc(ZigString, keys.len * 2) catch unreachable;
- var key_strings = key_strings_[0..keys.len];
- var value_strings = key_strings_[keys.len..];
-
- for (keys) |key, i| {
- key_strings[i] = ZigString.initUTF8(key);
- value_strings[i] = ZigString.initUTF8(values[i]);
- }
-
- var result = JSValue.fromEntries(globalThis, key_strings.ptr, value_strings.ptr, keys.len, false);
- allocator.free(key_strings_);
- return result;
- // }
- // ZigConsoleClient.Formatter.format(this: *Formatter, result: Tag.Result, comptime Writer: type, writer: Writer, value: JSValue, globalThis: *JSGlobalObject, comptime enable_ansi_colors: bool)
- }
-
- pub fn deleteProperty(
- globalThis: js.JSContextRef,
- _: js.JSObjectRef,
- propertyName: js.JSStringRef,
- _: js.ExceptionRef,
- ) callconv(.C) bool {
- var jsc_vm = globalThis.bunVM();
- const allocator = jsc_vm.allocator;
-
- const zig_str = propertyName.toZigString();
-
- var str = zig_str.toSlice(allocator);
- defer str.deinit();
- const name = str.slice();
-
- if (jsc_vm.bundler.env.map.map.fetchSwapRemove(name)) |entry| {
- // this can be a statically allocated string
- if (bun.isHeapMemory(entry.value))
- allocator.free(bun.constStrToU8(entry.value));
-
- allocator.free(bun.constStrToU8(entry.key));
+ pub export fn Bun__getEnvValue(globalObject: *JSC.JSGlobalObject, name: *ZigString, value: *ZigString) bool {
+ if (getEnvValue(globalObject, name.*)) |val| {
+ value.* = val;
return true;
}
return false;
}
- pub fn setProperty(
- globalThis: js.JSContextRef,
- _: js.JSObjectRef,
- propertyName: js.JSStringRef,
- value: js.JSValueRef,
- _: js.ExceptionRef,
- ) callconv(.C) bool {
- var jsc_vm = globalThis.bunVM();
- const allocator = jsc_vm.allocator;
-
- const zig_str = propertyName.toZigString();
-
- var str = zig_str.toSlice(allocator);
- const name = str.slice();
- var entry = jsc_vm.bundler.env.map.map.getOrPut(name) catch return false;
- if (!entry.found_existing) {
- const value_str = value.?.value().toSlice(globalThis, allocator).cloneIfNeeded(allocator) catch return false;
- entry.key_ptr.* = (str.cloneIfNeeded(allocator) catch return false).slice();
-
- entry.value_ptr.* = value_str.slice();
- } else {
- defer str.deinit();
- // this can be a statically allocated string
- if (bun.isHeapMemory(entry.value_ptr.*))
- allocator.free(bun.constStrToU8(entry.value_ptr.*));
- const cloned_value = value.?.value().toSlice(globalThis, allocator).cloneIfNeeded(allocator) catch return false;
- entry.value_ptr.* = cloned_value.slice();
+ pub fn getEnvNames(globalObject: *JSC.JSGlobalObject, names: []ZigString) usize {
+ var vm = globalObject.bunVM();
+ const keys = vm.bundler.env.map.map.keys();
+ const max = @minimum(names.len, keys.len);
+ for (keys[0..max]) |key, i| {
+ names[i] = ZigString.initUTF8(key);
}
-
- return true;
+ return keys.len;
}
-
- pub fn getPropertyNames(
- _: js.JSContextRef,
- _: js.JSObjectRef,
- props: js.JSPropertyNameAccumulatorRef,
- ) callconv(.C) void {
- var iter = VirtualMachine.vm.bundler.env.map.iter();
-
- while (iter.next()) |item| {
- const str = item.key_ptr.*;
- var init_str = ZigString.init(str);
- init_str.markUTF8();
- js.JSPropertyNameAccumulatorAddName(props, JSC.C.OpaqueJSString.fromZigString(init_str, VirtualMachine.vm.allocator));
- }
+ pub fn getEnvValue(globalObject: *JSC.JSGlobalObject, name: ZigString) ?ZigString {
+ var vm = globalObject.bunVM();
+ var sliced = name.toSlice(vm.allocator);
+ defer sliced.deinit();
+ const value = vm.bundler.env.map.map.get(sliced.slice()) orelse return null;
+ return ZigString.initUTF8(value);
}
};
@@ -3478,6 +3319,8 @@ export fn Bun__reportError(_: *JSGlobalObject, err: JSC.JSValue) void {
comptime {
if (!is_bindgen) {
_ = Bun__reportError;
+ _ = EnvironmentVariables.Bun__getEnvNames;
+ _ = EnvironmentVariables.Bun__getEnvValue;
}
}
diff --git a/src/bun.js/bindings/JSEnvironmentVariableMap.cpp b/src/bun.js/bindings/JSEnvironmentVariableMap.cpp
new file mode 100644
index 000000000..75114d791
--- /dev/null
+++ b/src/bun.js/bindings/JSEnvironmentVariableMap.cpp
@@ -0,0 +1,71 @@
+#include "root.h"
+#include "ZigGlobalObject.h"
+
+#include "helpers.h"
+
+#include "JavaScriptCore/JSObject.h"
+#include "JavaScriptCore/ObjectConstructor.h"
+
+extern "C" size_t Bun__getEnvNames(JSGlobalObject*, ZigString* names, size_t max);
+extern "C" bool Bun__getEnvValue(JSGlobalObject* globalObject, ZigString* name, ZigString* value);
+
+namespace Bun {
+
+JSC_DEFINE_CUSTOM_GETTER(jsGetterEnvironmentVariable, (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());
+
+ ZigString name = gettoZigString(propertyName.publicName());
+ ZigString value = { nullptr, 0 };
+
+ if (UNLIKELY(name.len == 0))
+ return JSValue::encode(jsUndefined());
+
+ if (!Bun__getEnvValue(globalObject, &name, &value) || value.len == 0) {
+ return JSValue::encode(jsUndefined());
+ }
+
+ JSValue result = jsString(vm, Zig::toStringCopy(value));
+ thisObject->putDirect(vm, propertyName, result, 0);
+ return JSValue::encode(result);
+}
+
+JSC_DEFINE_CUSTOM_SETTER(jsSetterEnvironmentVariable, (JSGlobalObject * globalObject, EncodedJSValue thisValue, EncodedJSValue value, PropertyName propertyName))
+{
+ VM& vm = globalObject->vm();
+ JSC::JSObject* object = JSValue::decode(thisValue).getObject();
+ if (!object)
+ return false;
+
+ object->putDirect(vm, propertyName, JSValue::decode(value), 0);
+ return true;
+}
+
+JSValue createEnvironmentVariablesMap(Zig::GlobalObject* globalObject)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ size_t max = 768;
+ ZigString names[max];
+ size_t count = Bun__getEnvNames(globalObject, names, max);
+ JSC::JSObject* object = nullptr;
+ if (count < 63) {
+ object = constructEmptyObject(globalObject, globalObject->objectPrototype(), count);
+ } else {
+ object = constructEmptyObject(globalObject, globalObject->objectPrototype());
+ }
+
+ for (size_t i = 0; i < count; i++) {
+ auto name = Zig::toStringCopy(names[i]);
+ object->putDirectCustomAccessor(vm, Identifier::fromString(vm, name), JSC::CustomGetterSetter::create(vm, jsGetterEnvironmentVariable, jsSetterEnvironmentVariable), JSC::PropertyAttribute::CustomAccessor | 0);
+ }
+
+ return object;
+}
+} \ No newline at end of file
diff --git a/src/bun.js/bindings/JSEnvironmentVariableMap.h b/src/bun.js/bindings/JSEnvironmentVariableMap.h
new file mode 100644
index 000000000..7cc605303
--- /dev/null
+++ b/src/bun.js/bindings/JSEnvironmentVariableMap.h
@@ -0,0 +1,15 @@
+#include "root.h"
+
+namespace Zig {
+class GlobalObject;
+}
+
+namespace JSC {
+class JSValue;
+}
+
+namespace Bun {
+
+JSC::JSValue createEnvironmentVariablesMap(Zig::GlobalObject* globalObject);
+
+} \ No newline at end of file
diff --git a/src/bun.js/bindings/Process.cpp b/src/bun.js/bindings/Process.cpp
index 2071cfa05..07aabf343 100644
--- a/src/bun.js/bindings/Process.cpp
+++ b/src/bun.js/bindings/Process.cpp
@@ -5,6 +5,7 @@
#include <dlfcn.h>
#include "ZigGlobalObject.h"
#include "headers.h"
+#include "JSEnvironmentVariableMap.h"
#pragma mark - Node.js Process
@@ -292,6 +293,7 @@ void Process::finishCreation(JSC::VM& vm)
{
Base::finishCreation(vm);
auto clientData = WebCore::clientData(vm);
+ auto* globalObject = reinterpret_cast<Zig::GlobalObject*>(this->globalObject());
putDirectCustomAccessor(vm, clientData->builtinNames().pidPublicName(),
JSC::CustomGetterSetter::create(vm, Process_getPID, nullptr),
@@ -313,27 +315,27 @@ void Process::finishCreation(JSC::VM& vm)
JSC::jsString(vm, makeAtomString(Bun__version_sha)), 0);
this->putDirect(vm, clientData->builtinNames().nextTickPublicName(),
- JSC::JSFunction::create(vm, JSC::jsCast<JSC::JSGlobalObject*>(globalObject()), 1,
+ JSC::JSFunction::create(vm, globalObject, 1,
MAKE_STATIC_STRING_IMPL("nextTick"), Process_functionNextTick, ImplementationVisibility::Public),
PropertyAttribute::Function | 0);
this->putDirect(vm, JSC::Identifier::fromString(vm, "dlopen"_s),
- JSC::JSFunction::create(vm, JSC::jsCast<JSC::JSGlobalObject*>(globalObject()), 1,
+ JSC::JSFunction::create(vm, globalObject, 1,
MAKE_STATIC_STRING_IMPL("dlopen"), Process_functionDlopen, ImplementationVisibility::Public),
PropertyAttribute::Function | 0);
this->putDirect(vm, clientData->builtinNames().cwdPublicName(),
- JSC::JSFunction::create(vm, JSC::jsCast<JSC::JSGlobalObject*>(globalObject()), 0,
+ JSC::JSFunction::create(vm, globalObject, 0,
MAKE_STATIC_STRING_IMPL("cwd"), Process_functionCwd, ImplementationVisibility::Public),
PropertyAttribute::Function | 0);
this->putDirect(vm, clientData->builtinNames().chdirPublicName(),
- JSC::JSFunction::create(vm, JSC::jsCast<JSC::JSGlobalObject*>(globalObject()), 0,
+ JSC::JSFunction::create(vm, globalObject, 0,
MAKE_STATIC_STRING_IMPL("chdir"), Process_functionChdir, ImplementationVisibility::Public),
PropertyAttribute::Function | 0);
this->putDirect(vm, JSC::Identifier::fromString(vm, "exit"_s),
- JSC::JSFunction::create(vm, JSC::jsCast<JSC::JSGlobalObject*>(globalObject()), 0,
+ JSC::JSFunction::create(vm, globalObject, 0,
MAKE_STATIC_STRING_IMPL("exit"), Process_functionExit, ImplementationVisibility::Public),
PropertyAttribute::Function | 0);
@@ -376,10 +378,10 @@ void Process::finishCreation(JSC::VM& vm)
JSC::jsString(this->vm(), makeAtomString("arm64")));
#endif
- JSC::JSFunction* hrtime = JSC::JSFunction::create(vm, JSC::jsCast<JSC::JSGlobalObject*>(globalObject()), 0,
+ JSC::JSFunction* hrtime = JSC::JSFunction::create(vm, globalObject, 0,
MAKE_STATIC_STRING_IMPL("hrtime"), Process_functionHRTime, ImplementationVisibility::Public);
- JSC::JSFunction* hrtimeBigInt = JSC::JSFunction::create(vm, JSC::jsCast<JSC::JSGlobalObject*>(globalObject()), 0,
+ JSC::JSFunction* hrtimeBigInt = JSC::JSFunction::create(vm, globalObject, 0,
MAKE_STATIC_STRING_IMPL("bigint"), Process_functionHRTimeBigInt, ImplementationVisibility::Public);
hrtime->putDirect(vm, JSC::Identifier::fromString(vm, "bigint"_s), hrtimeBigInt);
diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp
index d79048ea3..6d20a63d2 100644
--- a/src/bun.js/bindings/ZigGlobalObject.cpp
+++ b/src/bun.js/bindings/ZigGlobalObject.cpp
@@ -2462,13 +2462,7 @@ void GlobalObject::finishCreation(VM& vm)
m_processEnvObject.initLater(
[](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::JSObject>::Initializer& init) {
- auto jsClass = reinterpret_cast<Zig::GlobalObject*>(init.owner)->m_dotEnvClassRef;
-
- JSC::JSCallbackObject<JSNonFinalObject>* object = JSC::JSCallbackObject<JSNonFinalObject>::create(
- init.owner, init.owner->callbackObjectStructure(), jsClass, nullptr);
- if (JSObject* prototype = jsClass->prototype(init.owner))
- object->setPrototypeDirect(init.vm, prototype);
- init.set(object);
+ init.set(Bun::createEnvironmentVariablesMap(reinterpret_cast<Zig::GlobalObject*>(init.owner)).getObject());
});
m_processObject.initLater(
@@ -3177,6 +3171,16 @@ void GlobalObject::installAPIGlobals(JSClassRef* globals, int count, JSC::VM& vm
{
+ JSC::Identifier identifier = JSC::Identifier::fromString(vm, "env"_s);
+ object->putDirectCustomAccessor(vm, identifier,
+ JSC::CustomGetterSetter::create(vm, lazyProcessEnvGetter, lazyProcessEnvSetter),
+ JSC::PropertyAttribute::DontDelete
+ | JSC::PropertyAttribute::CustomValue
+ | 0);
+ }
+
+ {
+
JSC::Identifier identifier = JSC::Identifier::fromString(vm, pathToFileURLString);
object->putDirectNativeFunction(vm, this, identifier, 1, functionPathToFileURL, ImplementationVisibility::Public, NoIntrinsic,
JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly);
diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h
index 1aee587cf..30749b4ce 100644
--- a/src/bun.js/bindings/ZigGlobalObject.h
+++ b/src/bun.js/bindings/ZigGlobalObject.h
@@ -26,6 +26,7 @@ class EventLoopTask;
#include "JavaScriptCore/JSTypeInfo.h"
#include "JavaScriptCore/Structure.h"
#include "WebCoreJSBuiltinInternals.h"
+#include "JSEnvironmentVariableMap.h"
#include "ZigConsoleClient.h"
diff --git a/src/bun.js/bindings/exports.zig b/src/bun.js/bindings/exports.zig
index dac30b344..92f269752 100644
--- a/src/bun.js/bindings/exports.zig
+++ b/src/bun.js/bindings/exports.zig
@@ -1352,16 +1352,6 @@ pub const ZigConsoleClient = struct {
const callable = js_type != .Object and value.isCallable(globalThis.vm());
if (value.isClass(globalThis) and !callable) {
- // Temporary workaround
- // console.log(process.env) shows up as [class JSCallbackObject]
- // We want to print it like an object
- if (CAPI.JSValueIsObjectOfClass(globalThis, value.asObjectRef(), JSC.API.Bun.EnvironmentVariables.Class.get().?[0])) {
- return .{
- .tag = .Object,
- .cell = js_type,
- };
- }
-
return .{
.tag = .Object,
.cell = js_type,
diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig
index 7e4ae9ed5..900f42ea1 100644
--- a/src/bun.js/javascript.zig
+++ b/src/bun.js/javascript.zig
@@ -109,9 +109,6 @@ pub const GlobalClasses = [_]type{
WebCore.Alert.Class,
WebCore.Confirm.Class,
WebCore.Prompt.Class,
-
- // The last item in this array becomes "process.env"
- Bun.EnvironmentVariables.Class,
};
const TaggedPointerUnion = @import("../tagged_pointer.zig").TaggedPointerUnion;
const Task = JSC.Task;