aboutsummaryrefslogtreecommitdiff
path: root/src/javascript/jsc
diff options
context:
space:
mode:
Diffstat (limited to 'src/javascript/jsc')
-rw-r--r--src/javascript/jsc/api/bun.zig57
-rw-r--r--src/javascript/jsc/bindings/bindings.cpp21
-rw-r--r--src/javascript/jsc/test/jest.zig12
3 files changed, 80 insertions, 10 deletions
diff --git a/src/javascript/jsc/api/bun.zig b/src/javascript/jsc/api/bun.zig
index 8228139de..72d61d2e9 100644
--- a/src/javascript/jsc/api/bun.zig
+++ b/src/javascript/jsc/api/bun.zig
@@ -1623,8 +1623,49 @@ pub export fn Bun__escapeHTML(
const input_value = arguments[0];
const zig_str = input_value.getZigString(globalObject);
+ if (zig_str.len == 0)
+ return ZigString.Empty.toValue(globalObject);
+
if (zig_str.is16Bit()) {
- return input_value;
+ var input_slice = zig_str.utf16SliceAligned();
+ var escaped_html = strings.escapeHTMLForUTF16Input(globalObject.bunVM().allocator, input_slice) catch {
+ globalObject.vm().throwError(globalObject, ZigString.init("Out of memory").toValue(globalObject));
+ return JSC.JSValue.jsUndefined();
+ };
+
+ if (escaped_html.ptr == input_slice.ptr and escaped_html.len == input_slice.len) {
+ return input_value;
+ }
+
+ if (input_slice.len == 1) {
+ // single character escaped strings are statically allocated
+ return ZigString.init(std.mem.sliceAsBytes(escaped_html)).to16BitValue(globalObject);
+ }
+
+ if (comptime Environment.allow_assert) {
+ // assert that re-encoding the string produces the same result
+ std.debug.assert(
+ std.mem.eql(
+ u16,
+ (strings.toUTF16Alloc(bun.default_allocator, strings.toUTF8Alloc(bun.default_allocator, escaped_html) catch unreachable, false) catch unreachable).?,
+ escaped_html,
+ ),
+ );
+
+ // assert we do not allocate a new string unnecessarily
+ std.debug.assert(
+ !std.mem.eql(
+ u16,
+ input_slice,
+ escaped_html,
+ ),
+ );
+
+ // the output should always be longer than the input
+ std.debug.assert(escaped_html.len > input_slice.len);
+ }
+
+ return ZigString.from16(escaped_html.ptr, escaped_html.len).toExternalValue(globalObject);
} else {
var input_slice = zig_str.slice();
var escaped_html = strings.escapeHTMLForLatin1Input(globalObject.bunVM().allocator, input_slice) catch {
@@ -1641,6 +1682,20 @@ pub export fn Bun__escapeHTML(
return ZigString.init(escaped_html).toValue(globalObject);
}
+ if (comptime Environment.allow_assert) {
+ // the output should always be longer than the input
+ std.debug.assert(escaped_html.len > input_slice.len);
+
+ // assert we do not allocate a new string unnecessarily
+ std.debug.assert(
+ !std.mem.eql(
+ u8,
+ input_slice,
+ escaped_html,
+ ),
+ );
+ }
+
return ZigString.init(escaped_html).toExternalValue(globalObject);
}
}
diff --git a/src/javascript/jsc/bindings/bindings.cpp b/src/javascript/jsc/bindings/bindings.cpp
index 7505a8a8f..a4435f06b 100644
--- a/src/javascript/jsc/bindings/bindings.cpp
+++ b/src/javascript/jsc/bindings/bindings.cpp
@@ -1101,23 +1101,26 @@ static void free_global_string(void* str, void* ptr, unsigned len)
JSC__JSValue ZigString__toExternalU16(const uint16_t* arg0, size_t len, JSC__JSGlobalObject* global)
{
- return JSC::JSValue::encode(JSC::JSValue(JSC::jsOwnedString(
- global->vm(),
- ExternalStringImpl::create(reinterpret_cast<const UChar*>(arg0), len, nullptr, free_global_string))));
+ auto ref = String(ExternalStringImpl::create(reinterpret_cast<const UChar*>(arg0), len, nullptr, free_global_string));
+
+ return JSC::JSValue::encode(JSC::JSValue(JSC::jsString(
+ global->vm(), WTFMove(ref))));
}
// This must be a globally allocated string
JSC__JSValue ZigString__toExternalValue(const ZigString* arg0, JSC__JSGlobalObject* arg1)
{
ZigString str = *arg0;
if (Zig::isTaggedUTF16Ptr(str.ptr)) {
- return JSC::JSValue::encode(JSC::JSValue(JSC::jsOwnedString(
+ auto ref = String(ExternalStringImpl::create(reinterpret_cast<const UChar*>(Zig::untag(str.ptr)), str.len, nullptr, free_global_string));
+
+ return JSC::JSValue::encode(JSC::JSValue(JSC::jsString(
+ arg1->vm(), WTFMove(ref))));
+ } else {
+ auto ref = String(ExternalStringImpl::create(Zig::untag(str.ptr), str.len, nullptr, free_global_string));
+ return JSC::JSValue::encode(JSC::JSValue(JSC::jsString(
arg1->vm(),
- ExternalStringImpl::create(reinterpret_cast<const UChar*>(Zig::untag(str.ptr)), str.len, nullptr, free_global_string))));
+ WTFMove(ref))));
}
-
- return JSC::JSValue::encode(JSC::JSValue(JSC::jsOwnedString(
- arg1->vm(),
- ExternalStringImpl::create(Zig::untag(str.ptr), str.len, nullptr, free_global_string))));
}
VirtualMachine* JSC__JSGlobalObject__bunVM(JSC__JSGlobalObject* arg0)
diff --git a/src/javascript/jsc/test/jest.zig b/src/javascript/jsc/test/jest.zig
index a07a4bcac..db6353d21 100644
--- a/src/javascript/jsc/test/jest.zig
+++ b/src/javascript/jsc/test/jest.zig
@@ -367,7 +367,16 @@ pub const Expect = struct {
this.scope.tests.items[this.test_id].counter.actual += 1;
const left = JSValue.fromRef(arguments[0]);
const right = JSValue.fromRef(this.value);
+
if (!left.isSameValue(right, ctx.ptr())) {
+ if (left.isString() and right.isString()) {
+ var left_slice = left.toSlice(ctx, getAllocator(ctx));
+ defer left_slice.deinit();
+ var right_slice = right.toSlice(ctx, getAllocator(ctx));
+ defer right_slice.deinit();
+ std.debug.assert(!strings.eqlLong(left_slice.slice(), right_slice.slice(), false));
+ }
+
var lhs_formatter: JSC.ZigConsoleClient.Formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = ctx.ptr() };
var rhs_formatter: JSC.ZigConsoleClient.Formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = ctx.ptr() };
@@ -381,8 +390,10 @@ pub const Expect = struct {
ctx,
exception,
);
+
return null;
}
+
return thisObject;
}
@@ -563,6 +574,7 @@ pub const ExpectPrototype = struct {
.scope = DescribeScope.active,
.test_id = DescribeScope.active.current_test_id,
};
+ expect_.value.?.value().ensureStillAlive();
return Expect.Class.make(ctx, expect_);
}
};