From 68cb6130d3e4bd25a53c959db9108a68f5268298 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Wed, 2 Feb 2022 18:02:06 -0800 Subject: "path" module from Node.js implementation --- src/javascript/jsc/bindings/BunBuiltinNames.h | 14 + src/javascript/jsc/bindings/Path.cpp | 182 +++++++++++ src/javascript/jsc/bindings/Path.h | 43 +++ src/javascript/jsc/bindings/ZigGlobalObject.cpp | 5 + src/javascript/jsc/bindings/bindings.zig | 62 ++++ src/javascript/jsc/bindings/exports.zig | 3 + src/javascript/jsc/bindings/headers-cpp.h | 16 +- src/javascript/jsc/bindings/headers.h | 21 +- src/javascript/jsc/bindings/headers.zig | 1 + src/javascript/jsc/javascript.zig | 32 +- src/javascript/jsc/node/types.zig | 402 +++++++++++++++++++++++- src/javascript/jsc/path.exports.js | 56 ++++ src/linker.zig | 7 + src/pool.zig | 2 +- src/resolver/resolve_path.zig | 41 ++- 15 files changed, 875 insertions(+), 12 deletions(-) create mode 100644 src/javascript/jsc/bindings/Path.cpp create mode 100644 src/javascript/jsc/bindings/Path.h create mode 100644 src/javascript/jsc/path.exports.js diff --git a/src/javascript/jsc/bindings/BunBuiltinNames.h b/src/javascript/jsc/bindings/BunBuiltinNames.h index 7a666df61..86b5a8675 100644 --- a/src/javascript/jsc/bindings/BunBuiltinNames.h +++ b/src/javascript/jsc/bindings/BunBuiltinNames.h @@ -56,6 +56,20 @@ using namespace JSC; macro(unshift) \ macro(resume) \ macro(pause) \ + macro(basename) \ + macro(dirname) \ + macro(file) \ + macro(extname) \ + macro(format) \ + macro(isAbsolute) \ + macro(join) \ + macro(normalize) \ + macro(parse) \ + macro(relative) \ + macro(resolve) \ + macro(sep) \ + macro(delimiter) \ + macro(toNamespacedPath) \ BUN_ADDITIONAL_PRIVATE_IDENTIFIERS(macro) \ class BunBuiltinNames { diff --git a/src/javascript/jsc/bindings/Path.cpp b/src/javascript/jsc/bindings/Path.cpp new file mode 100644 index 000000000..a158beaa8 --- /dev/null +++ b/src/javascript/jsc/bindings/Path.cpp @@ -0,0 +1,182 @@ +#include "Path.h" +#include +#include + +#pragma mark - Node.js Path + +extern JSC__JSValue Bun__Path__create(JSC::JSGlobalObject *globalObject, bool isWindows) { + JSC::VM &vm = globalObject->vm(); + + return JSC::JSValue::encode(JSC::JSValue(Zig::Path::create( + vm, isWindows, Zig::Path::createStructure(vm, globalObject, globalObject->objectPrototype())))); +} + +namespace Zig { + +using JSGlobalObject = JSC::JSGlobalObject; +using Exception = JSC::Exception; +using JSValue = JSC::JSValue; +using JSString = JSC::JSString; +using JSModuleLoader = JSC::JSModuleLoader; +using JSModuleRecord = JSC::JSModuleRecord; +using Identifier = JSC::Identifier; +using SourceOrigin = JSC::SourceOrigin; +using JSObject = JSC::JSObject; +using JSNonFinalObject = JSC::JSNonFinalObject; +namespace JSCastingHelpers = JSC::JSCastingHelpers; + +// clang-format off +#define DEFINE_CALLBACK_FUNCTION_BODY(ZigFunction) JSC::VM& vm = globalObject->vm(); \ + auto* thisObject = JSC::jsDynamicCast(vm, callFrame->thisValue()); \ + auto scope = DECLARE_THROW_SCOPE(vm); \ + if (!thisObject) \ + return throwVMTypeError(globalObject, scope); \ + auto argCount = static_cast(callFrame->argumentCount()); \ + WTF::Vector arguments; \ + arguments.reserveInitialCapacity(argCount); \ + if (argCount) { \ + for (uint16_t i = 0; i < argCount; ++i) { \ + arguments.uncheckedAppend(JSC::JSValue::encode(callFrame->uncheckedArgument(i))); \ + } \ + } \ + JSC::JSValue result = JSC::JSValue::decode( \ + ZigFunction(globalObject, thisObject->isWindows, arguments.data(), argCount) \ + ); \ + JSC::JSObject *obj = result.getObject(); \ + if (UNLIKELY(obj != nullptr && obj->isErrorInstance())) { \ + scope.throwException(globalObject, obj); \ + return JSC::JSValue::encode(JSC::jsUndefined()); \ + } \ + if (UNLIKELY(scope.exception())) \ + return JSC::JSValue::encode(JSC::jsUndefined()); \ + return JSC::JSValue::encode(result); + +// clang-format on + +static JSC_DECLARE_HOST_FUNCTION(Path_functionBasename); +static JSC_DEFINE_HOST_FUNCTION(Path_functionBasename, + (JSC::JSGlobalObject * globalObject, JSC::CallFrame *callFrame)) { + DEFINE_CALLBACK_FUNCTION_BODY(Bun__Path__basename); +} + +static JSC_DECLARE_HOST_FUNCTION(Path_functionDirname); +static JSC_DEFINE_HOST_FUNCTION(Path_functionDirname, + (JSC::JSGlobalObject * globalObject, JSC::CallFrame *callFrame)) { + DEFINE_CALLBACK_FUNCTION_BODY(Bun__Path__dirname); +} +static JSC_DECLARE_HOST_FUNCTION(Path_functionExtname); +static JSC_DEFINE_HOST_FUNCTION(Path_functionExtname, + (JSC::JSGlobalObject * globalObject, JSC::CallFrame *callFrame)) { + DEFINE_CALLBACK_FUNCTION_BODY(Bun__Path__extname); +} +static JSC_DECLARE_HOST_FUNCTION(Path_functionFormat); +static JSC_DEFINE_HOST_FUNCTION(Path_functionFormat, + (JSC::JSGlobalObject * globalObject, JSC::CallFrame *callFrame)) { + DEFINE_CALLBACK_FUNCTION_BODY(Bun__Path__format); +} +static JSC_DECLARE_HOST_FUNCTION(Path_functionIsAbsolute); +static JSC_DEFINE_HOST_FUNCTION(Path_functionIsAbsolute, + (JSC::JSGlobalObject * globalObject, JSC::CallFrame *callFrame)) { + DEFINE_CALLBACK_FUNCTION_BODY(Bun__Path__isAbsolute); +} +static JSC_DECLARE_HOST_FUNCTION(Path_functionJoin); +static JSC_DEFINE_HOST_FUNCTION(Path_functionJoin, + (JSC::JSGlobalObject * globalObject, JSC::CallFrame *callFrame)) { + DEFINE_CALLBACK_FUNCTION_BODY(Bun__Path__join); +} +static JSC_DECLARE_HOST_FUNCTION(Path_functionNormalize); +static JSC_DEFINE_HOST_FUNCTION(Path_functionNormalize, + (JSC::JSGlobalObject * globalObject, JSC::CallFrame *callFrame)) { + DEFINE_CALLBACK_FUNCTION_BODY(Bun__Path__normalize); +} +static JSC_DECLARE_HOST_FUNCTION(Path_functionParse); +static JSC_DEFINE_HOST_FUNCTION(Path_functionParse, + (JSC::JSGlobalObject * globalObject, JSC::CallFrame *callFrame)) { + DEFINE_CALLBACK_FUNCTION_BODY(Bun__Path__parse); +} +static JSC_DECLARE_HOST_FUNCTION(Path_functionRelative); +static JSC_DEFINE_HOST_FUNCTION(Path_functionRelative, + (JSC::JSGlobalObject * globalObject, JSC::CallFrame *callFrame)) { + DEFINE_CALLBACK_FUNCTION_BODY(Bun__Path__relative); +} +static JSC_DECLARE_HOST_FUNCTION(Path_functionResolve); +static JSC_DEFINE_HOST_FUNCTION(Path_functionResolve, + (JSC::JSGlobalObject * globalObject, JSC::CallFrame *callFrame)) { + DEFINE_CALLBACK_FUNCTION_BODY(Bun__Path__resolve); +} +static JSC_DECLARE_HOST_FUNCTION(Path_functionToNamespacedPath); +static JSC_DEFINE_HOST_FUNCTION(Path_functionToNamespacedPath, + (JSC::JSGlobalObject * globalObject, JSC::CallFrame *callFrame)) { + auto argCount = static_cast(callFrame->argumentCount()); + // TODO: + return JSC::JSValue::encode(callFrame->argument(0)); +} + +void Path::finishCreation(JSC::VM &vm) { + Base::finishCreation(vm); + auto clientData = Bun::clientData(vm); + + JSC::JSGlobalObject *globalThis = globalObject(); + this->putDirect(vm, clientData->builtinNames().basenamePublicName(), + JSC::JSFunction::create(vm, JSC::jsCast(globalThis), 0, + WTF::String("basename"), Path_functionBasename), + 0); + this->putDirect(vm, clientData->builtinNames().dirnamePublicName(), + JSC::JSFunction::create(vm, JSC::jsCast(globalThis), 0, + WTF::String("dirname"), Path_functionDirname), + 0); + this->putDirect(vm, clientData->builtinNames().extnamePublicName(), + JSC::JSFunction::create(vm, JSC::jsCast(globalThis), 0, + WTF::String("extname"), Path_functionExtname), + 0); + this->putDirect(vm, clientData->builtinNames().formatPublicName(), + JSC::JSFunction::create(vm, JSC::jsCast(globalThis), 0, + WTF::String("format"), Path_functionFormat), + 0); + this->putDirect(vm, clientData->builtinNames().isAbsolutePublicName(), + JSC::JSFunction::create(vm, JSC::jsCast(globalThis), 0, + WTF::String("isAbsolute"), Path_functionIsAbsolute), + 0); + this->putDirect(vm, clientData->builtinNames().joinPublicName(), + JSC::JSFunction::create(vm, JSC::jsCast(globalThis), 0, + WTF::String("join"), Path_functionJoin), + 0); + this->putDirect(vm, clientData->builtinNames().normalizePublicName(), + JSC::JSFunction::create(vm, JSC::jsCast(globalThis), 0, + WTF::String("normalize"), Path_functionNormalize), + 0); + this->putDirect(vm, clientData->builtinNames().parsePublicName(), + JSC::JSFunction::create(vm, JSC::jsCast(globalThis), 0, + WTF::String("parse"), Path_functionParse), + 0); + this->putDirect(vm, clientData->builtinNames().relativePublicName(), + JSC::JSFunction::create(vm, JSC::jsCast(globalThis), 0, + WTF::String("relative"), Path_functionRelative), + 0); + this->putDirect(vm, clientData->builtinNames().resolvePublicName(), + JSC::JSFunction::create(vm, JSC::jsCast(globalThis), 0, + WTF::String("resolve"), Path_functionResolve), + 0); + + this->putDirect(vm, clientData->builtinNames().toNamespacedPathPublicName(), + JSC::JSFunction::create(vm, JSC::jsCast(globalThis), 0, + WTF::String("toNamespacedPath"), + Path_functionToNamespacedPath), + 0); + + if (isWindows) { + this->putDirect(vm, clientData->builtinNames().sepPublicName(), + JSC::jsString(vm, WTF::String("\\"_s)), 0); + this->putDirect(vm, clientData->builtinNames().delimiterPublicName(), + JSC::jsString(vm, WTF::String(";"_s)), 0); + } else { + this->putDirect(vm, clientData->builtinNames().sepPublicName(), + JSC::jsString(vm, WTF::String("/"_s)), 0); + this->putDirect(vm, clientData->builtinNames().delimiterPublicName(), + JSC::jsString(vm, WTF::String(":"_s)), 0); + } +} + +const JSC::ClassInfo Path::s_info = {"Path", &Base::s_info, nullptr, nullptr, + CREATE_METHOD_TABLE(Path)}; +} // namespace Zig \ No newline at end of file diff --git a/src/javascript/jsc/bindings/Path.h b/src/javascript/jsc/bindings/Path.h new file mode 100644 index 000000000..546a542a6 --- /dev/null +++ b/src/javascript/jsc/bindings/Path.h @@ -0,0 +1,43 @@ +#pragma once + +#include "BunBuiltinNames.h" +#include "BunClientData.h" +#include "root.h" + +namespace Zig { + +class Path : public JSC::JSNonFinalObject { + using Base = JSC::JSNonFinalObject; + + public: + Path(JSC::VM &vm, JSC::Structure *structure, bool isWindows_) : Base(vm, structure) { + isWindows = isWindows_; + } + + DECLARE_INFO; + + static constexpr unsigned StructureFlags = Base::StructureFlags; + + template + static JSC::CompleteSubspace *subspaceFor(JSC::VM &vm) { + return &vm.cellSpace; + } + + static JSC::Structure *createStructure(JSC::VM &vm, JSC::JSGlobalObject *globalObject, + JSC::JSValue prototype) { + return JSC::Structure::create(vm, globalObject, prototype, + JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); + } + + static Path *create(JSC::VM &vm, bool isWindows, JSC::Structure *structure) { + Path *accessor = new (NotNull, JSC::allocateCell(vm.heap)) Path(vm, structure, isWindows); + + accessor->finishCreation(vm); + return accessor; + } + bool isWindows = false; + + void finishCreation(JSC::VM &vm); +}; + +} // namespace Zig \ No newline at end of file diff --git a/src/javascript/jsc/bindings/ZigGlobalObject.cpp b/src/javascript/jsc/bindings/ZigGlobalObject.cpp index 43a106c2d..3bd4eccce 100644 --- a/src/javascript/jsc/bindings/ZigGlobalObject.cpp +++ b/src/javascript/jsc/bindings/ZigGlobalObject.cpp @@ -500,8 +500,13 @@ JSC::JSObject *GlobalObject::moduleLoaderCreateImportMetaProperties(JSGlobalObje if (index != WTF::notFound) { metaProperties->putDirect(vm, clientData->builtinNames().dirPublicName(), JSC::jsSubstring(globalObject, keyString, 0, index)); + metaProperties->putDirect( + vm, clientData->builtinNames().filePublicName(), + JSC::jsSubstring(globalObject, keyString, index + 1, keyString->length() - index - 1)); } + metaProperties->putDirect(vm, clientData->builtinNames().pathPublicName(), key); + RETURN_IF_EXCEPTION(scope, nullptr); // metaProperties->putDirect(vm, Identifier::fromString(vm, "resolve"), diff --git a/src/javascript/jsc/bindings/bindings.zig b/src/javascript/jsc/bindings/bindings.zig index c3e2314f5..63f3d36ac 100644 --- a/src/javascript/jsc/bindings/bindings.zig +++ b/src/javascript/jsc/bindings/bindings.zig @@ -89,6 +89,27 @@ pub const ZigString = extern struct { pub const shim = Shimmer("", "ZigString", @This()); + pub const Slice = struct { + allocator: std.mem.Allocator, + ptr: [*]const u8, + len: u32, + allocated: bool = false, + + pub const empty = Slice{ .allocator = _global.default_allocator, .ptr = undefined, .len = 0, .allocated = false }; + + pub fn slice(this: Slice) []const u8 { + return this.ptr[0..this.len]; + } + + pub fn deinit(this: *Slice) void { + if (!this.allocated) { + return; + } + + this.allocator.free(this.slice()); + } + }; + pub const name = "ZigString"; pub const namespace = ""; @@ -100,6 +121,10 @@ pub const ZigString = extern struct { return @ptrCast([*]align(1) const u16, untagged(this.ptr))[0..this.len]; } + pub inline fn isEmpty(this: *const ZigString) bool { + return this.len == 0; + } + pub fn fromStringPointer(ptr: StringPointer, buf: string, to: *ZigString) void { to.* = ZigString{ .len = ptr.length, @@ -173,6 +198,25 @@ pub const ZigString = extern struct { return untagged(this.ptr)[0..@minimum(this.len, std.math.maxInt(u32))]; } + pub fn toSlice(this: ZigString, allocator: std.mem.Allocator) Slice { + if (is16Bit(&this)) { + var buffer = std.fmt.allocPrint(allocator, "{}", .{this}) catch unreachable; + return Slice{ + .ptr = buffer.ptr, + .len = @truncate(u32, buffer.len), + .allocated = true, + .allocator = allocator, + }; + } + + return Slice{ + .ptr = untagged(this.ptr), + .len = @truncate(u32, this.len), + .allocated = false, + .allocator = allocator, + }; + } + pub fn sliceZBuf(this: ZigString, buf: *[std.fs.MAX_PATH_BYTES]u8) ![:0]const u8 { return try std.fmt.bufPrintZ(buf, "{}", .{this}); } @@ -1509,6 +1553,20 @@ pub const JSValue = enum(i64) { return @intToEnum(JSValue, @intCast(i64, @ptrToInt(ptr))); } + pub const Formatter = struct { + value: JSValue, + global: *JSGlobalObject, + + pub fn format(formatter: Formatter, comptime fmt: []const u8, opts: fmt.FormatOptions, writer: anytype) !void { + const self = formatter.value; + const kind = jsType(self); + if (kind.isStringLike()) { + var zig_str = self.getZigString(); + return try zig_str.format(fmt, opts, writer); + } + } + }; + pub fn to(this: JSValue, comptime T: type) T { return switch (comptime T) { u32 => toU32(this), @@ -1771,6 +1829,10 @@ pub const JSValue = enum(i64) { return str; } + pub inline fn toSlice(this: JSValue, global: *JSGlobalObject, allocator: std.mem.Allocator) ZigString.Slice { + return getZigString(this, global).toSlice(allocator); + } + // On exception, this returns the empty string. pub fn toString(this: JSValue, globalThis: *JSGlobalObject) *JSString { return cppFn("toString", .{ this, globalThis }); diff --git a/src/javascript/jsc/bindings/exports.zig b/src/javascript/jsc/bindings/exports.zig index 26ba4cd3c..ebf6ce47f 100644 --- a/src/javascript/jsc/bindings/exports.zig +++ b/src/javascript/jsc/bindings/exports.zig @@ -177,6 +177,8 @@ pub const NodeReadableStream = JSC.Node.Readable.State; /// do not use this reference directly, use JSC.Node.Writable pub const NodeWritableStream = JSC.Node.Writable.State; +pub const NodePath = JSC.Node.Path; + pub fn Errorable(comptime Type: type) type { return extern struct { result: Result, @@ -1824,5 +1826,6 @@ comptime { _ = Process.setTitle; std.testing.refAllDecls(NodeReadableStream); std.testing.refAllDecls(NodeWritableStream); + std.testing.refAllDecls(NodePath); } } diff --git a/src/javascript/jsc/bindings/headers-cpp.h b/src/javascript/jsc/bindings/headers-cpp.h index 2ba13ed1d..81ff30331 100644 --- a/src/javascript/jsc/bindings/headers-cpp.h +++ b/src/javascript/jsc/bindings/headers-cpp.h @@ -1,4 +1,4 @@ -//-- AUTOGENERATED FILE -- 1642736709 +//-- AUTOGENERATED FILE -- 1643849682 // clang-format off #pragma once @@ -232,6 +232,14 @@ extern "C" const size_t Bun__Readable_object_align_ = alignof(Bun__Readable); extern "C" const size_t Bun__Writable_object_size_ = sizeof(Bun__Writable); extern "C" const size_t Bun__Writable_object_align_ = alignof(Bun__Writable); +#ifndef INCLUDED_Path_h +#define INCLUDED_Path_h +#include Path.h +#endif + +extern "C" const size_t Bun__Path_object_size_ = sizeof(Bun__Path); +extern "C" const size_t Bun__Path_object_align_ = alignof(Bun__Path); + #ifndef INCLUDED__ZigConsoleClient_h_ #define INCLUDED__ZigConsoleClient_h_ #include "ZigConsoleClient.h" @@ -240,8 +248,8 @@ extern "C" const size_t Bun__Writable_object_align_ = alignof(Bun__Writable); extern "C" const size_t Zig__ConsoleClient_object_size_ = sizeof(Zig::ConsoleClient); extern "C" const size_t Zig__ConsoleClient_object_align_ = alignof(Zig::ConsoleClient); -const size_t sizes[29] = {sizeof(JSC::JSObject), sizeof(SystemError), sizeof(JSC::JSCell), sizeof(JSC::JSString), sizeof(Inspector::ScriptArguments), sizeof(JSC::JSModuleLoader), sizeof(JSC::JSModuleRecord), sizeof(JSC::JSPromise), sizeof(JSC::JSInternalPromise), sizeof(JSC::SourceOrigin), sizeof(JSC::SourceCode), sizeof(JSC::JSFunction), sizeof(JSC::JSGlobalObject), sizeof(WTF::URL), sizeof(WTF::String), sizeof(JSC::JSValue), sizeof(JSC::PropertyName), sizeof(JSC::Exception), sizeof(JSC::VM), sizeof(JSC::ThrowScope), sizeof(JSC::CatchScope), sizeof(JSC::CallFrame), sizeof(JSC::Identifier), sizeof(WTF::StringImpl), sizeof(WTF::ExternalStringImpl), sizeof(WTF::StringView), sizeof(Zig::GlobalObject), sizeof(Bun__Readable), sizeof(Bun__Writable)}; +const size_t sizes[30] = {sizeof(JSC::JSObject), sizeof(SystemError), sizeof(JSC::JSCell), sizeof(JSC::JSString), sizeof(Inspector::ScriptArguments), sizeof(JSC::JSModuleLoader), sizeof(JSC::JSModuleRecord), sizeof(JSC::JSPromise), sizeof(JSC::JSInternalPromise), sizeof(JSC::SourceOrigin), sizeof(JSC::SourceCode), sizeof(JSC::JSFunction), sizeof(JSC::JSGlobalObject), sizeof(WTF::URL), sizeof(WTF::String), sizeof(JSC::JSValue), sizeof(JSC::PropertyName), sizeof(JSC::Exception), sizeof(JSC::VM), sizeof(JSC::ThrowScope), sizeof(JSC::CatchScope), sizeof(JSC::CallFrame), sizeof(JSC::Identifier), sizeof(WTF::StringImpl), sizeof(WTF::ExternalStringImpl), sizeof(WTF::StringView), sizeof(Zig::GlobalObject), sizeof(Bun__Readable), sizeof(Bun__Writable), sizeof(Bun__Path)}; -const char* names[29] = {"JSC__JSObject", "SystemError", "JSC__JSCell", "JSC__JSString", "Inspector__ScriptArguments", "JSC__JSModuleLoader", "JSC__JSModuleRecord", "JSC__JSPromise", "JSC__JSInternalPromise", "JSC__SourceOrigin", "JSC__SourceCode", "JSC__JSFunction", "JSC__JSGlobalObject", "WTF__URL", "WTF__String", "JSC__JSValue", "JSC__PropertyName", "JSC__Exception", "JSC__VM", "JSC__ThrowScope", "JSC__CatchScope", "JSC__CallFrame", "JSC__Identifier", "WTF__StringImpl", "WTF__ExternalStringImpl", "WTF__StringView", "Zig__GlobalObject", "Bun__Readable", "Bun__Writable"}; +const char* names[30] = {"JSC__JSObject", "SystemError", "JSC__JSCell", "JSC__JSString", "Inspector__ScriptArguments", "JSC__JSModuleLoader", "JSC__JSModuleRecord", "JSC__JSPromise", "JSC__JSInternalPromise", "JSC__SourceOrigin", "JSC__SourceCode", "JSC__JSFunction", "JSC__JSGlobalObject", "WTF__URL", "WTF__String", "JSC__JSValue", "JSC__PropertyName", "JSC__Exception", "JSC__VM", "JSC__ThrowScope", "JSC__CatchScope", "JSC__CallFrame", "JSC__Identifier", "WTF__StringImpl", "WTF__ExternalStringImpl", "WTF__StringView", "Zig__GlobalObject", "Bun__Readable", "Bun__Writable", "Bun__Path"}; -const size_t aligns[29] = {alignof(JSC::JSObject), alignof(SystemError), alignof(JSC::JSCell), alignof(JSC::JSString), alignof(Inspector::ScriptArguments), alignof(JSC::JSModuleLoader), alignof(JSC::JSModuleRecord), alignof(JSC::JSPromise), alignof(JSC::JSInternalPromise), alignof(JSC::SourceOrigin), alignof(JSC::SourceCode), alignof(JSC::JSFunction), alignof(JSC::JSGlobalObject), alignof(WTF::URL), alignof(WTF::String), alignof(JSC::JSValue), alignof(JSC::PropertyName), alignof(JSC::Exception), alignof(JSC::VM), alignof(JSC::ThrowScope), alignof(JSC::CatchScope), alignof(JSC::CallFrame), alignof(JSC::Identifier), alignof(WTF::StringImpl), alignof(WTF::ExternalStringImpl), alignof(WTF::StringView), alignof(Zig::GlobalObject), alignof(Bun__Readable), alignof(Bun__Writable)}; +const size_t aligns[30] = {alignof(JSC::JSObject), alignof(SystemError), alignof(JSC::JSCell), alignof(JSC::JSString), alignof(Inspector::ScriptArguments), alignof(JSC::JSModuleLoader), alignof(JSC::JSModuleRecord), alignof(JSC::JSPromise), alignof(JSC::JSInternalPromise), alignof(JSC::SourceOrigin), alignof(JSC::SourceCode), alignof(JSC::JSFunction), alignof(JSC::JSGlobalObject), alignof(WTF::URL), alignof(WTF::String), alignof(JSC::JSValue), alignof(JSC::PropertyName), alignof(JSC::Exception), alignof(JSC::VM), alignof(JSC::ThrowScope), alignof(JSC::CatchScope), alignof(JSC::CallFrame), alignof(JSC::Identifier), alignof(WTF::StringImpl), alignof(WTF::ExternalStringImpl), alignof(WTF::StringView), alignof(Zig::GlobalObject), alignof(Bun__Readable), alignof(Bun__Writable), alignof(Bun__Path)}; diff --git a/src/javascript/jsc/bindings/headers.h b/src/javascript/jsc/bindings/headers.h index 31ccc29ea..b8934c1a0 100644 --- a/src/javascript/jsc/bindings/headers.h +++ b/src/javascript/jsc/bindings/headers.h @@ -1,5 +1,5 @@ // clang-format: off -//-- AUTOGENERATED FILE -- 1642736709 +//-- AUTOGENERATED FILE -- 1643849682 #pragma once #include @@ -671,6 +671,25 @@ ZIG_DECL JSC__JSValue Bun__Writable__write(Bun__Writable* arg0, JSC__JSGlobalObj #endif +#pragma mark - Bun__Path + +CPP_DECL JSC__JSValue Bun__Path__create(JSC__JSGlobalObject* arg0, bool arg1); + +#ifdef __cplusplus + +ZIG_DECL JSC__JSValue Bun__Path__basename(JSC__JSGlobalObject* arg0, bool arg1, JSC__JSValue* arg2, uint16_t arg3); +ZIG_DECL JSC__JSValue Bun__Path__dirname(JSC__JSGlobalObject* arg0, bool arg1, JSC__JSValue* arg2, uint16_t arg3); +ZIG_DECL JSC__JSValue Bun__Path__extname(JSC__JSGlobalObject* arg0, bool arg1, JSC__JSValue* arg2, uint16_t arg3); +ZIG_DECL JSC__JSValue Bun__Path__format(JSC__JSGlobalObject* arg0, bool arg1, JSC__JSValue* arg2, uint16_t arg3); +ZIG_DECL JSC__JSValue Bun__Path__isAbsolute(JSC__JSGlobalObject* arg0, bool arg1, JSC__JSValue* arg2, uint16_t arg3); +ZIG_DECL JSC__JSValue Bun__Path__join(JSC__JSGlobalObject* arg0, bool arg1, JSC__JSValue* arg2, uint16_t arg3); +ZIG_DECL JSC__JSValue Bun__Path__normalize(JSC__JSGlobalObject* arg0, bool arg1, JSC__JSValue* arg2, uint16_t arg3); +ZIG_DECL JSC__JSValue Bun__Path__parse(JSC__JSGlobalObject* arg0, bool arg1, JSC__JSValue* arg2, uint16_t arg3); +ZIG_DECL JSC__JSValue Bun__Path__relative(JSC__JSGlobalObject* arg0, bool arg1, JSC__JSValue* arg2, uint16_t arg3); +ZIG_DECL JSC__JSValue Bun__Path__resolve(JSC__JSGlobalObject* arg0, bool arg1, JSC__JSValue* arg2, uint16_t arg3); + +#endif + #ifdef __cplusplus ZIG_DECL JSC__JSValue Bun__Process__getArgv(JSC__JSGlobalObject* arg0); diff --git a/src/javascript/jsc/bindings/headers.zig b/src/javascript/jsc/bindings/headers.zig index 9b637f427..c832d8af5 100644 --- a/src/javascript/jsc/bindings/headers.zig +++ b/src/javascript/jsc/bindings/headers.zig @@ -425,4 +425,5 @@ pub extern fn Zig__GlobalObject__getModuleRegistryMap(arg0: [*c]JSC__JSGlobalObj pub extern fn Zig__GlobalObject__resetModuleRegistryMap(arg0: [*c]JSC__JSGlobalObject, arg1: ?*anyopaque) bool; pub extern fn Bun__Readable__create(arg0: [*c]Bun__Readable, arg1: [*c]JSC__JSGlobalObject) JSC__JSValue; pub extern fn Bun__Writable__create(arg0: [*c]Bun__Writable, arg1: [*c]JSC__JSGlobalObject) JSC__JSValue; +pub extern fn Bun__Path__create(arg0: [*c]JSC__JSGlobalObject, arg1: bool) JSC__JSValue; pub extern fn ZigException__fromException(arg0: [*c]JSC__Exception) ZigException; diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig index fcbc532ca..014e5bc75 100644 --- a/src/javascript/jsc/javascript.zig +++ b/src/javascript/jsc/javascript.zig @@ -356,6 +356,18 @@ pub const Bun = struct { return JSValue.createStringArray(ctx.ptr(), styles.ptr, styles.len, true).asRef(); } + pub fn newPath( + _: void, + ctx: js.JSContextRef, + _: js.JSObjectRef, + _: js.JSObjectRef, + args: []const js.JSValueRef, + _: js.ExceptionRef, + ) js.JSValueRef { + const is_windows = args.len == 1 and JSValue.fromRef(args[0]).toBoolean(); + return Node.Path.create(ctx.ptr(), is_windows).asObjectRef(); + } + pub fn readFileAsStringCallback( ctx: js.JSContextRef, buf_z: [:0]const u8, @@ -705,6 +717,10 @@ pub const Bun = struct { .@"return" = "string[]", }, }, + ._Path = .{ + .rfn = Bun.newPath, + .ts = d.ts{}, + }, .getRouteNames = .{ .rfn = Bun.getRouteNames, .ts = d.ts{ @@ -1596,6 +1612,15 @@ pub const VirtualMachine = struct { .hash = 0, .bytecodecache_fd = 0, }; + } else if (strings.eqlComptime(_specifier, "node:path")) { + return ResolvedSource{ + .allocator = null, + .source_code = ZigString.init(Node.Path.code), + .specifier = ZigString.init("node:path"), + .source_url = ZigString.init("node:path"), + .hash = 0, + .bytecodecache_fd = 0, + }; } const specifier = normalizeSpecifier(_specifier); @@ -1746,11 +1771,16 @@ pub const VirtualMachine = struct { ret.result = null; ret.path = specifier; return; - } else if (strings.eqlComptime(specifier, "fs") or strings.eqlComptime(specifier, "node:fs")) { + } else if (strings.eqlComptime(specifier, "node:fs")) { ret.result = null; ret.path = "node:fs"; return; } + if (strings.eqlComptime(specifier, "node:path")) { + ret.result = null; + ret.path = "node:path"; + return; + } const is_special_source = strings.eqlComptime(source, main_file_name) or js_ast.Macro.isMacroPath(source); diff --git a/src/javascript/jsc/node/types.zig b/src/javascript/jsc/node/types.zig index 922f51b27..9238c3970 100644 --- a/src/javascript/jsc/node/types.zig +++ b/src/javascript/jsc/node/types.zig @@ -13,10 +13,10 @@ const os = std.os; const Buffer = JSC.MarkedArrayBuffer; const IdentityContext = @import("../../../identity_context.zig").IdentityContext; const logger = @import("../../../logger.zig"); +const Fs = @import("../../../fs.zig"); const Shimmer = @import("../bindings/shimmer.zig").Shimmer; const is_bindgen: bool = std.meta.globalOption("bindgen", bool) orelse false; const meta = _global.meta; - /// Time in seconds. Not nanos! pub const TimeLike = c_int; pub const Mode = if (Environment.isLinux) u32 else std.os.mode_t; @@ -1963,6 +1963,405 @@ pub const Readable = struct { }; }; +pub const Path = struct { + pub const shim = Shimmer("Bun", "Path", @This()); + pub const name = "Bun__Path"; + pub const include = "Path.h"; + pub const namespace = shim.namespace; + const PathHandler = @import("../../../resolver/resolve_path.zig"); + const StringBuilder = @import("../../../string_builder.zig"); + pub const code = @embedFile("../path.exports.js"); + + pub fn create(globalObject: *JSC.JSGlobalObject, isWindows: bool) callconv(.C) JSC.JSValue { + return shim.cppFn("create", .{ globalObject, isWindows }); + } + + pub fn basename(globalThis: *JSC.JSGlobalObject, isWindows: bool, args_ptr: [*]JSC.JSValue, args_len: u16) callconv(.C) JSC.JSValue { + if (comptime is_bindgen) return JSC.JSValue.jsUndefined(); + if (args_len == 0) { + return JSC.toInvalidArguments("path is required", .{}, globalThis.ref()); + } + var stack_fallback = std.heap.stackFallback(4096, JSC.getAllocator(globalThis.ref())); + var allocator = stack_fallback.get(); + + var arguments: []JSC.JSValue = args_ptr[0..args_len]; + var path = arguments[0].toSlice(globalThis, allocator); + defer path.deinit(); + var extname_ = if (args_len > 1) arguments[1].toSlice(globalThis, allocator) else JSC.ZigString.Slice.empty; + defer extname_.deinit(); + + var base_slice = path.slice(); + if (extname_.len > 0) { + if (strings.endsWith(base_slice, extname_.slice())) { + base_slice = base_slice[0 .. base_slice.len - extname_.len]; + } + } + var out: []const u8 = undefined; + + if (!isWindows) { + out = std.fs.path.basenamePosix(base_slice); + } else { + out = std.fs.path.basenameWindows(base_slice); + } + + return JSC.ZigString.init(out).toValueGC(globalThis); + } + pub fn dirname(globalThis: *JSC.JSGlobalObject, isWindows: bool, args_ptr: [*]JSC.JSValue, args_len: u16) callconv(.C) JSC.JSValue { + if (comptime is_bindgen) return JSC.JSValue.jsUndefined(); + if (args_len == 0) { + return JSC.toInvalidArguments("path is required", .{}, globalThis.ref()); + } + var stack_fallback = std.heap.stackFallback(4096, JSC.getAllocator(globalThis.ref())); + var allocator = stack_fallback.get(); + + var arguments: []JSC.JSValue = args_ptr[0..args_len]; + var path = arguments[0].toSlice(globalThis, allocator); + defer path.deinit(); + + const base_slice = path.slice(); + + const out = if (!isWindows) + std.fs.path.dirnameWindows(base_slice) orelse "C:\\" + else + std.fs.path.dirnamePosix(base_slice) orelse "/"; + + return JSC.ZigString.init(out).toValueGC(globalThis); + } + pub fn extname(globalThis: *JSC.JSGlobalObject, _: bool, args_ptr: [*]JSC.JSValue, args_len: u16) callconv(.C) JSC.JSValue { + if (comptime is_bindgen) return JSC.JSValue.jsUndefined(); + if (args_len == 0) { + return JSC.toInvalidArguments("path is required", .{}, globalThis.ref()); + } + var stack_fallback = std.heap.stackFallback(4096, JSC.getAllocator(globalThis.ref())); + var allocator = stack_fallback.get(); + var arguments: []JSC.JSValue = args_ptr[0..args_len]; + + var path = arguments[0].toSlice(globalThis, allocator); + defer path.deinit(); + + const base_slice = path.slice(); + + return JSC.ZigString.init(std.fs.path.extension(base_slice)).toValueGC(globalThis); + } + pub fn format(globalThis: *JSC.JSGlobalObject, isWindows: bool, args_ptr: [*]JSC.JSValue, args_len: u16) callconv(.C) JSC.JSValue { + if (comptime is_bindgen) return JSC.JSValue.jsUndefined(); + if (args_len == 0) { + return JSC.toInvalidArguments("pathObject is required", .{}, globalThis.ref()); + } + var path_object: JSC.JSValue = args_ptr[0]; + const js_type = path_object.jsType(); + if (!js_type.isObject()) { + return JSC.toInvalidArguments("pathObject is required", .{}, globalThis.ref()); + } + + var stack_fallback = std.heap.stackFallback(4096, JSC.getAllocator(globalThis.ref())); + var allocator = stack_fallback.get(); + var dir = JSC.ZigString.Empty; + var name_ = JSC.ZigString.Empty; + var ext = JSC.ZigString.Empty; + var name_with_ext = JSC.ZigString.Empty; + + var insert_separator = true; + if (path_object.get(globalThis, "dir")) |prop| { + prop.toZigString(&dir, globalThis); + insert_separator = !dir.isEmpty(); + } else if (path_object.get(globalThis, "root")) |prop| { + prop.toZigString(&dir, globalThis); + } + + if (path_object.get(globalThis, "base")) |prop| { + prop.toZigString(&name_with_ext, globalThis); + } else { + var had_ext = false; + if (path_object.get(globalThis, "ext")) |prop| { + prop.toZigString(&ext, globalThis); + had_ext = !ext.isEmpty(); + } + + if (path_object.get(globalThis, "name")) |prop| { + if (had_ext) { + prop.toZigString(&name_, globalThis); + } else { + prop.toZigString(&name_with_ext, globalThis); + } + } + } + + if (dir.isEmpty()) { + if (!name_with_ext.isEmpty()) { + return name_with_ext.toValueAuto(globalThis); + } + + if (name_.isEmpty()) { + return JSC.ZigString.Empty.toValue(globalThis); + } + const out = std.fmt.allocPrint(allocator, "{s}{s}", .{ name_, ext }) catch unreachable; + defer allocator.free(out); + return JSC.ZigString.init(out).toValueGC(globalThis); + } + + if (insert_separator) { + const separator = if (!isWindows) "/" else "\\"; + if (name_with_ext.isEmpty()) { + const out = std.fmt.allocPrint(allocator, "{}{s}{}{}", .{ dir, separator, name_, ext }) catch unreachable; + defer allocator.free(out); + return JSC.ZigString.init(out).toValueGC(globalThis); + } + + { + const out = std.fmt.allocPrint(allocator, "{}{s}{}", .{ + dir, + separator, + name_with_ext, + }) catch unreachable; + defer allocator.free(out); + return JSC.ZigString.init(out).toValueGC(globalThis); + } + } + + if (name_with_ext.isEmpty()) { + const out = std.fmt.allocPrint(allocator, "{}{}{}", .{ dir, name_, ext }) catch unreachable; + defer allocator.free(out); + return JSC.ZigString.init(out).toValueGC(globalThis); + } + + { + const out = std.fmt.allocPrint(allocator, "{}{}", .{ + dir, + name_with_ext, + }) catch unreachable; + defer allocator.free(out); + return JSC.ZigString.init(out).toValueGC(globalThis); + } + } + pub fn isAbsolute(globalThis: *JSC.JSGlobalObject, isWindows: bool, args_ptr: [*]JSC.JSValue, args_len: u16) callconv(.C) JSC.JSValue { + if (comptime is_bindgen) return JSC.JSValue.jsUndefined(); + if (args_len == 0) return JSC.JSValue.jsBoolean(false); + var zig_str: JSC.ZigString = args_ptr[0].getZigString(globalThis); + if (zig_str.isEmpty()) return JSC.JSValue.jsBoolean(false); + + if (!isWindows) { + return JSC.JSValue.jsBoolean(zig_str.slice()[0] == '/'); + } + + return JSC.JSValue.jsBoolean(isZigStringAbsoluteWindows(zig_str)); + } + fn isZigStringAbsoluteWindows(zig_str: JSC.ZigString) bool { + if (zig_str.is16Bit()) { + var buf = [4]u16{ 0, 0, 0, 0 }; + var u16_slice = zig_str.utf16Slice(); + + buf[0] = u16_slice[0]; + if (u16_slice.len > 1) + buf[1] = u16_slice[1]; + + if (u16_slice.len > 2) + buf[2] = u16_slice[2]; + + if (u16_slice.len > 3) + buf[3] = u16_slice[3]; + + return std.fs.path.isAbsoluteWindowsWTF16(buf[0..@minimum(u16_slice.len, buf.len)]); + } + + return std.fs.path.isAbsoluteWindows(zig_str.slice()); + } + pub fn join(globalThis: *JSC.JSGlobalObject, isWindows: bool, args_ptr: [*]JSC.JSValue, args_len: u16) callconv(.C) JSC.JSValue { + if (comptime is_bindgen) return JSC.JSValue.jsUndefined(); + + var stack_fallback_allocator = std.heap.stackFallback( + (32 * @sizeOf(string)), + heap_allocator, + ); + var allocator = stack_fallback_allocator.get(); + var arena = std.heap.ArenaAllocator.init(heap_allocator); + var arena_allocator = arena.allocator(); + defer arena.deinit(); + var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + var to_join = allocator.alloc(string, args_len) catch unreachable; + for (args_ptr[0..args_len]) |arg, i| { + const zig_str: JSC.ZigString = arg.getZigString(globalThis); + if (zig_str.is16Bit()) { + // TODO: remove this string conversion + to_join[i] = zig_str.toSlice(arena_allocator).slice(); + } else { + to_join[i] = zig_str.slice(); + } + } + + const out = if (!isWindows) + PathHandler.joinStringBuf(&buf, to_join, .posix) + else + PathHandler.joinStringBuf(&buf, to_join, .windows); + + var out_str = JSC.ZigString.init(out); + out_str.detectEncoding(); + return out_str.toValueGC(globalThis); + } + pub fn normalize(globalThis: *JSC.JSGlobalObject, isWindows: bool, args_ptr: [*]JSC.JSValue, args_len: u16) callconv(.C) JSC.JSValue { + if (comptime is_bindgen) return JSC.JSValue.jsUndefined(); + if (args_len == 0) return JSC.ZigString.init("").toValue(globalThis); + + var zig_str: JSC.ZigString = args_ptr[0].getZigString(globalThis); + if (zig_str.len == 0) return JSC.ZigString.init("").toValue(globalThis); + + var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + var str_slice = zig_str.toSlice(heap_allocator); + defer str_slice.deinit(); + var str = str_slice.slice(); + + const out = if (!isWindows) + PathHandler.normalizeBuf(str, &buf, .posix) + else + PathHandler.normalizeBuf(str, &buf, .windows); + + var out_str = JSC.ZigString.init(out); + out_str.detectEncoding(); + return out_str.toValueGC(globalThis); + } + pub fn parse(globalThis: *JSC.JSGlobalObject, isWindows: bool, args_ptr: [*]JSC.JSValue, args_len: u16) callconv(.C) JSC.JSValue { + if (comptime is_bindgen) return JSC.JSValue.jsUndefined(); + if (args_len == 0 or !args_ptr[0].jsType().isStringLike()) { + return JSC.toInvalidArguments("path string is required", .{}, globalThis.ref()); + } + var path_slice: JSC.ZigString.Slice = args_ptr[0].toSlice(globalThis, heap_allocator); + defer path_slice.deinit(); + var path = path_slice.slice(); + var path_name = Fs.PathName.init(path); + var root = JSC.ZigString.init(path_name.dir); + const is_absolute = (isWindows and isZigStringAbsoluteWindows(root)) or (!isWindows and path_name.dir.len > 0 and path_name.dir[0] == '/'); + + var dir = JSC.ZigString.init(path_name.dir); + if (is_absolute) { + root = JSC.ZigString.Empty; + if (path_name.dir.len == 0) + dir = JSC.ZigString.init(if (isWindows) std.fs.path.sep_str_windows else std.fs.path.sep_str_posix); + } + + var base = JSC.ZigString.init(path_name.base); + var name_ = JSC.ZigString.init(path_name.filename); + var ext = JSC.ZigString.init(path_name.ext); + var entries = [10]JSC.ZigString{ + JSC.ZigString.init("dir"), + JSC.ZigString.init("root"), + JSC.ZigString.init("base"), + JSC.ZigString.init("name"), + JSC.ZigString.init("ext"), + dir, + root, + base, + name_, + ext, + }; + + var keys: []JSC.ZigString = entries[0..5]; + var values: []JSC.ZigString = entries[5..10]; + return JSC.JSValue.fromEntries(globalThis, keys.ptr, values.ptr, 5, true); + } + pub fn relative(globalThis: *JSC.JSGlobalObject, isWindows: bool, args_ptr: [*]JSC.JSValue, args_len: u16) callconv(.C) JSC.JSValue { + if (comptime is_bindgen) return JSC.JSValue.jsUndefined(); + var arguments = args_ptr[0..args_len]; + + if (args_len > 1 and JSC.JSValue.eqlValue(args_ptr[0], args_ptr[1])) + return JSC.ZigString.init(".").toValue(globalThis); + + var from_slice: JSC.ZigString.Slice = if (args_len > 0) arguments[0].toSlice(globalThis, heap_allocator) else JSC.ZigString.Slice.empty; + defer from_slice.deinit(); + var to_slice: JSC.ZigString.Slice = if (args_len > 1) arguments[1].toSlice(globalThis, heap_allocator) else JSC.ZigString.Slice.empty; + defer to_slice.deinit(); + + var from = from_slice.slice(); + var to = to_slice.slice(); + + var out = if (!isWindows) + PathHandler.relativeNormalized(from, to, .posix, false) + else + PathHandler.relativeNormalized(from, to, .windows, false); + + var out_str = JSC.ZigString.init(out); + out_str.detectEncoding(); + return out_str.toValueGC(globalThis); + } + + pub fn resolve(globalThis: *JSC.JSGlobalObject, isWindows: bool, args_ptr: [*]JSC.JSValue, args_len: u16) callconv(.C) JSC.JSValue { + if (comptime is_bindgen) return JSC.JSValue.jsUndefined(); + if (args_len < 2) return normalize(globalThis, isWindows, args_ptr, args_len); + + var stack_fallback_allocator = std.heap.stackFallback( + (32 * @sizeOf(string)), + heap_allocator, + ); + var allocator = stack_fallback_allocator.get(); + var out_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + // TODO: + _ = isWindows; + var parts = allocator.alloc(string, args_len) catch unreachable; + defer allocator.free(parts); + var i: u16 = 0; + var arena = std.heap.ArenaAllocator.init(heap_allocator); + var arena_allocator = arena.allocator(); + defer arena.deinit(); + + while (i < args_len) : (i += 1) { + parts[i] = args_ptr[0].toSlice(globalThis, arena_allocator).slice(); + } + + var out = JSC.ZigString.init(PathHandler.joinStringBuf(&out_buf, parts, .posix)); + out.detectEncoding(); + return out.toValueGC(globalThis); + } + + pub const Export = shim.exportFunctions(.{ + .@"basename" = basename, + .@"dirname" = dirname, + .@"extname" = extname, + .@"format" = format, + .@"isAbsolute" = isAbsolute, + .@"join" = join, + .@"normalize" = normalize, + .@"parse" = parse, + .@"relative" = relative, + .@"resolve" = resolve, + }); + + pub const Extern = [_][]const u8{"create"}; + + comptime { + if (!is_bindgen) { + @export(Path.basename, .{ + .name = Export[0].symbol_name, + }); + @export(Path.dirname, .{ + .name = Export[1].symbol_name, + }); + @export(Path.extname, .{ + .name = Export[2].symbol_name, + }); + @export(Path.format, .{ + .name = Export[3].symbol_name, + }); + @export(Path.isAbsolute, .{ + .name = Export[4].symbol_name, + }); + @export(Path.join, .{ + .name = Export[5].symbol_name, + }); + @export(Path.normalize, .{ + .name = Export[6].symbol_name, + }); + @export(Path.parse, .{ + .name = Export[7].symbol_name, + }); + @export(Path.relative, .{ + .name = Export[8].symbol_name, + }); + @export(Path.resolve, .{ + .name = Export[9].symbol_name, + }); + } + } +}; + pub const Process = struct { pub fn getArgv(globalObject: *JSC.JSGlobalObject) callconv(.C) JSC.JSValue { if (JSC.VirtualMachine.vm.argv.len == 0) @@ -2068,6 +2467,7 @@ comptime { std.testing.refAllDecls(Process); std.testing.refAllDecls(Stream); std.testing.refAllDecls(Readable); + std.testing.refAllDecls(Path); std.testing.refAllDecls(Writable); std.testing.refAllDecls(Writable.State); std.testing.refAllDecls(Readable.State); diff --git a/src/javascript/jsc/path.exports.js b/src/javascript/jsc/path.exports.js new file mode 100644 index 000000000..6fa7af88d --- /dev/null +++ b/src/javascript/jsc/path.exports.js @@ -0,0 +1,56 @@ +function bound(obj) { + return { + basename: obj.basename.bind(obj), + dirname: obj.dirname.bind(obj), + extname: obj.extname.bind(obj), + format: obj.format.bind(obj), + isAbsolute: obj.isAbsolute.bind(obj), + join: obj.join.bind(obj), + normalize: obj.normalize.bind(obj), + parse: obj.parse.bind(obj), + relative: obj.relative.bind(obj), + resolve: obj.resolve.bind(obj), + toNamespacedPath: obj.toNamespacedPath.bind(obj), + sep: obj.sep, + delimiter: obj.delimiter, + }; +} +var path = bound(Bun._Path()); +path.win32 = win32; +path.posix = posix; +export var posix = bound(Bun._Path(false)); +export var win32 = bound(Bun._Path(true)); + +var { + basename, + dirname, + extname, + format, + isAbsolute, + join, + normalize, + parse, + relative, + resolve, + toNamespacedPath, + sep, + delimiter, +} = path; + +export { + basename, + dirname, + extname, + format, + isAbsolute, + join, + normalize, + parse, + relative, + resolve, + toNamespacedPath, + sep, + delimiter, +}; + +export default path; diff --git a/src/linker.zig b/src/linker.zig index 04604522a..b108ccce7 100644 --- a/src/linker.zig +++ b/src/linker.zig @@ -258,6 +258,13 @@ pub const Linker = struct { if (linker.options.platform.isBun()) { if (strings.eqlComptime(import_record.path.text, "fs") or strings.eqlComptime(import_record.path.text, "node:fs")) { + import_record.path.text = "node:fs"; + externals.append(record_index) catch unreachable; + continue; + } + + if (strings.eqlComptime(import_record.path.text, "path") or strings.eqlComptime(import_record.path.text, "node:path")) { + import_record.path.text = "node:path"; externals.append(record_index) catch unreachable; continue; } diff --git a/src/pool.zig b/src/pool.zig index 084fa9dd4..84fb6acb1 100644 --- a/src/pool.zig +++ b/src/pool.zig @@ -107,7 +107,7 @@ fn SinglyLinkedList(comptime T: type, comptime Parent: type) type { }; } -const log_allocations = true; +const log_allocations = false; pub fn ObjectPool( comptime Type: type, diff --git a/src/resolver/resolve_path.zig b/src/resolver/resolve_path.zig index ca18f1f82..d77825211 100644 --- a/src/resolver/resolve_path.zig +++ b/src/resolver/resolve_path.zig @@ -254,7 +254,7 @@ pub fn relativeToCommonPath( if (normalized_to.len > last_common_separator + 1) { const tail = normalized_to[last_common_separator..]; - const insert_leading_slash = last_common_separator > 0 and normalized_to[last_common_separator - 1] != separator; + const insert_leading_slash = last_common_separator > 0 and normalized_to[last_common_separator - 1] != separator and tail[0] != separator; if (insert_leading_slash) { buf[out_slice.len] = separator; @@ -521,6 +521,32 @@ pub fn normalizeString(str: []const u8, comptime allow_above_root: bool, comptim return normalizeStringBuf(str, &parser_buffer, allow_above_root, _platform, false); } +pub fn normalizeBuf(str: []const u8, buf: []u8, comptime _platform: Platform) []u8 { + if (buf.len == 0) { + buf[0] = '.'; + return buf[0..1]; + } + + const is_absolute = if (_platform == .posix or _platform == .auto) + (buf[0] == _platform.separator()) + else + std.fs.path.isAbsoluteWindows(str); + + const trailing_separator = + buf[buf.len - 1] == _platform.separator(); + + if (is_absolute and trailing_separator) + return normalizeStringBuf(str, buf, true, _platform, true); + + if (is_absolute and !trailing_separator) + return normalizeStringBuf(str, buf, true, _platform, false); + + if (!is_absolute and !trailing_separator) + return normalizeStringBuf(str, buf, false, _platform, false); + + return normalizeStringBuf(str, buf, false, _platform, true); +} + pub fn normalizeStringBuf(str: []const u8, buf: []u8, comptime allow_above_root: bool, comptime _platform: Platform, comptime preserve_trailing_slash: anytype) []u8 { const platform = comptime _platform.resolve(); @@ -528,7 +554,13 @@ pub fn normalizeStringBuf(str: []const u8, buf: []u8, comptime allow_above_root: .auto => unreachable, .windows => { - @compileError("Not implemented"); + // @compileError("Not implemented"); + return normalizeStringLooseBuf( + str, + buf, + allow_above_root, + preserve_trailing_slash, + ); }, .posix => { return normalizeStringLooseBuf( @@ -620,7 +652,7 @@ pub fn joinStringBuf(buf: []u8, _parts: anytype, comptime _platform: Platform) [ if (_parts[0].len > 0 and _parts[0][0] == _platform.separator()) { const out = switch (comptime platform) { // .loose => - .windows => @compileError("Not implemented yet"), + // .windows => @compileError("Not implemented yet"), else => normalizeStringLooseBuf(parser_join_input_buffer[0..written], buf[1..], false, false), }; buf[0] = _platform.separator(); @@ -629,7 +661,7 @@ pub fn joinStringBuf(buf: []u8, _parts: anytype, comptime _platform: Platform) [ } else { return switch (platform) { else => normalizeStringLooseBuf(parser_join_input_buffer[0..written], buf[0..], false, false), - .windows => @compileError("Not implemented yet"), + // .windows => @compileError("Not implemented yet"), }; } } @@ -956,6 +988,7 @@ test "relative" { _ = t.expect("index.js", try relativeAlloc(default_allocator, "/app/public/", "/app/public/index.js"), @src()); _ = t.expect("..", try relativeAlloc(default_allocator, "/app/public/index.js", "/app/public/"), @src()); _ = t.expect("../../src/bacon.ts", try relativeAlloc(default_allocator, "/app/public/index.html", "/app/src/bacon.ts"), @src()); + _ = t.expect("../../../../bacon/foo/baz", try relativeAlloc(default_allocator, "/app/foo/bar/baz.js", "/bacon/foo/baz"), @src()); } test "longestCommonPath" { -- cgit v1.2.3