aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2023-05-26 16:28:09 -0700
committerGravatar GitHub <noreply@github.com> 2023-05-26 16:28:09 -0700
commit3a0735e16470cde796c1420f4db982af61bdab9c (patch)
treefd16595c122f085c5f18465f6db130e7f219dfbf /src/bun.js
parent42125b43513a76e3e18b2b76ecc4323b1d8e1b3a (diff)
downloadbun-3a0735e16470cde796c1420f4db982af61bdab9c.tar.gz
bun-3a0735e16470cde796c1420f4db982af61bdab9c.tar.zst
bun-3a0735e16470cde796c1420f4db982af61bdab9c.zip
Pretty formatter for `Headers` & `URLSearchParams` (#3081)
* Pretty formatter for `Headers` & `URLSearchParams` * cleanup * console.log on Headers, FormData, URLSearchParams will always quote the keys now --------- Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
Diffstat (limited to 'src/bun.js')
-rw-r--r--src/bun.js/bindings/JSDOMWrapper.h1
-rw-r--r--src/bun.js/bindings/bindings.zig4
-rw-r--r--src/bun.js/bindings/exports.zig75
-rw-r--r--src/bun.js/bindings/webcore/JSFetchHeaders.cpp2
-rw-r--r--src/bun.js/bindings/webcore/JSURLSearchParams.cpp58
-rw-r--r--src/bun.js/bindings/webcore/JSURLSearchParams.h2
-rw-r--r--src/bun.js/webcore/body.zig4
-rw-r--r--src/bun.js/webcore/request.zig14
-rw-r--r--src/bun.js/webcore/response.zig16
9 files changed, 147 insertions, 29 deletions
diff --git a/src/bun.js/bindings/JSDOMWrapper.h b/src/bun.js/bindings/JSDOMWrapper.h
index 726b2e8bf..f80585e72 100644
--- a/src/bun.js/bindings/JSDOMWrapper.h
+++ b/src/bun.js/bindings/JSDOMWrapper.h
@@ -58,6 +58,7 @@ static const uint8_t JSCommentNodeType = JSNodeType | NodeConstants::COMMENT_NOD
static const uint8_t JSCDATASectionNodeType = JSNodeType | NodeConstants::CDATA_SECTION_NODE;
static const uint8_t JSAttrNodeType = JSNodeType | NodeConstants::ATTRIBUTE_NODE;
static const uint8_t JSElementType = 0b11110000 | NodeConstants::ELEMENT_NODE;
+static const uint8_t JSAsJSONType = JSElementType;
static_assert(JSDOMWrapperType > JSC::LastJSCObjectType, "JSC::JSType offers the highest bit.");
static_assert(NodeConstants::LastNodeType <= JSNodeTypeMask, "NodeType should be represented in 4bit.");
diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig
index 42f0c5344..3bf2b9172 100644
--- a/src/bun.js/bindings/bindings.zig
+++ b/src/bun.js/bindings/bindings.zig
@@ -2980,6 +2980,10 @@ pub const JSValue = enum(JSValueReprInt) {
Event = 0b11101111,
DOMWrapper = 0b11101110,
Blob = 0b11111100,
+
+ /// This means that we don't have Zig bindings for the type yet, but it
+ /// implements .toJSON()
+ JSAsJSONType = 0b11110000 | 1,
_,
pub fn canGet(this: JSType) bool {
diff --git a/src/bun.js/bindings/exports.zig b/src/bun.js/bindings/exports.zig
index bfea93306..37fc7dabc 100644
--- a/src/bun.js/bindings/exports.zig
+++ b/src/bun.js/bindings/exports.zig
@@ -1182,6 +1182,7 @@ pub const ZigConsoleClient = struct {
depth: u16 = 0,
max_depth: u16 = 8,
quote_strings: bool = false,
+ quote_keys: bool = false,
failed: bool = false,
estimated_line_length: usize = 0,
always_newline_scope: bool = false,
@@ -1266,6 +1267,7 @@ pub const ZigConsoleClient = struct {
Promise,
JSON,
+ toJSON,
NativeCode,
ArrayBuffer,
@@ -1485,6 +1487,8 @@ pub const ZigConsoleClient = struct {
.GetterSetter, .CustomGetterSetter => .Getter,
+ .JSAsJSONType => .toJSON,
+
else => .JSON,
},
.cell = js_type,
@@ -1774,14 +1778,14 @@ pub const ZigConsoleClient = struct {
if (!is_symbol) {
// TODO: make this one pass?
- if (!key.is16Bit() and JSLexer.isLatin1Identifier(@TypeOf(key.slice()), key.slice())) {
+ if (!key.is16Bit() and (!this.quote_keys and JSLexer.isLatin1Identifier(@TypeOf(key.slice()), key.slice()))) {
this.addForNewLine(key.len + 1);
writer.print(
comptime Output.prettyFmt("<r>{}<d>:<r> ", enable_ansi_colors),
.{key},
);
- } else if (key.is16Bit() and JSLexer.isLatin1Identifier(@TypeOf(key.utf16SliceAligned()), key.utf16SliceAligned())) {
+ } else if (key.is16Bit() and (!this.quote_keys and JSLexer.isLatin1Identifier(@TypeOf(key.utf16SliceAligned()), key.utf16SliceAligned()))) {
this.addForNewLine(key.len + 1);
writer.print(
@@ -2156,20 +2160,41 @@ pub const ZigConsoleClient = struct {
} else if (value.as(JSC.WebCore.Blob)) |blob| {
blob.writeFormat(ZigConsoleClient.Formatter, this, writer_, enable_ansi_colors) catch {};
return;
+ } else if (value.as(JSC.FetchHeaders) != null) {
+ if (value.get(this.globalThis, "toJSON")) |toJSONFunction| {
+ this.addForNewLine("Headers ".len);
+ writer.writeAll(comptime Output.prettyFmt("<r>Headers ", enable_ansi_colors));
+ const prev_quote_keys = this.quote_keys;
+ this.quote_keys = true;
+ defer this.quote_keys = prev_quote_keys;
+
+ return this.printAs(
+ .Object,
+ Writer,
+ writer_,
+ toJSONFunction.callWithThis(this.globalThis, value, &.{}),
+ .Object,
+ enable_ansi_colors,
+ );
+ }
} else if (value.as(JSC.DOMFormData) != null) {
- const toJSONFunction = value.get(this.globalThis, "toJSON").?;
-
- this.addForNewLine("FormData (entries) ".len);
- writer.writeAll(comptime Output.prettyFmt("<r><blue>FormData<r> <d>(entries)<r> ", enable_ansi_colors));
-
- return this.printAs(
- .Object,
- Writer,
- writer_,
- toJSONFunction.callWithThis(this.globalThis, value, &.{}),
- .Object,
- enable_ansi_colors,
- );
+ if (value.get(this.globalThis, "toJSON")) |toJSONFunction| {
+ const prev_quote_keys = this.quote_keys;
+ this.quote_keys = true;
+ defer this.quote_keys = prev_quote_keys;
+
+ return this.printAs(
+ .Object,
+ Writer,
+ writer_,
+ toJSONFunction.callWithThis(this.globalThis, value, &.{}),
+ .Object,
+ enable_ansi_colors,
+ );
+ }
+
+ // this case should never happen
+ return this.printAs(.Undefined, Writer, writer_, .undefined, .Cell, enable_ansi_colors);
} else if (value.as(JSC.API.Bun.Timer.TimerObject)) |timer| {
this.addForNewLine("Timeout(# ) ".len + bun.fmt.fastDigitCount(@intCast(u64, @max(timer.id, 0))));
if (timer.kind == .setInterval) {
@@ -2317,6 +2342,20 @@ pub const ZigConsoleClient = struct {
this.writeIndent(Writer, writer_) catch {};
writer.writeAll("}");
},
+ .toJSON => {
+ if (value.get(this.globalThis, "toJSON")) |func| {
+ const result = func.callWithThis(this.globalThis, value, &.{});
+ if (result.toError() == null) {
+ const prev_quote_keys = this.quote_keys;
+ this.quote_keys = true;
+ defer this.quote_keys = prev_quote_keys;
+ this.printAs(.Object, Writer, writer_, result, value.jsType(), enable_ansi_colors);
+ return;
+ }
+ }
+
+ writer.writeAll("{}");
+ },
.JSON => {
var str = ZigString.init("");
value.jsonStringify(this.globalThis, this.indent, &str);
@@ -2844,7 +2883,13 @@ pub const ZigConsoleClient = struct {
.GlobalObject => this.printAs(.GlobalObject, Writer, writer, value, result.cell, enable_ansi_colors),
.Private => this.printAs(.Private, Writer, writer, value, result.cell, enable_ansi_colors),
.Promise => this.printAs(.Promise, Writer, writer, value, result.cell, enable_ansi_colors),
+
+ // Call JSON.stringify on the value
.JSON => this.printAs(.JSON, Writer, writer, value, result.cell, enable_ansi_colors),
+
+ // Call value.toJSON() and print as an object
+ .toJSON => this.printAs(.toJSON, Writer, writer, value, result.cell, enable_ansi_colors),
+
.NativeCode => this.printAs(.NativeCode, Writer, writer, value, result.cell, enable_ansi_colors),
.JSX => this.printAs(.JSX, Writer, writer, value, result.cell, enable_ansi_colors),
.Event => this.printAs(.Event, Writer, writer, value, result.cell, enable_ansi_colors),
diff --git a/src/bun.js/bindings/webcore/JSFetchHeaders.cpp b/src/bun.js/bindings/webcore/JSFetchHeaders.cpp
index 2e75cdc86..6bea5dc84 100644
--- a/src/bun.js/bindings/webcore/JSFetchHeaders.cpp
+++ b/src/bun.js/bindings/webcore/JSFetchHeaders.cpp
@@ -301,7 +301,7 @@ static const HashTableValue JSFetchHeadersPrototypeTableValues[] = {
{ "values"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsFetchHeadersPrototypeFunction_values, 0 } },
{ "forEach"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsFetchHeadersPrototypeFunction_forEach, 1 } },
{ "toJSON"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsFetchHeadersPrototypeFunction_toJSON, 0 } },
- { "count"_s, static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsFetchHeadersGetterCount, 0 } },
+ { "count"_s, static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsFetchHeadersGetterCount, 0 } },
// { "getSetCookie"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsFetchHeadersPrototypeFunction_getSetCookie, 0 } },
};
diff --git a/src/bun.js/bindings/webcore/JSURLSearchParams.cpp b/src/bun.js/bindings/webcore/JSURLSearchParams.cpp
index d80304684..a99587d40 100644
--- a/src/bun.js/bindings/webcore/JSURLSearchParams.cpp
+++ b/src/bun.js/bindings/webcore/JSURLSearchParams.cpp
@@ -56,6 +56,7 @@
#include "wtf/URL.h"
#include "wtf/Vector.h"
#include <variant>
+#include "GCDefferalContext.h"
namespace WebCore {
using namespace JSC;
@@ -69,6 +70,7 @@ static JSC_DECLARE_HOST_FUNCTION(jsURLSearchParamsPrototypeFunction_getAll);
static JSC_DECLARE_HOST_FUNCTION(jsURLSearchParamsPrototypeFunction_has);
static JSC_DECLARE_HOST_FUNCTION(jsURLSearchParamsPrototypeFunction_set);
static JSC_DECLARE_HOST_FUNCTION(jsURLSearchParamsPrototypeFunction_sort);
+static JSC_DECLARE_HOST_FUNCTION(jsURLSearchParamsPrototypeFunction_toJSON);
static JSC_DECLARE_HOST_FUNCTION(jsURLSearchParamsPrototypeFunction_entries);
static JSC_DECLARE_HOST_FUNCTION(jsURLSearchParamsPrototypeFunction_keys);
static JSC_DECLARE_HOST_FUNCTION(jsURLSearchParamsPrototypeFunction_values);
@@ -178,6 +180,7 @@ static const HashTableValue JSURLSearchParamsPrototypeTableValues[] = {
{ "values"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsURLSearchParamsPrototypeFunction_values, 0 } },
{ "forEach"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsURLSearchParamsPrototypeFunction_forEach, 1 } },
{ "toString"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsURLSearchParamsPrototypeFunction_toString, 0 } },
+ { "toJSON"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsURLSearchParamsPrototypeFunction_toJSON, 0 } },
{ "length"_s, static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsURLSearchParamsPrototype_getLength, 0 } },
};
@@ -393,6 +396,60 @@ JSC_DEFINE_HOST_FUNCTION(jsURLSearchParamsPrototypeFunction_toString, (JSGlobalO
return IDLOperation<JSURLSearchParams>::call<jsURLSearchParamsPrototypeFunction_toStringBody>(*lexicalGlobalObject, *callFrame, "toString");
}
+static inline JSC::EncodedJSValue jsURLSearchParamsPrototypeFunction_toJSONBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSURLSearchParams>::ClassParameter castedThis)
+{
+ auto& vm = JSC::getVM(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ UNUSED_PARAM(throwScope);
+ UNUSED_PARAM(callFrame);
+ auto& impl = castedThis->wrapped();
+ auto iter = impl.createIterator();
+
+ auto* obj = JSC::constructEmptyObject(lexicalGlobalObject, lexicalGlobalObject->objectPrototype(), impl.size() + 1);
+ obj->putDirect(vm, vm.propertyNames->toStringTagSymbol, jsNontrivialString(lexicalGlobalObject->vm(), "URLSearchParams"_s), JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::ReadOnly | 0);
+
+ RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+ WTF::HashSet<String> seenKeys;
+ for (auto entry = iter.next(); entry.has_value(); entry = iter.next()) {
+ auto& key = entry.value().key;
+ auto& value = entry.value().value;
+ auto ident = Identifier::fromString(vm, key);
+ if (seenKeys.contains(key)) {
+ JSValue jsValue = obj->getDirect(vm, ident);
+ if (jsValue.isString()) {
+ GCDeferralContext deferralContext(lexicalGlobalObject->vm());
+ JSC::ObjectInitializationScope initializationScope(lexicalGlobalObject->vm());
+
+ JSC::JSArray* array = JSC::JSArray::tryCreateUninitializedRestricted(
+ initializationScope, &deferralContext,
+ lexicalGlobalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous),
+ 2);
+
+ array->initializeIndex(initializationScope, 0, jsValue);
+ array->initializeIndex(initializationScope, 1, jsString(vm, value));
+ obj->putDirect(vm, ident, array, 0);
+ } else if (jsValue.isObject() && jsValue.getObject()->inherits<JSC::JSArray>()) {
+ JSC::JSArray* array = jsCast<JSC::JSArray*>(jsValue.getObject());
+ array->push(lexicalGlobalObject, jsString(vm, value));
+ RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+
+ } else {
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+ } else {
+ seenKeys.add(key);
+ obj->putDirect(vm, ident, jsString(vm, value), 0);
+ }
+ }
+
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(obj));
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsURLSearchParamsPrototypeFunction_toJSON, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ return IDLOperation<JSURLSearchParams>::call<jsURLSearchParamsPrototypeFunction_toJSONBody>(*lexicalGlobalObject, *callFrame, "toJSON");
+}
+
struct URLSearchParamsIteratorTraits {
static constexpr JSDOMIteratorType type = JSDOMIteratorType::Map;
using KeyType = IDLUSVString;
@@ -566,5 +623,4 @@ URLSearchParams* JSURLSearchParams::toWrapped(JSC::VM& vm, JSC::JSValue value)
return &wrapper->wrapped();
return nullptr;
}
-
}
diff --git a/src/bun.js/bindings/webcore/JSURLSearchParams.h b/src/bun.js/bindings/webcore/JSURLSearchParams.h
index b7e90a3fb..54abe1237 100644
--- a/src/bun.js/bindings/webcore/JSURLSearchParams.h
+++ b/src/bun.js/bindings/webcore/JSURLSearchParams.h
@@ -45,7 +45,7 @@ public:
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(), JSC::NonArray);
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::JSType(WebCore::JSAsJSONType), StructureFlags), info(), JSC::NonArray);
}
static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
diff --git a/src/bun.js/webcore/body.zig b/src/bun.js/webcore/body.zig
index b39fb1761..9cfa1f9ce 100644
--- a/src/bun.js/webcore/body.zig
+++ b/src/bun.js/webcore/body.zig
@@ -79,7 +79,7 @@ pub const Body = struct {
const Writer = @TypeOf(writer);
try formatter.writeIndent(Writer, writer);
- try writer.writeAll("bodyUsed: ");
+ try writer.writeAll(comptime Output.prettyFmt("<r>bodyUsed<d>:<r> ", enable_ansi_colors));
formatter.printAs(.Boolean, Writer, writer, JSC.JSValue.jsBoolean(this.value == .Used), .BooleanObject, enable_ansi_colors);
formatter.printComma(Writer, writer, enable_ansi_colors) catch unreachable;
try writer.writeAll("\n");
@@ -92,7 +92,7 @@ pub const Body = struct {
// }
try formatter.writeIndent(Writer, writer);
- try writer.writeAll("status: ");
+ try writer.writeAll(comptime Output.prettyFmt("<r>status<d>:<r> ", enable_ansi_colors));
formatter.printAs(.Double, Writer, writer, JSC.JSValue.jsNumber(this.init.status_code), .NumberObject, enable_ansi_colors);
if (this.value == .Blob) {
try formatter.printComma(Writer, writer, enable_ansi_colors);
diff --git a/src/bun.js/webcore/request.zig b/src/bun.js/webcore/request.zig
index 248b6a1bf..643fbb38b 100644
--- a/src/bun.js/webcore/request.zig
+++ b/src/bun.js/webcore/request.zig
@@ -133,18 +133,24 @@ pub const Request = struct {
defer formatter.indent -|= 1;
try formatter.writeIndent(Writer, writer);
- try writer.writeAll("method: \"");
+ try writer.writeAll(comptime Output.prettyFmt("<r>method<d>:<r> \"", enable_ansi_colors));
+
try writer.writeAll(bun.asByteSlice(@tagName(this.method)));
try writer.writeAll("\"");
formatter.printComma(Writer, writer, enable_ansi_colors) catch unreachable;
try writer.writeAll("\n");
try formatter.writeIndent(Writer, writer);
- try writer.writeAll("url: \"");
+ try writer.writeAll(comptime Output.prettyFmt("<r>url<d>:<r> ", enable_ansi_colors));
try this.ensureURL();
- try writer.print(comptime Output.prettyFmt("<r><b>{s}<r>", enable_ansi_colors), .{this.url});
+ try writer.print(comptime Output.prettyFmt("\"<b>{s}<r>\"", enable_ansi_colors), .{this.url});
+ formatter.printComma(Writer, writer, enable_ansi_colors) catch unreachable;
+ try writer.writeAll("\n");
+
+ try formatter.writeIndent(Writer, writer);
+ try writer.writeAll(comptime Output.prettyFmt("<r>headers<d>:<r> ", enable_ansi_colors));
+ formatter.printAs(.Private, Writer, writer, this.getHeaders(formatter.globalThis), .DOMWrapper, enable_ansi_colors);
- try writer.writeAll("\"");
if (this.body.value == .Blob) {
try writer.writeAll("\n");
try formatter.writeIndent(Writer, writer);
diff --git a/src/bun.js/webcore/response.zig b/src/bun.js/webcore/response.zig
index af69b8f95..8d1bfb961 100644
--- a/src/bun.js/webcore/response.zig
+++ b/src/bun.js/webcore/response.zig
@@ -120,7 +120,7 @@ pub const Response = struct {
pub const Props = struct {};
- pub fn writeFormat(this: *const Response, comptime Formatter: type, formatter: *Formatter, writer: anytype, comptime enable_ansi_colors: bool) !void {
+ pub fn writeFormat(this: *Response, comptime Formatter: type, formatter: *Formatter, writer: anytype, comptime enable_ansi_colors: bool) !void {
const Writer = @TypeOf(writer);
try writer.print("Response ({}) {{\n", .{bun.fmt.size(this.body.len())});
{
@@ -128,26 +128,32 @@ pub const Response = struct {
defer formatter.indent -|= 1;
try formatter.writeIndent(Writer, writer);
- try writer.writeAll("ok: ");
+ try writer.writeAll(comptime Output.prettyFmt("<r>ok<d>:<r> ", enable_ansi_colors));
formatter.printAs(.Boolean, Writer, writer, JSC.JSValue.jsBoolean(this.isOK()), .BooleanObject, enable_ansi_colors);
formatter.printComma(Writer, writer, enable_ansi_colors) catch unreachable;
try writer.writeAll("\n");
try formatter.writeIndent(Writer, writer);
- try writer.writeAll("url: \"");
+ try writer.writeAll(comptime Output.prettyFmt("<r>url<d>:<r> \"", enable_ansi_colors));
try writer.print(comptime Output.prettyFmt("<r><b>{s}<r>", enable_ansi_colors), .{this.url});
try writer.writeAll("\"");
formatter.printComma(Writer, writer, enable_ansi_colors) catch unreachable;
try writer.writeAll("\n");
try formatter.writeIndent(Writer, writer);
- try writer.writeAll("statusText: ");
+ try writer.writeAll(comptime Output.prettyFmt("<r>headers<d>:<r> ", enable_ansi_colors));
+ formatter.printAs(.Private, Writer, writer, this.getHeaders(formatter.globalThis), .DOMWrapper, enable_ansi_colors);
+ formatter.printComma(Writer, writer, enable_ansi_colors) catch unreachable;
+ try writer.writeAll("\n");
+
+ try formatter.writeIndent(Writer, writer);
+ try writer.writeAll(comptime Output.prettyFmt("<r>statusText<d>:<r> ", enable_ansi_colors));
try JSPrinter.writeJSONString(this.status_text, Writer, writer, .ascii);
formatter.printComma(Writer, writer, enable_ansi_colors) catch unreachable;
try writer.writeAll("\n");
try formatter.writeIndent(Writer, writer);
- try writer.writeAll("redirected: ");
+ try writer.writeAll(comptime Output.prettyFmt("<r>redirected<d>:<r> ", enable_ansi_colors));
formatter.printAs(.Boolean, Writer, writer, JSC.JSValue.jsBoolean(this.redirected), .BooleanObject, enable_ansi_colors);
formatter.printComma(Writer, writer, enable_ansi_colors) catch unreachable;
try writer.writeAll("\n");