Compare commits

...

1 Commits

Author SHA1 Message Date
Meghan Denny
27f4389b4c wip: implement CompressionStream and DecompressionStream globals 2024-09-30 20:33:38 -07:00
19 changed files with 1559 additions and 70 deletions

View File

@@ -104,6 +104,12 @@ Bun implements the following globals.
---
- [`CompressionStream`](https://developer.mozilla.org/en-US/docs/Web/API/CompressionStream)
- Web
- Also [`DecompressionStream`](https://developer.mozilla.org/en-US/docs/Web/API/DecompressionStream)
---
- [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console)
- Web
-  
@@ -140,6 +146,12 @@ Bun implements the following globals.
---
- [`DecompressionStream`](https://developer.mozilla.org/en-US/docs/Web/API/DecompressionStream)
- Web
- Also [`CompressionStream`](https://developer.mozilla.org/en-US/docs/Web/API/CompressionStream)
---
- [`Event`](https://developer.mozilla.org/en-US/docs/Web/API/Event)
- Web
- Also [`ErrorEvent`](https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent) [`CloseEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent) [`MessageEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent).

View File

@@ -143,17 +143,30 @@ The following Web APIs are partially or completely supported.
---
- HTTP
- [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/fetch) [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers) [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal)
- [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/fetch)
[`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
[`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request)
[`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers)
[`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)
[`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal)
---
- URLs
- [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL) [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)
- [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL)
[`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)
---
- Streams
- [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) [`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream) [`TransformStream`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream) [`ByteLengthQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/ByteLengthQueuingStrategy) [`CountQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/CountQueuingStrategy) and associated classes
- [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)
[`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream)
[`TransformStream`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream)
[`ByteLengthQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/ByteLengthQueuingStrategy)
[`CountQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/CountQueuingStrategy)
[`CompressionStream`](https://developer.mozilla.org/en-US/docs/Web/API/CompressionStream)
[`DecompressionStream`](https://developer.mozilla.org/en-US/docs/Web/API/DecompressionStream)
and associated classes
---
@@ -168,29 +181,36 @@ The following Web APIs are partially or completely supported.
---
- Encoding and decoding
- [`atob`](https://developer.mozilla.org/en-US/docs/Web/API/atob) [`btoa`](https://developer.mozilla.org/en-US/docs/Web/API/btoa) [`TextEncoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder) [`TextDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder)
- [`atob`](https://developer.mozilla.org/en-US/docs/Web/API/atob)
[`btoa`](https://developer.mozilla.org/en-US/docs/Web/API/btoa)
[`TextEncoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder)
[`TextDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder)
---
- Timeouts
- [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout) [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout)
- [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout)
[`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout)
---
- Intervals
- [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval)[`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval)
- [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval)
[`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval)
---
- Crypto
- [`crypto`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto) [`SubtleCrypto`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto)
- [`crypto`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto)
[`SubtleCrypto`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto)
[`CryptoKey`](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey)
---
- Debugging
- [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console) [`performance`](https://developer.mozilla.org/en-US/docs/Web/API/Performance)
- [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console)
[`performance`](https://developer.mozilla.org/en-US/docs/Web/API/Performance)
---
@@ -205,7 +225,10 @@ The following Web APIs are partially or completely supported.
---
- User interaction
- [`alert`](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert) [`confirm`](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm) [`prompt`](https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt) (intended for interactive CLIs)
- [`alert`](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert)
[`confirm`](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm)
[`prompt`](https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt)
(intended for interactive CLIs)
<!-- - Blocking. Prints the alert message to terminal and awaits `[ENTER]` before proceeding. -->
<!-- - Blocking. Prints confirmation message and awaits `[y/N]` input from user. Returns `true` if user entered `y` or `Y`, `false` otherwise.
@@ -220,7 +243,10 @@ The following Web APIs are partially or completely supported.
- Events
- [`EventTarget`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget)
[`Event`](https://developer.mozilla.org/en-US/docs/Web/API/Event) [`ErrorEvent`](https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent) [`CloseEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent) [`MessageEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent)
[`Event`](https://developer.mozilla.org/en-US/docs/Web/API/Event)
[`ErrorEvent`](https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent)
[`CloseEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent)
[`MessageEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent)
---

View File

@@ -233,7 +233,7 @@ The table below lists all globals implemented by Node.js and Bun's current compa
### [`CompressionStream`](https://developer.mozilla.org/en-US/docs/Web/API/CompressionStream)
🔴 Not implemented.
🟢 Fully implemented.
### [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console)
@@ -261,7 +261,7 @@ The table below lists all globals implemented by Node.js and Bun's current compa
### [`DecompressionStream`](https://developer.mozilla.org/en-US/docs/Web/API/DecompressionStream)
🔴 Not implemented.
🟢 Fully implemented.
### [`Event`](https://developer.mozilla.org/en-US/docs/Web/API/Event)

View File

@@ -688,6 +688,18 @@ declare global {
new <W = any>(underlyingSink?: Bun.UnderlyingSink<W>, strategy?: QueuingStrategy<W>): WritableStream<W>;
};
type CompressionFormat = "deflate" | "deflate-raw" | "gzip";
type CompressionStream<R = any, W = any> = import("stream/web").CompressionStream<R, W>;
const CompressionStream: {
prototype: CompressionStream;
new <R = any, W = any>(format: CompressionFormat): CompressionStream<R, W>;
};
type DecompressionStream<R = any, W = any> = import("stream/web").DecompressionStream<R, W>;
const DecompressionStream: {
prototype: DecompressionStream;
new <R = any, W = any>(format: CompressionFormat): DecompressionStream<R, W>;
};
interface Worker extends _Worker {}
var Worker: typeof globalThis extends {
onerror: any;

View File

@@ -116,6 +116,8 @@ ReadableStreamDefaultReader;
ReadableStreamDefaultController;
// ReadableByteStreamController;
WritableStreamDefaultWriter;
CompressionStream;
DecompressionStream;
function stuff(arg: Blob): any;
function stuff(arg: WebSocket): any;
@@ -135,6 +137,8 @@ function stuff(arg: TextDecoder): any;
function stuff(arg: ReadableStreamDefaultReader): any;
function stuff(arg: ReadableStreamDefaultController): any;
function stuff(arg: WritableStreamDefaultWriter): any;
function stuff(arg: CompressionStream): any;
function stuff(arg: DecompressionStream): any;
function stuff(arg: any) {
return "asfd";
}
@@ -301,6 +305,16 @@ const writableStream = new WritableStream();
const ws = new WebSocket("ws://www.host.com/path");
ws.send("asdf");
}
{
const a = new CompressionStream("gzip");
a.readable;
a.writable;
}
{
const a = new DecompressionStream("gzip");
a.readable;
a.writable;
}
atob("asf");
btoa("asdf");

View File

@@ -21,10 +21,10 @@
setInterval functionSetInterval Function 1
setTimeout functionSetTimeout Function 1
structuredClone functionStructuredClone Function 2
global GlobalObject_getGlobalThis PropertyCallback
EventSource getEventSourceConstructor PropertyCallback
Bun GlobalObject::m_bunObject CellProperty|DontDelete|ReadOnly
File GlobalObject::m_JSDOMFileConstructor CellProperty
crypto GlobalObject::m_cryptoObject CellProperty
@@ -36,7 +36,9 @@
Buffer GlobalObject::m_JSBufferClassStructure ClassStructure
BuildError GlobalObject::m_JSBuildMessage ClassStructure
BuildMessage GlobalObject::m_JSBuildMessage ClassStructure
CompressionStream GlobalObject::m_JSCompressionStream ClassStructure
Crypto GlobalObject::m_JSCrypto ClassStructure
DecompressionStream GlobalObject::m_JSDecompressionStream ClassStructure
HTMLRewriter GlobalObject::m_JSHTMLRewriter ClassStructure
Request GlobalObject::m_JSRequest ClassStructure
ResolveError GlobalObject::m_JSResolveMessage ClassStructure

View File

@@ -2959,11 +2959,11 @@ pub const JSGlobalObject = opaque {
typename: []const u8,
value: JSValue,
) JSValue {
const ty_str = value.jsTypeString(this).toSlice(this, bun.default_allocator);
defer ty_str.deinit();
this.ERR_INVALID_ARG_TYPE("The \"{s}\" argument must be of type {s}. Received {}", .{ argname, typename, bun.fmt.quote(ty_str.slice()) }).throw();
var formatter = ConsoleObject.Formatter{ .globalThis = this };
this.ERR_INVALID_ARG_TYPE("The \"{s}\" argument must be of type {s}. Received {}", .{ argname, typename, value.toFmt(&formatter) }).throw();
return .zero;
}
pub fn throwInvalidArgumentRangeValue(
this: *JSGlobalObject,
argname: []const u8,

View File

@@ -76,4 +76,6 @@ pub const Classes = struct {
pub const TextEncoderStreamEncoder = JSC.WebCore.TextEncoderStreamEncoder;
pub const NativeZlib = JSC.API.NativeZlib;
pub const NativeBrotli = JSC.API.NativeBrotli;
pub const CompressionStream = JSC.API.CompressionStream;
pub const DecompressionStream = JSC.API.DecompressionStream;
};

View File

@@ -18,7 +18,7 @@ pub fn throwErrInvalidArgValue(
globalThis: *JSGlobalObject,
comptime fmt: [:0]const u8,
args: anytype,
) !void {
) error{InvalidArgument} {
@setCold(true);
globalThis.ERR_INVALID_ARG_VALUE(fmt, args).throw();
return error.InvalidArgument;
@@ -28,7 +28,7 @@ pub fn throwErrInvalidArgTypeWithMessage(
globalThis: *JSGlobalObject,
comptime fmt: [:0]const u8,
args: anytype,
) !void {
) error{InvalidArgument} {
@setCold(true);
globalThis.ERR_INVALID_ARG_TYPE(fmt, args).throw();
return error.InvalidArgument;
@@ -40,17 +40,18 @@ pub fn throwErrInvalidArgType(
name_args: anytype,
comptime expected_type: []const u8,
value: JSValue,
) !void {
) error{InvalidArgument} {
@setCold(true);
const actual_type = getTypeName(globalThis, value);
try throwErrInvalidArgTypeWithMessage(globalThis, "\"" ++ name_fmt ++ "\" property must be of type {s}, got {s}", name_args ++ .{ expected_type, actual_type });
const kind = if (comptime bun.strings.startsWith(name_fmt, "options.")) "property" else "argument";
return throwErrInvalidArgTypeWithMessage(globalThis, "\"" ++ name_fmt ++ "\" " ++ kind ++ " must be of type {s}, got {s}", name_args ++ .{ expected_type, actual_type });
}
pub fn throwRangeError(
globalThis: *JSGlobalObject,
comptime fmt: [:0]const u8,
args: anytype,
) !void {
) error{InvalidArgument} {
@setCold(true);
globalThis.ERR_OUT_OF_RANGE(fmt, args).throw();
return error.InvalidArgument;
@@ -78,44 +79,44 @@ pub fn validateInt32(globalThis: *JSGlobalObject, value: JSValue, comptime name_
const max = max_value orelse std.math.maxInt(i32);
// The defaults for min and max correspond to the limits of 32-bit integers.
if (!value.isNumber()) {
try throwErrInvalidArgType(globalThis, name_fmt, name_args, "number", value);
return throwErrInvalidArgType(globalThis, name_fmt, name_args, "number", value);
}
if (!value.isInt32()) {
var formatter = JSC.ConsoleObject.Formatter{ .globalThis = globalThis };
try throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be an integer. Received {}", name_args ++ .{value.toFmt(&formatter)});
return throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be an integer. Received {}", name_args ++ .{value.toFmt(&formatter)});
}
const num = value.asInt32();
if (num < min or num > max) {
var formatter = JSC.ConsoleObject.Formatter{ .globalThis = globalThis };
try throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be >= {d} and <= {d}. Received {}", name_args ++ .{ min, max, value.toFmt(&formatter) });
return throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be >= {d} and <= {d}. Received {}", name_args ++ .{ min, max, value.toFmt(&formatter) });
}
return num;
}
pub fn validateUint32(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype, greater_than_zero: bool) !u32 {
if (!value.isNumber()) {
try throwErrInvalidArgType(globalThis, name_fmt, name_args, "number", value);
return throwErrInvalidArgType(globalThis, name_fmt, name_args, "number", value);
}
if (!value.isAnyInt()) {
try throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be an integer. Received {s}", name_args ++ .{value});
return throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be an integer. Received {s}", name_args ++ .{value});
}
const num: i64 = value.asInt52();
const min: i64 = if (greater_than_zero) 1 else 0;
const max: i64 = @intCast(std.math.maxInt(u32));
if (num < min or num > max) {
try throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be >= {d} and <= {d}. Received {s}", name_args ++ .{ min, max, value });
return throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be >= {d} and <= {d}. Received {s}", name_args ++ .{ min, max, value });
}
return @truncate(num);
}
pub fn validateString(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype) !void {
if (!value.isString())
try throwErrInvalidArgType(globalThis, name_fmt, name_args, "string", value);
return throwErrInvalidArgType(globalThis, name_fmt, name_args, "string", value);
}
pub fn validateNumber(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype, min: ?f64, max: ?f64) !f64 {
if (!value.isNumber())
try throwErrInvalidArgType(globalThis, name_fmt, name_args, "number", value);
return throwErrInvalidArgType(globalThis, name_fmt, name_args, "number", value);
const num: f64 = value.asNumber();
var valid = true;
@@ -130,11 +131,11 @@ pub fn validateNumber(globalThis: *JSGlobalObject, value: JSValue, comptime name
}
if (!valid) {
if (min != null and max != null) {
try throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be >= {d} and <= {d}. Received {s}", name_args ++ .{ min, max, value });
return throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be >= {d} and <= {d}. Received {s}", name_args ++ .{ min, max, value });
} else if (min != null) {
try throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be >= {d}. Received {s}", name_args ++ .{ max, value });
return throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must be >= {d}. Received {s}", name_args ++ .{ max, value });
} else {
try throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must and <= {d}. Received {s}", name_args ++ .{ max, value });
return throwRangeError(globalThis, "The value of \"" ++ name_fmt ++ "\" is out of range. It must and <= {d}. Received {s}", name_args ++ .{ max, value });
}
}
return num;
@@ -142,7 +143,7 @@ pub fn validateNumber(globalThis: *JSGlobalObject, value: JSValue, comptime name
pub fn validateBoolean(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype) !bool {
if (!value.isBoolean())
try throwErrInvalidArgType(globalThis, name_fmt, name_args, "boolean", value);
return throwErrInvalidArgType(globalThis, name_fmt, name_args, "boolean", value);
return value.asBoolean();
}
@@ -155,23 +156,23 @@ pub const ValidateObjectOptions = packed struct {
pub fn validateObject(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype, comptime options: ValidateObjectOptions) !void {
if (comptime !options.allow_nullable and !options.allow_array and !options.allow_function) {
if (value.isNull() or value.jsType().isArray()) {
try throwErrInvalidArgType(globalThis, name_fmt, name_args, "object", value);
return throwErrInvalidArgType(globalThis, name_fmt, name_args, "object", value);
}
if (!value.isObject()) {
try throwErrInvalidArgType(globalThis, name_fmt, name_args, "object", value);
return throwErrInvalidArgType(globalThis, name_fmt, name_args, "object", value);
}
} else {
if (!options.allow_nullable and value.isNull()) {
try throwErrInvalidArgType(globalThis, name_fmt, name_args, "object", value);
return throwErrInvalidArgType(globalThis, name_fmt, name_args, "object", value);
}
if (!options.allow_array and value.jsType().isArray()) {
try throwErrInvalidArgType(globalThis, name_fmt, name_args, "object", value);
return throwErrInvalidArgType(globalThis, name_fmt, name_args, "object", value);
}
if (!value.isObject() and (!options.allow_function or !value.jsType().isFunction())) {
try throwErrInvalidArgType(globalThis, name_fmt, name_args, "object", value);
return throwErrInvalidArgType(globalThis, name_fmt, name_args, "object", value);
}
}
}
@@ -179,11 +180,11 @@ pub fn validateObject(globalThis: *JSGlobalObject, value: JSValue, comptime name
pub fn validateArray(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype, comptime min_length: ?i32) !void {
if (!value.jsType().isArray()) {
const actual_type = getTypeName(globalThis, value);
try throwErrInvalidArgTypeWithMessage(globalThis, "\"" ++ name_fmt ++ "\" property must be an instance of Array, got {s}", name_args ++ .{actual_type});
return throwErrInvalidArgTypeWithMessage(globalThis, "\"" ++ name_fmt ++ "\" property must be an instance of Array, got {s}", name_args ++ .{actual_type});
}
if (comptime min_length != null) {
if (value.getLength(globalThis) < min_length) {
try throwErrInvalidArgValue(globalThis, name_fmt ++ " must be longer than {d}", name_args ++ .{min_length});
return throwErrInvalidArgValue(globalThis, name_fmt ++ " must be longer than {d}", name_args ++ .{min_length});
}
}
}
@@ -194,7 +195,7 @@ pub fn validateStringArray(globalThis: *JSGlobalObject, value: JSValue, comptime
var iter = value.arrayIterator(globalThis);
while (iter.next()) |item| {
if (!item.isString()) {
try throwErrInvalidArgType(globalThis, name_fmt ++ "[{d}]", name_args ++ .{i}, "string", value);
return throwErrInvalidArgType(globalThis, name_fmt ++ "[{d}]", name_args ++ .{i}, "string", value);
}
i += 1;
}
@@ -207,7 +208,7 @@ pub fn validateBooleanArray(globalThis: *JSGlobalObject, value: JSValue, comptim
var iter = value.arrayIterator(globalThis);
while (iter.next()) |item| {
if (!item.isBoolean()) {
try throwErrInvalidArgType(globalThis, name_fmt ++ "[{d}]", name_args ++ .{i}, "boolean", value);
return throwErrInvalidArgType(globalThis, name_fmt ++ "[{d}]", name_args ++ .{i}, "boolean", value);
}
i += 1;
}
@@ -216,16 +217,19 @@ pub fn validateBooleanArray(globalThis: *JSGlobalObject, value: JSValue, comptim
pub fn validateFunction(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype) !JSValue {
if (!value.jsType().isFunction())
try throwErrInvalidArgType(globalThis, name_fmt, name_args, "function", value);
return throwErrInvalidArgType(globalThis, name_fmt, name_args, "function", value);
return value;
}
pub fn validateUndefined(globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype) !void {
if (!value.isUndefined())
try throwErrInvalidArgType(globalThis, name_fmt, name_args, "undefined", value);
return throwErrInvalidArgType(globalThis, name_fmt, name_args, "undefined", value);
}
pub fn validateStringEnum(comptime T: type, globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype) !T {
if (!value.isString()) {
return throwErrInvalidArgType(globalThis, name_fmt, name_args, "string", value);
}
const str = value.toBunString(globalThis);
defer str.deref();
inline for (@typeInfo(T).Enum.fields) |enum_field| {
@@ -236,10 +240,9 @@ pub fn validateStringEnum(comptime T: type, globalThis: *JSGlobalObject, value:
const values_info = comptime blk: {
var out: []const u8 = "";
for (@typeInfo(T).Enum.fields, 0..) |enum_field, i| {
out = out ++ (if (i > 0) "|" else "") ++ enum_field.name;
out = out ++ (if (i > 0) ", " else "") ++ enum_field.name;
}
break :blk out;
};
try throwErrInvalidArgTypeWithMessage(globalThis, name_fmt ++ " must be one of: {s}", name_args ++ .{values_info});
return error.InvalidArgument;
return throwErrInvalidArgValue(globalThis, "\"" ++ name_fmt ++ "\" argument must be one of: {s}", name_args ++ .{values_info});
}

View File

@@ -0,0 +1,27 @@
import { define } from "../../codegen/class-definitions";
export default [
define({
name: "CompressionStream",
construct: true,
finalize: true,
klass: {},
JSType: "0b11101110",
proto: {
readable: { getter: "get_readable", setter: "set_noop" },
writable: { getter: "get_writable", setter: "set_noop" },
},
}),
define({
name: "DecompressionStream",
construct: true,
finalize: true,
klass: {},
JSType: "0b11101110",
proto: {
readable: { getter: "get_readable", setter: "set_noop" },
writable: { getter: "get_writable", setter: "set_noop" },
},
}),
];

View File

@@ -0,0 +1,104 @@
const std = @import("std");
const bun = @import("root").bun;
const Environment = bun.Environment;
const JSC = bun.JSC;
const string = bun.string;
const Output = bun.Output;
const ZigString = JSC.ZigString;
const validators = @import("./../node/util/validators.zig");
pub const CompressionStream = struct {
pub usingnamespace bun.NewRefCounted(@This(), deinit);
pub usingnamespace JSC.Codegen.JSCompressionStream;
ref_count: u32 = 1,
format: Format,
pub fn constructor(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) ?*@This() {
const arguments = callframe.argumentsUndef(1).ptr;
const format = validators.validateStringEnum(Format, globalThis, arguments[0], "format", .{}) catch return null;
return CompressionStream.new(.{
.format = format,
});
}
pub fn finalize(this: *@This()) void {
this.deref();
}
pub fn deinit(this: *@This()) void {
this.destroy();
}
pub fn get_readable(this: *@This(), globalThis: *JSC.JSGlobalObject) JSC.JSValue {
_ = this;
_ = globalThis;
return .undefined;
}
pub fn get_writable(this: *@This(), globalThis: *JSC.JSGlobalObject) JSC.JSValue {
_ = this;
_ = globalThis;
return .undefined;
}
pub fn set_noop(this: *@This(), globalThis: *JSC.JSGlobalObject, newvalue: JSC.JSValue) bool {
_ = this;
_ = globalThis;
_ = newvalue;
return true;
}
};
pub const DecompressionStream = struct {
pub usingnamespace bun.NewRefCounted(@This(), deinit);
pub usingnamespace JSC.Codegen.JSCompressionStream;
ref_count: u32 = 1,
format: Format,
pub fn constructor(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) ?*@This() {
const arguments = callframe.argumentsUndef(1).ptr;
const format = validators.validateStringEnum(Format, globalThis, arguments[0], "format", .{}) catch return null;
return DecompressionStream.new(.{
.format = format,
});
}
pub fn finalize(this: *@This()) void {
this.deref();
}
pub fn deinit(this: *@This()) void {
this.destroy();
}
pub fn get_readable(this: *@This(), globalThis: *JSC.JSGlobalObject) JSC.JSValue {
_ = this;
_ = globalThis;
return .undefined;
}
pub fn get_writable(this: *@This(), globalThis: *JSC.JSGlobalObject) JSC.JSValue {
_ = this;
_ = globalThis;
return .undefined;
}
pub fn set_noop(this: *@This(), globalThis: *JSC.JSGlobalObject, newvalue: JSC.JSValue) bool {
_ = this;
_ = globalThis;
_ = newvalue;
return true;
}
};
pub const Format = enum {
deflate,
@"deflate-raw",
gzip,
};

View File

@@ -53,6 +53,8 @@ export const globalsToPrefix = [
"ReadableStreamDefaultReader",
"TransformStream",
"TransformStreamDefaultController",
"CompressionStream",
"DecompressionStream",
"Uint8Array",
"String",
"Buffer",

View File

@@ -54,6 +54,7 @@ using namespace JSC;
macro(closeRequest) \
macro(closeRequested) \
macro(code) \
macro(CompressionStream) \
macro(connect) \
macro(controlledReadableStream) \
macro(controller) \
@@ -71,6 +72,7 @@ using namespace JSC;
macro(data) \
macro(dataView) \
macro(decode) \
macro(DecompressionStream) \
macro(delimiter) \
macro(destroy) \
macro(dir) \

View File

@@ -15,6 +15,6 @@ export default {
CountQueuingStrategy,
TextEncoderStream,
TextDecoderStream,
CompressionStream: undefined,
DecompressionStream: undefined,
CompressionStream,
DecompressionStream,
};

View File

@@ -51,6 +51,8 @@ pub const API = struct {
pub const H2FrameParser = @import("./bun.js/api/bun/h2_frame_parser.zig").H2FrameParser;
pub const NativeZlib = @import("./bun.js/node/node_zlib_binding.zig").SNativeZlib;
pub const NativeBrotli = @import("./bun.js/node/node_zlib_binding.zig").SNativeBrotli;
pub const CompressionStream = @import("./bun.js/webcore/compression.zig").CompressionStream;
pub const DecompressionStream = @import("./bun.js/webcore/compression.zig").DecompressionStream;
};
pub const Postgres = @import("./sql/postgres.zig");
pub const DNS = @import("./bun.js/api/bun/dns_resolver.zig");

View File

@@ -106,22 +106,6 @@ delete console.timeLog;
delete console.assert;
Bun.generateHeapSnapshot = () => {};
const TODOs = [
"ByteLengthQueuingStrategy",
"CountQueuingStrategy",
"ReadableByteStreamController",
"ReadableStream",
"ReadableStreamBYOBReader",
"ReadableStreamBYOBRequest",
"ReadableStreamDefaultController",
"ReadableStreamDefaultReader",
"TransformStream",
"TransformStreamDefaultController",
"WritableStream",
"WritableStreamDefaultController",
"WritableStreamDefaultWriter",
];
const ignoreList = [
Object.prototype,
Function.prototype,
@@ -155,13 +139,10 @@ const ignoreList = [
RegExp.prototype,
Date.prototype,
String.prototype,
// TODO: getFunctionRealm() on these.
ReadableStream.prototype,
];
const constructBanned = banned;
const callBanned = [...TODOs, ...banned];
const callBanned = [...banned];
function allThePropertyNames(object, banned) {
if (!object) {

View File

@@ -17,6 +17,8 @@ it("prototype", () => {
MessageEvent.prototype,
CloseEvent.prototype,
WebSocket.prototype,
CompressionStream.prototype,
DecompressionStream.prototype,
];
for (let prototype of prototypes) {

View File

@@ -18,6 +18,8 @@ test("Web Stream classes have correct Symbol.toStringTag", () => {
CountQueuingStrategy,
TransformStream,
TransformStreamDefaultController,
CompressionStream,
DecompressionStream,
];
classesToBeTested.forEach(cls => {

File diff suppressed because it is too large Load Diff