mirror of
https://github.com/oven-sh/bun
synced 2026-02-17 14:22:01 +00:00
Compare commits
13 Commits
claude/red
...
jarred/fix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7bb4d31f43 | ||
|
|
f3cd2be68c | ||
|
|
dec6c62968 | ||
|
|
d728839497 | ||
|
|
8d877e288b | ||
|
|
cb8af3a4e7 | ||
|
|
5b0277b6b8 | ||
|
|
88ad5ed73c | ||
|
|
4d3eefa45f | ||
|
|
7a748678ae | ||
|
|
43b0d03482 | ||
|
|
7ac6eab209 | ||
|
|
16207d78be |
@@ -55,7 +55,7 @@ async function runTest(path) {
|
||||
stdout,
|
||||
stderr,
|
||||
status: exitCode,
|
||||
} = spawnSync("bun", ["test", basename(path)], {
|
||||
} = spawnSync("bun", ["test", path], {
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
timeout: 10_000,
|
||||
env: {
|
||||
|
||||
20
packages/bun-types/bun.d.ts
vendored
20
packages/bun-types/bun.d.ts
vendored
@@ -620,8 +620,26 @@ declare module "bun" {
|
||||
*
|
||||
* @param begin - start offset in bytes
|
||||
* @param end - absolute offset in bytes (relative to 0)
|
||||
* @param contentType - MIME type for the new FileBlob
|
||||
*/
|
||||
slice(begin?: number, end?: number): FileBlob;
|
||||
slice(begin?: number, end?: number, contentType?: string): FileBlob;
|
||||
|
||||
/**
|
||||
* Offset any operation on the file starting at `begin`
|
||||
*
|
||||
* Similar to [`TypedArray.subarray`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/subarray). Does not copy the file, open the file, or modify the file.
|
||||
*
|
||||
* If `begin` > 0, {@link Bun.write()} will be slower on macOS
|
||||
*
|
||||
* @param begin - start offset in bytes
|
||||
* @param contentType - MIME type for the new FileBlob
|
||||
*/
|
||||
slice(begin?: number, contentType?: string): FileBlob;
|
||||
|
||||
/**
|
||||
* @param contentType - MIME type for the new FileBlob
|
||||
*/
|
||||
slice(contentType?: string): FileBlob;
|
||||
|
||||
/**
|
||||
* Incremental writer for files and pipes.
|
||||
|
||||
24
packages/bun-types/globals.d.ts
vendored
24
packages/bun-types/globals.d.ts
vendored
@@ -565,7 +565,29 @@ declare class Blob implements BlobInterface {
|
||||
* @param end The index that sets the end of the view.
|
||||
*
|
||||
*/
|
||||
slice(begin?: number, end?: number): Blob;
|
||||
slice(begin?: number, end?: number, contentType?: string): Blob;
|
||||
|
||||
/**
|
||||
* Create a new view **without 🚫 copying** the underlying data.
|
||||
*
|
||||
* Similar to [`BufferSource.subarray`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BufferSource/subarray)
|
||||
*
|
||||
* @param begin The index that sets the beginning of the view.
|
||||
* @param end The index that sets the end of the view.
|
||||
*
|
||||
*/
|
||||
slice(begin?: number, contentType?: string): Blob;
|
||||
|
||||
/**
|
||||
* Create a new view **without 🚫 copying** the underlying data.
|
||||
*
|
||||
* Similar to [`BufferSource.subarray`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BufferSource/subarray)
|
||||
*
|
||||
* @param begin The index that sets the beginning of the view.
|
||||
* @param end The index that sets the end of the view.
|
||||
*
|
||||
*/
|
||||
slice(contentType?: string): Blob;
|
||||
|
||||
/**
|
||||
* Read the data from the blob as a string. It will be decoded from UTF-8.
|
||||
|
||||
@@ -13,6 +13,4 @@ async function* listReleases() {
|
||||
}
|
||||
}
|
||||
|
||||
const releases = await Array.fromAsync(listReleases());
|
||||
|
||||
export {};
|
||||
export const releases = await Array.fromAsync(listReleases());
|
||||
|
||||
@@ -377,7 +377,9 @@ pub const ServerConfig = struct {
|
||||
}
|
||||
|
||||
if (arg.getTruthy(global, "maxRequestBodySize")) |max_request_body_size| {
|
||||
args.max_request_body_size = @intCast(u64, @max(0, max_request_body_size.toInt64()));
|
||||
if (max_request_body_size.isNumber()) {
|
||||
args.max_request_body_size = @intCast(u64, @max(0, max_request_body_size.toInt64()));
|
||||
}
|
||||
}
|
||||
|
||||
if (arg.getTruthy(global, "error")) |onError| {
|
||||
|
||||
@@ -1773,6 +1773,8 @@ pub const ArrayBuffer = extern struct {
|
||||
}
|
||||
|
||||
pub fn createEmpty(globalThis: *JSC.JSGlobalObject, comptime kind: JSC.JSValue.JSType) JSValue {
|
||||
JSC.markBinding(@src());
|
||||
|
||||
return switch (comptime kind) {
|
||||
.Uint8Array => Bun__createUint8ArrayForCopy(globalThis, null, 0, false),
|
||||
.ArrayBuffer => Bun__createArrayBufferForCopy(globalThis, null, 0),
|
||||
|
||||
@@ -2455,10 +2455,6 @@ bool JSC__JSValue__isPrimitive(JSC__JSValue JSValue0)
|
||||
{
|
||||
return JSC::JSValue::decode(JSValue0).isPrimitive();
|
||||
}
|
||||
bool JSC__JSValue__isString(JSC__JSValue JSValue0)
|
||||
{
|
||||
return JSC::JSValue::decode(JSValue0).isString();
|
||||
}
|
||||
bool JSC__JSValue__isSymbol(JSC__JSValue JSValue0)
|
||||
{
|
||||
return JSC::JSValue::decode(JSValue0).isSymbol();
|
||||
|
||||
@@ -159,6 +159,9 @@ pub const ZigString = extern struct {
|
||||
}
|
||||
|
||||
pub fn eql(this: ZigString, other: ZigString) bool {
|
||||
if (this.len == 0 or other.len == 0)
|
||||
return this.len == other.len;
|
||||
|
||||
const left_utf16 = this.is16Bit();
|
||||
const right_utf16 = other.is16Bit();
|
||||
|
||||
@@ -2276,6 +2279,10 @@ pub const JSGlobalObject = extern struct {
|
||||
return this.bunVM().allocator;
|
||||
}
|
||||
|
||||
pub fn throwOutOfMemory(this: *JSGlobalObject) void {
|
||||
this.throwValue(this.createErrorInstance("Out of memory", .{}));
|
||||
}
|
||||
|
||||
pub fn throwInvalidArguments(
|
||||
this: *JSGlobalObject,
|
||||
comptime fmt: string,
|
||||
@@ -3454,8 +3461,11 @@ pub const JSValue = enum(JSValueReprInt) {
|
||||
return res;
|
||||
}
|
||||
|
||||
pub fn isString(this: JSValue) bool {
|
||||
return cppFn("isString", .{this});
|
||||
pub inline fn isString(this: JSValue) bool {
|
||||
if (!this.isCell())
|
||||
return false;
|
||||
|
||||
return jsType(this).isStringLike();
|
||||
}
|
||||
pub fn isBigInt(this: JSValue) bool {
|
||||
return cppFn("isBigInt", .{this});
|
||||
@@ -3968,7 +3978,6 @@ pub const JSValue = enum(JSValueReprInt) {
|
||||
"isObject",
|
||||
"isPrimitive",
|
||||
"isSameValue",
|
||||
"isString",
|
||||
"isSymbol",
|
||||
"isTerminationException",
|
||||
"isUInt32AsAnyInt",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//-- AUTOGENERATED FILE -- 1677776166
|
||||
//-- AUTOGENERATED FILE -- 1678254453
|
||||
// clang-format off
|
||||
#pragma once
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// clang-format off
|
||||
//-- AUTOGENERATED FILE -- 1677776166
|
||||
//-- AUTOGENERATED FILE -- 1678254453
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
@@ -331,7 +331,6 @@ CPP_DECL bool JSC__JSValue__isNumber(JSC__JSValue JSValue0);
|
||||
CPP_DECL bool JSC__JSValue__isObject(JSC__JSValue JSValue0);
|
||||
CPP_DECL bool JSC__JSValue__isPrimitive(JSC__JSValue JSValue0);
|
||||
CPP_DECL bool JSC__JSValue__isSameValue(JSC__JSValue JSValue0, JSC__JSValue JSValue1, JSC__JSGlobalObject* arg2);
|
||||
CPP_DECL bool JSC__JSValue__isString(JSC__JSValue JSValue0);
|
||||
CPP_DECL bool JSC__JSValue__isSymbol(JSC__JSValue JSValue0);
|
||||
CPP_DECL bool JSC__JSValue__isTerminationException(JSC__JSValue JSValue0, JSC__VM* arg1);
|
||||
CPP_DECL bool JSC__JSValue__isUInt32AsAnyInt(JSC__JSValue JSValue0);
|
||||
|
||||
@@ -244,7 +244,6 @@ pub extern fn JSC__JSValue__isNumber(JSValue0: JSC__JSValue) bool;
|
||||
pub extern fn JSC__JSValue__isObject(JSValue0: JSC__JSValue) bool;
|
||||
pub extern fn JSC__JSValue__isPrimitive(JSValue0: JSC__JSValue) bool;
|
||||
pub extern fn JSC__JSValue__isSameValue(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: *bindings.JSGlobalObject) bool;
|
||||
pub extern fn JSC__JSValue__isString(JSValue0: JSC__JSValue) bool;
|
||||
pub extern fn JSC__JSValue__isSymbol(JSValue0: JSC__JSValue) bool;
|
||||
pub extern fn JSC__JSValue__isTerminationException(JSValue0: JSC__JSValue, arg1: *bindings.VM) bool;
|
||||
pub extern fn JSC__JSValue__isUInt32AsAnyInt(JSValue0: JSC__JSValue) bool;
|
||||
|
||||
@@ -451,6 +451,10 @@ pub const VirtualMachine = struct {
|
||||
return VMHolder.vm.?;
|
||||
}
|
||||
|
||||
pub fn mimeType(this: *VirtualMachine, str: []const u8) ?bun.HTTP.MimeType {
|
||||
return this.rareData().mimeTypeFromString(this.allocator, str);
|
||||
}
|
||||
|
||||
pub const GCLevel = enum(u3) {
|
||||
none = 0,
|
||||
mild = 1,
|
||||
|
||||
@@ -27,6 +27,18 @@ file_polls_: ?*JSC.FilePoll.HiveArray = null,
|
||||
|
||||
global_dns_data: ?*JSC.DNS.GlobalData = null,
|
||||
|
||||
mime_types: ?bun.HTTP.MimeType.Map = null,
|
||||
|
||||
pub fn mimeTypeFromString(this: *RareData, allocator: std.mem.Allocator, str: []const u8) ?bun.HTTP.MimeType {
|
||||
if (this.mime_types == null) {
|
||||
this.mime_types = bun.HTTP.MimeType.createHashTable(
|
||||
allocator,
|
||||
) catch @panic("Out of memory");
|
||||
}
|
||||
|
||||
return this.mime_types.?.get(str);
|
||||
}
|
||||
|
||||
pub fn filePolls(this: *RareData, vm: *JSC.VirtualMachine) *JSC.FilePoll.HiveArray {
|
||||
return this.file_polls_ orelse {
|
||||
this.file_polls_ = vm.allocator.create(JSC.FilePoll.HiveArray) catch unreachable;
|
||||
|
||||
@@ -2391,7 +2391,7 @@ pub const Blob = struct {
|
||||
callframe: *JSC.CallFrame,
|
||||
) callconv(.C) JSC.JSValue {
|
||||
var allocator = globalThis.allocator();
|
||||
var arguments_ = callframe.arguments(2);
|
||||
var arguments_ = callframe.arguments(3);
|
||||
var args = arguments_.ptr[0..arguments_.len];
|
||||
|
||||
if (this.size == 0) {
|
||||
@@ -2410,51 +2410,84 @@ pub const Blob = struct {
|
||||
// If the optional end parameter is not used as a parameter when making this call, let relativeEnd be size.
|
||||
var relativeEnd: i64 = @intCast(i64, this.size);
|
||||
|
||||
if (args.ptr[0].isString()) {
|
||||
args.ptr[2] = args.ptr[0];
|
||||
args.ptr[1] = .zero;
|
||||
args.ptr[0] = .zero;
|
||||
args.len = 3;
|
||||
} else if (args.ptr[1].isString()) {
|
||||
args.ptr[2] = args.ptr[1];
|
||||
args.ptr[1] = .zero;
|
||||
args.len = 3;
|
||||
}
|
||||
|
||||
var args_iter = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), args);
|
||||
if (args_iter.nextEat()) |start_| {
|
||||
const start = start_.toInt64();
|
||||
if (start < 0) {
|
||||
// If the optional start parameter is negative, let relativeStart be start + size.
|
||||
relativeStart = @intCast(i64, @max(start + @intCast(i64, this.size), 0));
|
||||
} else {
|
||||
// Otherwise, let relativeStart be start.
|
||||
relativeStart = @min(@intCast(i64, start), @intCast(i64, this.size));
|
||||
if (start_.isNumber()) {
|
||||
const start = start_.toInt64();
|
||||
if (start < 0) {
|
||||
// If the optional start parameter is negative, let relativeStart be start + size.
|
||||
relativeStart = @intCast(i64, @max(start +% @intCast(i64, this.size), 0));
|
||||
} else {
|
||||
// Otherwise, let relativeStart be start.
|
||||
relativeStart = @min(@intCast(i64, start), @intCast(i64, this.size));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (args_iter.nextEat()) |end_| {
|
||||
const end = end_.toInt64();
|
||||
// If end is negative, let relativeEnd be max((size + end), 0).
|
||||
if (end < 0) {
|
||||
// If the optional start parameter is negative, let relativeStart be start + size.
|
||||
relativeEnd = @intCast(i64, @max(end + @intCast(i64, this.size), 0));
|
||||
} else {
|
||||
// Otherwise, let relativeStart be start.
|
||||
relativeEnd = @min(@intCast(i64, end), @intCast(i64, this.size));
|
||||
if (end_.isNumber()) {
|
||||
const end = end_.toInt64();
|
||||
// If end is negative, let relativeEnd be max((size + end), 0).
|
||||
if (end < 0) {
|
||||
// If the optional start parameter is negative, let relativeStart be start + size.
|
||||
relativeEnd = @intCast(i64, @max(end +% @intCast(i64, this.size), 0));
|
||||
} else {
|
||||
// Otherwise, let relativeStart be start.
|
||||
relativeEnd = @min(@intCast(i64, end), @intCast(i64, this.size));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var content_type: string = "";
|
||||
var content_type_was_allocated = false;
|
||||
if (args_iter.nextEat()) |content_type_| {
|
||||
if (content_type_.isString()) {
|
||||
var zig_str = content_type_.getZigString(globalThis);
|
||||
var slicer = zig_str.toSlice(bun.default_allocator);
|
||||
defer slicer.deinit();
|
||||
var slice = slicer.slice();
|
||||
var content_type_buf = allocator.alloc(u8, slice.len) catch unreachable;
|
||||
content_type = strings.copyLowercase(slice, content_type_buf);
|
||||
inner: {
|
||||
if (content_type_.isString()) {
|
||||
var zig_str = content_type_.getZigString(globalThis);
|
||||
var slicer = zig_str.toSlice(bun.default_allocator);
|
||||
defer slicer.deinit();
|
||||
var slice = slicer.slice();
|
||||
if (!strings.isAllASCII(slice)) {
|
||||
break :inner;
|
||||
}
|
||||
|
||||
if (globalThis.bunVM().mimeType(slice)) |mime| {
|
||||
content_type = mime.value;
|
||||
break :inner;
|
||||
}
|
||||
|
||||
content_type_was_allocated = slice.len > 0;
|
||||
var content_type_buf = allocator.alloc(u8, slice.len) catch unreachable;
|
||||
content_type = strings.copyLowercase(slice, content_type_buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const len = @intCast(SizeType, @max(relativeEnd - relativeStart, 0));
|
||||
const len = @intCast(SizeType, @max(relativeEnd -| relativeStart, 0));
|
||||
|
||||
// This copies over the is_all_ascii flag
|
||||
// which is okay because this will only be a <= slice
|
||||
var blob = this.dupe();
|
||||
blob.offset = @intCast(SizeType, relativeStart);
|
||||
blob.size = len;
|
||||
|
||||
// infer the content type if it was not specified
|
||||
if (content_type.len == 0 and this.content_type.len > 0 and !this.content_type_allocated)
|
||||
content_type = this.content_type;
|
||||
|
||||
blob.content_type = content_type;
|
||||
blob.content_type_allocated = content_type.len > 0;
|
||||
blob.content_type_allocated = content_type_was_allocated;
|
||||
|
||||
var blob_ = allocator.create(Blob) catch unreachable;
|
||||
blob_.* = blob;
|
||||
@@ -2474,19 +2507,35 @@ pub const Blob = struct {
|
||||
globalThis: *JSC.JSGlobalObject,
|
||||
value: JSC.JSValue,
|
||||
) callconv(.C) bool {
|
||||
var zig_str = value.getZigString(globalThis);
|
||||
if (zig_str.is16Bit())
|
||||
return false;
|
||||
var zig_str = if (value.isString())
|
||||
value.getZigString(globalThis)
|
||||
else
|
||||
ZigString.Empty;
|
||||
|
||||
var slice = zig_str.trimmedSlice();
|
||||
if (strings.eql(slice, this.content_type))
|
||||
if (!zig_str.isAllASCII()) {
|
||||
zig_str = ZigString.Empty;
|
||||
}
|
||||
|
||||
if (zig_str.eql(ZigString.init(this.content_type))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const prev_content_type = this.content_type;
|
||||
{
|
||||
defer if (this.content_type_allocated) bun.default_allocator.free(prev_content_type);
|
||||
var content_type_buf = globalThis.allocator().alloc(u8, slice.len) catch unreachable;
|
||||
this.content_type = strings.copyLowercase(slice, content_type_buf);
|
||||
var slicer = zig_str.toSlice(bun.default_allocator);
|
||||
defer slicer.deinit();
|
||||
const allocated = this.content_type_allocated;
|
||||
defer if (allocated) bun.default_allocator.free(prev_content_type);
|
||||
if (globalThis.bunVM().mimeType(slicer.slice())) |mime| {
|
||||
this.content_type = mime.value;
|
||||
this.content_type_allocated = false;
|
||||
return true;
|
||||
}
|
||||
var content_type_buf = globalThis.allocator().alloc(u8, slicer.len) catch {
|
||||
globalThis.throwOutOfMemory();
|
||||
return false;
|
||||
};
|
||||
this.content_type = strings.copyLowercase(slicer.slice(), content_type_buf);
|
||||
}
|
||||
|
||||
this.content_type_allocated = true;
|
||||
@@ -2602,13 +2651,22 @@ pub const Blob = struct {
|
||||
// Normative conditions for this member are provided
|
||||
// in the § 3.1 Constructors.
|
||||
if (options.get(globalThis, "type")) |content_type| {
|
||||
if (content_type.isString()) {
|
||||
var content_type_str = content_type.toSlice(globalThis, bun.default_allocator);
|
||||
defer content_type_str.deinit();
|
||||
var slice = content_type_str.slice();
|
||||
var content_type_buf = allocator.alloc(u8, slice.len) catch unreachable;
|
||||
blob.content_type = strings.copyLowercase(slice, content_type_buf);
|
||||
blob.content_type_allocated = true;
|
||||
inner: {
|
||||
if (content_type.isString()) {
|
||||
var content_type_str = content_type.toSlice(globalThis, bun.default_allocator);
|
||||
defer content_type_str.deinit();
|
||||
var slice = content_type_str.slice();
|
||||
if (!strings.isAllASCII(slice)) {
|
||||
break :inner;
|
||||
}
|
||||
if (globalThis.bunVM().mimeType(slice)) |mime| {
|
||||
blob.content_type = mime.value;
|
||||
break :inner;
|
||||
}
|
||||
var content_type_buf = allocator.alloc(u8, slice.len) catch unreachable;
|
||||
blob.content_type = strings.copyLowercase(slice, content_type_buf);
|
||||
blob.content_type_allocated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,7 +399,8 @@ pub const StreamStart = union(Tag) {
|
||||
}
|
||||
|
||||
if (value.get(globalThis, "chunkSize")) |chunkSize| {
|
||||
return .{ .chunk_size = @intCast(Blob.SizeType, @truncate(i52, chunkSize.toInt64())) };
|
||||
if (chunkSize.isNumber())
|
||||
return .{ .chunk_size = @intCast(Blob.SizeType, @truncate(i52, chunkSize.toInt64())) };
|
||||
}
|
||||
|
||||
return .{ .empty = {} };
|
||||
@@ -432,8 +433,10 @@ pub const StreamStart = union(Tag) {
|
||||
}
|
||||
|
||||
if (value.get(globalThis, "highWaterMark")) |chunkSize| {
|
||||
empty = false;
|
||||
chunk_size = @intCast(JSC.WebCore.Blob.SizeType, @max(0, @truncate(i51, chunkSize.toInt64())));
|
||||
if (chunkSize.isNumber()) {
|
||||
empty = false;
|
||||
chunk_size = @intCast(JSC.WebCore.Blob.SizeType, @max(0, @truncate(i51, chunkSize.toInt64())));
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty) {
|
||||
@@ -450,7 +453,8 @@ pub const StreamStart = union(Tag) {
|
||||
var chunk_size: JSC.WebCore.Blob.SizeType = 0;
|
||||
|
||||
if (value.get(globalThis, "highWaterMark")) |chunkSize| {
|
||||
chunk_size = @intCast(JSC.WebCore.Blob.SizeType, @max(0, @truncate(i51, chunkSize.toInt64())));
|
||||
if (chunkSize.isNumber())
|
||||
chunk_size = @intCast(JSC.WebCore.Blob.SizeType, @max(0, @truncate(i51, chunkSize.toInt64())));
|
||||
}
|
||||
|
||||
if (value.get(globalThis, "path")) |path| {
|
||||
@@ -485,8 +489,10 @@ pub const StreamStart = union(Tag) {
|
||||
var chunk_size: JSC.WebCore.Blob.SizeType = 2048;
|
||||
|
||||
if (value.get(globalThis, "highWaterMark")) |chunkSize| {
|
||||
empty = false;
|
||||
chunk_size = @intCast(JSC.WebCore.Blob.SizeType, @max(256, @truncate(i51, chunkSize.toInt64())));
|
||||
if (chunkSize.isNumber()) {
|
||||
empty = false;
|
||||
chunk_size = @intCast(JSC.WebCore.Blob.SizeType, @max(256, @truncate(i51, chunkSize.toInt64())));
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty) {
|
||||
|
||||
@@ -18,6 +18,23 @@ const MimeType = @This();
|
||||
value: string,
|
||||
category: Category,
|
||||
|
||||
pub const Map = bun.StringHashMap(MimeType);
|
||||
|
||||
pub fn createHashTable(allocator: std.mem.Allocator) !Map {
|
||||
@setCold(true);
|
||||
|
||||
const decls = comptime std.meta.declarations(all);
|
||||
|
||||
var map = Map.init(allocator);
|
||||
try map.ensureTotalCapacity(@truncate(u32, decls.len));
|
||||
@setEvalBranchQuota(4000);
|
||||
inline for (decls) |decl| {
|
||||
map.putAssumeCapacityNoClobber(decl.name, @field(all, decl.name));
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
pub fn canOpenInEditor(this: MimeType) bool {
|
||||
if (this.category == .text or this.category.isCode())
|
||||
return true;
|
||||
|
||||
56
test/js/web/fetch/blob.test.ts
Normal file
56
test/js/web/fetch/blob.test.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { test, expect } from "bun:test";
|
||||
|
||||
test("Blob.slice", () => {
|
||||
const blob = new Blob(["Bun", "Foo"]);
|
||||
const b1 = blob.slice(0, 3, "Text/HTML");
|
||||
expect(b1 instanceof Blob).toBeTruthy();
|
||||
expect(b1.size).toBe(3);
|
||||
expect(b1.type).toBe("text/html");
|
||||
const b2 = blob.slice(-1, 3);
|
||||
expect(b2.size).toBe(0);
|
||||
const b3 = blob.slice(100, 3);
|
||||
expect(b3.size).toBe(0);
|
||||
const b4 = blob.slice(0, 10);
|
||||
expect(b4.size).toBe(blob.size);
|
||||
|
||||
expect(blob.slice().size).toBe(blob.size);
|
||||
expect(blob.slice(0).size).toBe(blob.size);
|
||||
expect(blob.slice(NaN).size).toBe(blob.size);
|
||||
expect(blob.slice(0, Infinity).size).toBe(blob.size);
|
||||
expect(blob.slice(-Infinity).size).toBe(blob.size);
|
||||
expect(blob.slice(0, NaN).size).toBe(0);
|
||||
// @ts-expect-error
|
||||
expect(blob.slice(Symbol(), "-123").size).toBe(6);
|
||||
expect(blob.slice(Object.create(null), "-123").size).toBe(6);
|
||||
// @ts-expect-error
|
||||
expect(blob.slice(null, "-123").size).toBe(6);
|
||||
expect(blob.slice(0, 10).size).toBe(blob.size);
|
||||
expect(blob.slice("text/plain;charset=utf-8").type).toBe("text/plain;charset=utf-8");
|
||||
});
|
||||
|
||||
test("Blob.prototype.type setter", () => {
|
||||
var blob = new Blob(["Bun", "Foo"], { type: "text/foo" });
|
||||
expect(blob.type).toBe("text/foo");
|
||||
blob.type = "text/bar";
|
||||
expect(blob.type).toBe("text/bar");
|
||||
blob.type = "text/baz";
|
||||
expect(blob.type).toBe("text/baz");
|
||||
blob.type = "text/baz; charset=utf-8";
|
||||
expect(blob.type).toBe("text/baz; charset=utf-8");
|
||||
// @ts-expect-error
|
||||
blob.type = NaN;
|
||||
expect(blob.type).toBe("");
|
||||
// @ts-expect-error
|
||||
blob.type = Symbol();
|
||||
expect(blob.type).toBe("");
|
||||
});
|
||||
|
||||
test("new Blob", () => {
|
||||
var blob = new Blob(["Bun", "Foo"], { type: "text/foo" });
|
||||
expect(blob.size).toBe(6);
|
||||
expect(blob.type).toBe("text/foo");
|
||||
|
||||
blob = new Blob(["Bun", "Foo"], { type: "\u1234" });
|
||||
expect(blob.size).toBe(6);
|
||||
expect(blob.type).toBe("");
|
||||
});
|
||||
Reference in New Issue
Block a user