diff options
author | 2023-06-28 16:09:08 -0700 | |
---|---|---|
committer | 2023-06-28 16:09:08 -0700 | |
commit | 292647bd531c154f81d2d3d8f3344e01752549f6 (patch) | |
tree | 0bd9619a719382e65dd5c7b3ac30556490468f74 /src | |
parent | 42ded7033623feec80afd13ce199752eaf20e438 (diff) | |
download | bun-292647bd531c154f81d2d3d8f3344e01752549f6.tar.gz bun-292647bd531c154f81d2d3d8f3344e01752549f6.tar.zst bun-292647bd531c154f81d2d3d8f3344e01752549f6.zip |
Introduce `await Bun.file(path).exists()` (#3446)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/bun.js/bindings/ZigGeneratedClasses.cpp | 31 | ||||
-rw-r--r-- | src/bun.js/bindings/generated_classes.zig | 3 | ||||
-rw-r--r-- | src/bun.js/webcore/blob.zig | 29 | ||||
-rw-r--r-- | src/bun.js/webcore/response.classes.ts | 1 |
4 files changed, 64 insertions, 0 deletions
diff --git a/src/bun.js/bindings/ZigGeneratedClasses.cpp b/src/bun.js/bindings/ZigGeneratedClasses.cpp index 387580d54..b7461b5f0 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses.cpp +++ b/src/bun.js/bindings/ZigGeneratedClasses.cpp @@ -103,6 +103,9 @@ extern "C" void BlobClass__finalize(void*); extern "C" EncodedJSValue BlobPrototype__getArrayBuffer(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); JSC_DECLARE_HOST_FUNCTION(BlobPrototype__arrayBufferCallback); +extern "C" EncodedJSValue BlobPrototype__getExists(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC_DECLARE_HOST_FUNCTION(BlobPrototype__existsCallback); + extern "C" EncodedJSValue BlobPrototype__getFormData(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); JSC_DECLARE_HOST_FUNCTION(BlobPrototype__formDataCallback); @@ -137,6 +140,7 @@ STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSBlobPrototype, JSBlobPrototype::Base); static const HashTableValue JSBlobPrototypeTableValues[] = { { "arrayBuffer"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, BlobPrototype__arrayBufferCallback, 0 } }, + { "exists"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, BlobPrototype__existsCallback, 0 } }, { "formData"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, BlobPrototype__formDataCallback, 0 } }, { "json"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, BlobPrototype__jsonCallback, 0 } }, { "lastModified"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, BlobPrototype__lastModifiedGetterWrap, 0 } }, @@ -190,6 +194,33 @@ JSC_DEFINE_HOST_FUNCTION(BlobPrototype__arrayBufferCallback, (JSGlobalObject * l return BlobPrototype__getArrayBuffer(thisObject->wrapped(), lexicalGlobalObject, callFrame); } +JSC_DEFINE_HOST_FUNCTION(BlobPrototype__existsCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +{ + auto& vm = lexicalGlobalObject->vm(); + + JSBlob* thisObject = jsDynamicCast<JSBlob*>(callFrame->thisValue()); + + if (UNLIKELY(!thisObject)) { + auto throwScope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(lexicalGlobalObject, throwScope); + } + + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + +#ifdef BUN_DEBUG + /** View the file name of the JS file that called this function + * from a debugger */ + SourceOrigin sourceOrigin = callFrame->callerSourceOrigin(vm); + const char* fileName = sourceOrigin.string().utf8().data(); + static const char* lastFileName = nullptr; + if (lastFileName != fileName) { + lastFileName = fileName; + } +#endif + + return BlobPrototype__getExists(thisObject->wrapped(), lexicalGlobalObject, callFrame); +} + JSC_DEFINE_HOST_FUNCTION(BlobPrototype__formDataCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) { auto& vm = lexicalGlobalObject->vm(); diff --git a/src/bun.js/bindings/generated_classes.zig b/src/bun.js/bindings/generated_classes.zig index bdde69c1a..04a72d7ed 100644 --- a/src/bun.js/bindings/generated_classes.zig +++ b/src/bun.js/bindings/generated_classes.zig @@ -108,6 +108,8 @@ pub const JSBlob = struct { if (@TypeOf(Blob.getArrayBuffer) != CallbackType) @compileLog("Expected Blob.getArrayBuffer to be a callback but received " ++ @typeName(@TypeOf(Blob.getArrayBuffer))); + if (@TypeOf(Blob.getExists) != CallbackType) + @compileLog("Expected Blob.getExists to be a callback but received " ++ @typeName(@TypeOf(Blob.getExists))); if (@TypeOf(Blob.getFormData) != CallbackType) @compileLog("Expected Blob.getFormData to be a callback but received " ++ @typeName(@TypeOf(Blob.getFormData))); if (@TypeOf(Blob.getJSON) != CallbackType) @@ -136,6 +138,7 @@ pub const JSBlob = struct { @export(Blob.constructor, .{ .name = "BlobClass__construct" }); @export(Blob.finalize, .{ .name = "BlobClass__finalize" }); @export(Blob.getArrayBuffer, .{ .name = "BlobPrototype__getArrayBuffer" }); + @export(Blob.getExists, .{ .name = "BlobPrototype__getExists" }); @export(Blob.getFormData, .{ .name = "BlobPrototype__getFormData" }); @export(Blob.getJSON, .{ .name = "BlobPrototype__getJSON" }); @export(Blob.getLastModified, .{ .name = "BlobPrototype__getLastModified" }); diff --git a/src/bun.js/webcore/blob.zig b/src/bun.js/webcore/blob.zig index 868acbb80..faf503a3f 100644 --- a/src/bun.js/webcore/blob.zig +++ b/src/bun.js/webcore/blob.zig @@ -319,6 +319,7 @@ pub const Blob = struct { }, ); } + pub fn writeFormat(this: *const Blob, comptime Formatter: type, formatter: *Formatter, writer: anytype, comptime enable_ansi_colors: bool) !void { const Writer = @TypeOf(writer); @@ -2324,6 +2325,34 @@ pub const Blob = struct { return promisified(this.toFormData(globalThis, .temporary), globalThis); } + fn getExistsSync(this: *Blob) JSC.JSValue { + if (this.size == Blob.max_size) { + this.resolveSize(); + } + + // If there's no store that means it's empty and we just return true + // it will not error to return an empty Blob + var store = this.store orelse return JSValue.jsBoolean(true); + + if (store.data == .bytes) { + // Bytes will never error + return JSValue.jsBoolean(true); + } + + // We say regular files and pipes exist. + // This is mostly meant for "Can we use this in new Response(file)?" + return JSValue.jsBoolean(std.os.S.ISREG(store.data.file.mode) or std.os.S.ISFIFO(store.data.file.mode)); + } + + // This mostly means 'can it be read?' + pub fn getExists( + this: *Blob, + globalThis: *JSC.JSGlobalObject, + _: *JSC.CallFrame, + ) callconv(.C) JSValue { + return JSC.JSPromise.resolvedPromiseValue(globalThis, this.getExistsSync()); + } + pub fn getWriter( this: *Blob, globalThis: *JSC.JSGlobalObject, diff --git a/src/bun.js/webcore/response.classes.ts b/src/bun.js/webcore/response.classes.ts index b6ad452d2..c11cb10b2 100644 --- a/src/bun.js/webcore/response.classes.ts +++ b/src/bun.js/webcore/response.classes.ts @@ -132,6 +132,7 @@ export default [ slice: { fn: "getSlice", length: 2 }, stream: { fn: "getStream", length: 1 }, formData: { fn: "getFormData" }, + exists: { fn: "getExists", length: 0 }, type: { getter: "getType", |