mirror of
https://github.com/oven-sh/bun
synced 2026-02-13 04:18:58 +00:00
pass test-worker-message-event.js (#19614)
Co-authored-by: 190n <7763597+190n@users.noreply.github.com>
This commit is contained in:
@@ -16,6 +16,7 @@ const errors: ErrorCodeMapping = [
|
||||
["ABORT_ERR", Error, "AbortError"],
|
||||
["ERR_ACCESS_DENIED", Error],
|
||||
["ERR_AMBIGUOUS_ARGUMENT", TypeError],
|
||||
["ERR_ARG_NOT_ITERABLE", TypeError],
|
||||
["ERR_ASSERTION", Error],
|
||||
["ERR_ASYNC_CALLBACK", TypeError],
|
||||
["ERR_ASYNC_TYPE", TypeError],
|
||||
|
||||
@@ -278,9 +278,13 @@ JSC::EncodedJSValue throwConstructorScriptExecutionContextUnavailableError(JSC::
|
||||
return throwVMError(&lexicalGlobalObject, scope, createReferenceError(&lexicalGlobalObject, makeString(interfaceName, " constructor associated execution context is unavailable"_s)));
|
||||
}
|
||||
|
||||
void throwSequenceTypeError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope)
|
||||
void throwSequenceTypeError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, ASCIILiteral functionName, ASCIILiteral argumentName)
|
||||
{
|
||||
Bun::throwError(&lexicalGlobalObject, scope, Bun::ErrorCode::ERR_INVALID_ARG_TYPE, "Value is not a sequence"_s);
|
||||
if (functionName && argumentName) {
|
||||
Bun::throwError(&lexicalGlobalObject, scope, Bun::ErrorCode::ERR_ARG_NOT_ITERABLE, makeString(functionName, ": "_s, argumentName, " is not iterable."_s));
|
||||
} else {
|
||||
Bun::throwError(&lexicalGlobalObject, scope, Bun::ErrorCode::ERR_INVALID_ARG_TYPE, "Value is not a sequence"_s);
|
||||
}
|
||||
}
|
||||
|
||||
void throwNonFiniteTypeError(JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope)
|
||||
|
||||
@@ -45,7 +45,7 @@ void throwInvalidStateError(JSC::JSGlobalObject&, JSC::ThrowScope&, ASCIILiteral
|
||||
WEBCORE_EXPORT void throwNonFiniteTypeError(JSC::JSGlobalObject&, JSC::ThrowScope&);
|
||||
void throwNotSupportedError(JSC::JSGlobalObject&, JSC::ThrowScope&, ASCIILiteral);
|
||||
void throwSecurityError(JSC::JSGlobalObject&, JSC::ThrowScope&, const String& message);
|
||||
WEBCORE_EXPORT void throwSequenceTypeError(JSC::JSGlobalObject&, JSC::ThrowScope&);
|
||||
WEBCORE_EXPORT void throwSequenceTypeError(JSC::JSGlobalObject&, JSC::ThrowScope&, ASCIILiteral functionName = {}, ASCIILiteral argumentName = {});
|
||||
|
||||
WEBCORE_EXPORT JSC::EncodedJSValue throwArgumentMustBeEnumError(JSC::JSGlobalObject&, JSC::ThrowScope&, unsigned argumentIndex, ASCIILiteral argumentName, ASCIILiteral functionInterfaceName, ASCIILiteral functionName, ASCIILiteral expectedValues);
|
||||
WEBCORE_EXPORT JSC::EncodedJSValue throwArgumentMustBeFunctionError(JSC::JSGlobalObject&, JSC::ThrowScope&, unsigned argumentIndex, ASCIILiteral argumentName, ASCIILiteral functionInterfaceName, ASCIILiteral functionName);
|
||||
|
||||
@@ -267,7 +267,7 @@ void BroadcastChannel::dispatchMessage(Ref<SerializedScriptValue>&& message)
|
||||
auto& vm = JSC::getVM(globalObject);
|
||||
auto scope = DECLARE_CATCH_SCOPE(vm);
|
||||
Vector<RefPtr<MessagePort>> dummyPorts;
|
||||
auto event = MessageEvent::create(*globalObject, WTFMove(message), {}, {}, std::nullopt, WTFMove(dummyPorts));
|
||||
auto event = MessageEvent::create(*globalObject, WTFMove(message), {}, {}, nullptr, WTFMove(dummyPorts));
|
||||
if (UNLIKELY(scope.exception())) {
|
||||
// Currently, we assume that the only way we can get here is if we have a termination.
|
||||
RELEASE_ASSERT(vm.hasPendingTerminationException());
|
||||
|
||||
@@ -56,6 +56,8 @@ template<typename T> typename Converter<T>::ReturnType convert(JSC::JSGlobalObje
|
||||
template<typename T> typename Converter<T>::ReturnType convert(JSC::JSGlobalObject&, JSC::JSValue, JSC::JSObject&);
|
||||
template<typename T> typename Converter<T>::ReturnType convert(JSC::JSGlobalObject&, JSC::JSValue, JSDOMGlobalObject&);
|
||||
template<typename T, typename ExceptionThrower> typename Converter<T>::ReturnType convert(JSC::JSGlobalObject&, JSC::JSValue, ExceptionThrower&&);
|
||||
template<typename T, typename ExceptionThrower> typename Converter<T>::ReturnType convert(JSC::JSGlobalObject&, JSC::JSValue, ExceptionThrower&&, ASCIILiteral functionName, ASCIILiteral argumentName);
|
||||
|
||||
template<typename T, typename ExceptionThrower> typename Converter<T>::ReturnType convert(JSC::JSGlobalObject&, JSC::JSValue, JSC::JSObject&, ExceptionThrower&&);
|
||||
template<typename T, typename ExceptionThrower> typename Converter<T>::ReturnType convert(JSC::JSGlobalObject&, JSC::JSValue, JSDOMGlobalObject&, ExceptionThrower&&);
|
||||
|
||||
@@ -79,6 +81,11 @@ template<typename T, typename ExceptionThrower> inline typename Converter<T>::Re
|
||||
return Converter<T>::convert(lexicalGlobalObject, value, std::forward<ExceptionThrower>(exceptionThrower));
|
||||
}
|
||||
|
||||
template<typename T, typename ExceptionThrower> inline typename Converter<T>::ReturnType convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value, ExceptionThrower&& exceptionThrower, ASCIILiteral functionName, ASCIILiteral argumentName)
|
||||
{
|
||||
return Converter<T>::convert(lexicalGlobalObject, value, std::forward<ExceptionThrower>(exceptionThrower), functionName, argumentName);
|
||||
}
|
||||
|
||||
template<typename T, typename ExceptionThrower> inline typename Converter<T>::ReturnType convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value, JSC::JSObject& thisObject, ExceptionThrower&& exceptionThrower)
|
||||
{
|
||||
return Converter<T>::convert(lexicalGlobalObject, value, thisObject, std::forward<ExceptionThrower>(exceptionThrower));
|
||||
|
||||
@@ -60,6 +60,21 @@ struct GenericSequenceConverter {
|
||||
return WTFMove(result);
|
||||
}
|
||||
|
||||
template<typename ExceptionThrower = DefaultExceptionThrower>
|
||||
static ReturnType convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSObject* object, ExceptionThrower&& exceptionThrower = ExceptionThrower())
|
||||
{
|
||||
ReturnType result;
|
||||
forEachInIterable(&lexicalGlobalObject, object, [&result, &exceptionThrower](JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSValue nextValue) {
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
auto convertedValue = Converter<IDLType>::convert(*lexicalGlobalObject, nextValue, std::forward<ExceptionThrower>(exceptionThrower));
|
||||
if (UNLIKELY(scope.exception()))
|
||||
return;
|
||||
result.append(WTFMove(convertedValue));
|
||||
});
|
||||
return WTFMove(result);
|
||||
}
|
||||
|
||||
static ReturnType convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSObject* object, JSC::JSValue method)
|
||||
{
|
||||
return convert(lexicalGlobalObject, object, method, ReturnType());
|
||||
@@ -240,13 +255,58 @@ struct SequenceConverter {
|
||||
return result;
|
||||
}
|
||||
|
||||
static ReturnType convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value)
|
||||
template<typename ExceptionThrower = DefaultExceptionThrower>
|
||||
static ReturnType convertArray(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSArray* array, ExceptionThrower&& exceptionThrower = ExceptionThrower())
|
||||
{
|
||||
auto& vm = lexicalGlobalObject.vm();
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
unsigned length = array->length();
|
||||
|
||||
ReturnType result;
|
||||
if (!result.tryReserveCapacity(length)) {
|
||||
// FIXME: Is the right exception to throw?
|
||||
throwTypeError(&lexicalGlobalObject, scope);
|
||||
return {};
|
||||
}
|
||||
|
||||
JSC::IndexingType indexingType = array->indexingType() & JSC::IndexingShapeMask;
|
||||
|
||||
if (indexingType == JSC::ContiguousShape) {
|
||||
for (unsigned i = 0; i < length; i++) {
|
||||
auto indexValue = array->butterfly()->contiguous().at(array, i).get();
|
||||
if (!indexValue)
|
||||
indexValue = JSC::jsUndefined();
|
||||
|
||||
auto convertedValue = Converter<IDLType>::convert(lexicalGlobalObject, indexValue, std::forward<ExceptionThrower>(exceptionThrower));
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
|
||||
result.append(convertedValue);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < length; i++) {
|
||||
auto indexValue = array->getDirectIndex(&lexicalGlobalObject, i);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
|
||||
if (!indexValue)
|
||||
indexValue = JSC::jsUndefined();
|
||||
|
||||
auto convertedValue = Converter<IDLType>::convert(lexicalGlobalObject, indexValue, std::forward<ExceptionThrower>(exceptionThrower));
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
|
||||
result.append(convertedValue);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static ReturnType convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value, ASCIILiteral functionName = {}, ASCIILiteral argumentName = {})
|
||||
{
|
||||
auto& vm = JSC::getVM(&lexicalGlobalObject);
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
if (!value.isObject()) {
|
||||
throwSequenceTypeError(lexicalGlobalObject, scope);
|
||||
throwSequenceTypeError(lexicalGlobalObject, scope, functionName, argumentName);
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -264,6 +324,34 @@ struct SequenceConverter {
|
||||
RELEASE_AND_RETURN(scope, (convertArray(lexicalGlobalObject, array)));
|
||||
}
|
||||
|
||||
template<typename ExceptionThrower = DefaultExceptionThrower>
|
||||
static ReturnType convert(JSC::JSGlobalObject& lexicalGlobalObject,
|
||||
JSC::JSValue value,
|
||||
ExceptionThrower&& exceptionThrower = ExceptionThrower(),
|
||||
ASCIILiteral functionName = {}, ASCIILiteral argumentName = {})
|
||||
{
|
||||
auto& vm = JSC::getVM(&lexicalGlobalObject);
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
if (!value.isObject()) {
|
||||
throwSequenceTypeError(lexicalGlobalObject, scope, functionName, argumentName);
|
||||
return {};
|
||||
}
|
||||
|
||||
JSC::JSObject* object = JSC::asObject(value);
|
||||
if (Converter<IDLType>::conversionHasSideEffects)
|
||||
RELEASE_AND_RETURN(scope, (GenericConverter::convert(lexicalGlobalObject, object, std::forward<ExceptionThrower>(exceptionThrower))));
|
||||
|
||||
if (!JSC::isJSArray(object))
|
||||
RELEASE_AND_RETURN(scope, (GenericConverter::convert(lexicalGlobalObject, object, std::forward<ExceptionThrower>(exceptionThrower))));
|
||||
|
||||
JSC::JSArray* array = JSC::asArray(object);
|
||||
if (!array->isIteratorProtocolFastAndNonObservable())
|
||||
RELEASE_AND_RETURN(scope, (GenericConverter::convert(lexicalGlobalObject, object, std::forward<ExceptionThrower>(exceptionThrower))));
|
||||
|
||||
RELEASE_AND_RETURN(scope, (convertArray(lexicalGlobalObject, array, std::forward<ExceptionThrower>(exceptionThrower))));
|
||||
}
|
||||
|
||||
static ReturnType convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSObject* object, JSC::JSValue method)
|
||||
{
|
||||
if (Converter<IDLType>::conversionHasSideEffects)
|
||||
@@ -360,15 +448,20 @@ struct SequenceConverter<IDLUnrestrictedDouble> {
|
||||
template<typename T> struct Converter<IDLSequence<T>> : DefaultConverter<IDLSequence<T>> {
|
||||
using ReturnType = typename Detail::SequenceConverter<T>::ReturnType;
|
||||
|
||||
static ReturnType convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value)
|
||||
static ReturnType convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value, ASCIILiteral functionName = {}, ASCIILiteral argumentName = {})
|
||||
{
|
||||
return Detail::SequenceConverter<T>::convert(lexicalGlobalObject, value);
|
||||
return Detail::SequenceConverter<T>::convert(lexicalGlobalObject, value, functionName, argumentName);
|
||||
}
|
||||
|
||||
static ReturnType convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSObject* object, JSC::JSValue method)
|
||||
{
|
||||
return Detail::SequenceConverter<T>::convert(lexicalGlobalObject, object, method);
|
||||
}
|
||||
|
||||
template<typename ExceptionThrower> static ReturnType convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value, ExceptionThrower&& exceptionThrower, ASCIILiteral functionName = {}, ASCIILiteral argumentName = {})
|
||||
{
|
||||
return Detail::SequenceConverter<T>::convert(lexicalGlobalObject, value, std::forward<ExceptionThrower>(exceptionThrower), functionName, argumentName);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> struct JSConverter<IDLSequence<T>> {
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
#include <wtf/GetPtr.h>
|
||||
#include <wtf/PointerPreparations.h>
|
||||
#include <wtf/URL.h>
|
||||
#include "ErrorCode.h"
|
||||
|
||||
namespace WebCore {
|
||||
using namespace JSC;
|
||||
@@ -151,7 +152,16 @@ template<> MessageEvent::Init convertDictionary<MessageEvent::Init>(JSGlobalObje
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
}
|
||||
if (!portsValue.isUndefined()) {
|
||||
result.ports = convert<IDLSequence<IDLInterface<MessagePort>>>(lexicalGlobalObject, portsValue);
|
||||
result.ports = convert<IDLSequence<IDLInterface<MessagePort>>>(
|
||||
lexicalGlobalObject,
|
||||
portsValue,
|
||||
[](JSGlobalObject& lexicalGlobalObject, ThrowScope& throwScope) {
|
||||
Bun::ERR::INVALID_ARG_TYPE(throwScope,
|
||||
&lexicalGlobalObject,
|
||||
"MessageEvent constructor: Expected every item of eventInitDict.ports to be an instance of MessagePort."_s);
|
||||
},
|
||||
"MessageEvent constructor"_s,
|
||||
"eventInitDict.ports"_s);
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
} else
|
||||
result.ports = Converter<IDLSequence<IDLInterface<MessagePort>>>::ReturnType {};
|
||||
@@ -162,11 +172,14 @@ template<> MessageEvent::Init convertDictionary<MessageEvent::Init>(JSGlobalObje
|
||||
sourceValue = object->get(&lexicalGlobalObject, Identifier::fromString(vm, "source"_s));
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
}
|
||||
// if (!sourceValue.isUndefined()) {
|
||||
// result.source = convert<IDLNullable<IDLUnion<IDLInterface<WindowProxy>, IDLInterface<MessagePort>, IDLInterface<ServiceWorker>>>>(lexicalGlobalObject, sourceValue);
|
||||
// RETURN_IF_EXCEPTION(throwScope, {});
|
||||
// } else
|
||||
result.source = std::nullopt;
|
||||
if (!sourceValue.isUndefinedOrNull()) {
|
||||
result.source = convert<IDLNullable<IDLInterface<MessagePort>>>(lexicalGlobalObject, sourceValue, [&sourceValue](JSGlobalObject& lexicalGlobalObject, ThrowScope& throwScope) {
|
||||
Bun::ERR::INVALID_ARG_TYPE(throwScope, &lexicalGlobalObject, "eventInitDict.source"_s, "MessagePort"_s, sourceValue);
|
||||
});
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
} else {
|
||||
result.source = nullptr;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -351,10 +364,10 @@ JSC_DEFINE_CUSTOM_GETTER(jsMessageEvent_lastEventId, (JSGlobalObject * lexicalGl
|
||||
|
||||
static inline JSValue jsMessageEvent_sourceGetter(JSGlobalObject& lexicalGlobalObject, JSMessageEvent& thisObject)
|
||||
{
|
||||
return jsNull();
|
||||
// auto throwScope = DECLARE_THROW_SCOPE(vm);
|
||||
// auto& impl = thisObject.wrapped();
|
||||
// RELEASE_AND_RETURN(throwScope, (toJS<IDLNullable<IDLUnion<IDLInterface<WindowProxy>, IDLInterface<MessagePort>, IDLInterface<ServiceWorker>>>>(lexicalGlobalObject, *thisObject.globalObject(), throwScope, impl.source())));
|
||||
auto& vm = JSC::getVM(&lexicalGlobalObject);
|
||||
auto throwScope = DECLARE_THROW_SCOPE(vm);
|
||||
auto& impl = thisObject.wrapped();
|
||||
RELEASE_AND_RETURN(throwScope, (toJS<IDLNullable<IDLInterface<MessagePort>>>(lexicalGlobalObject, *thisObject.globalObject(), throwScope, impl.source())));
|
||||
}
|
||||
|
||||
JSC_DEFINE_CUSTOM_GETTER(jsMessageEvent_source, (JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, PropertyName attributeName))
|
||||
@@ -412,8 +425,7 @@ static inline JSC::EncodedJSValue jsMessageEventPrototypeFunction_initMessageEve
|
||||
auto lastEventId = argument5.value().isUndefined() ? emptyString() : convert<IDLDOMString>(*lexicalGlobalObject, argument5.value());
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
EnsureStillAliveScope argument6 = callFrame->argument(6);
|
||||
auto source = WebCore::MessageEventSource();
|
||||
// auto source = argument6.value().isUndefined() ? std::nullopt : convert<IDLNullable<IDLUnion<IDLInterface<WindowProxy>, IDLInterface<MessagePort>, IDLInterface<ServiceWorker>>>>(*lexicalGlobalObject, argument6.value());
|
||||
RefPtr<MessagePort> source = argument6.value().isUndefined() ? nullptr : convert<IDLNullable<IDLInterface<MessagePort>>>(*lexicalGlobalObject, argument6.value());
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
EnsureStillAliveScope argument7 = callFrame->argument(7);
|
||||
auto messagePorts = argument7.value().isUndefined() ? Converter<IDLSequence<IDLInterface<MessagePort>>>::ReturnType {} : convert<IDLSequence<IDLInterface<MessagePort>>>(*lexicalGlobalObject, argument7.value());
|
||||
|
||||
@@ -54,7 +54,7 @@ inline MessageEvent::MessageEvent(const AtomString& type, Init&& initializer, Is
|
||||
{
|
||||
}
|
||||
|
||||
inline MessageEvent::MessageEvent(const AtomString& type, DataType&& data, const String& origin, const String& lastEventId, std::optional<MessageEventSource>&& source, Vector<RefPtr<MessagePort>>&& ports)
|
||||
inline MessageEvent::MessageEvent(const AtomString& type, DataType&& data, const String& origin, const String& lastEventId, RefPtr<MessagePort>&& source, Vector<RefPtr<MessagePort>>&& ports)
|
||||
: Event(type, CanBubble::No, IsCancelable::No)
|
||||
, m_data(WTFMove(data))
|
||||
, m_origin(origin)
|
||||
@@ -64,12 +64,12 @@ inline MessageEvent::MessageEvent(const AtomString& type, DataType&& data, const
|
||||
{
|
||||
}
|
||||
|
||||
Ref<MessageEvent> MessageEvent::create(const AtomString& type, DataType&& data, const String& origin, const String& lastEventId, std::optional<MessageEventSource>&& source, Vector<RefPtr<MessagePort>>&& ports)
|
||||
Ref<MessageEvent> MessageEvent::create(const AtomString& type, DataType&& data, const String& origin, const String& lastEventId, RefPtr<MessagePort>&& source, Vector<RefPtr<MessagePort>>&& ports)
|
||||
{
|
||||
return adoptRef(*new MessageEvent(type, WTFMove(data), origin, lastEventId, WTFMove(source), WTFMove(ports)));
|
||||
}
|
||||
|
||||
Ref<MessageEvent> MessageEvent::create(DataType&& data, const String& origin, const String& lastEventId, std::optional<MessageEventSource>&& source, Vector<RefPtr<MessagePort>>&& ports)
|
||||
Ref<MessageEvent> MessageEvent::create(DataType&& data, const String& origin, const String& lastEventId, RefPtr<MessagePort>&& source, Vector<RefPtr<MessagePort>>&& ports)
|
||||
{
|
||||
return create(eventNames().messageEvent, WTFMove(data), origin, lastEventId, WTFMove(source), WTFMove(ports));
|
||||
}
|
||||
@@ -86,12 +86,12 @@ Ref<MessageEvent> MessageEvent::create(const AtomString& type, Init&& initialize
|
||||
|
||||
MessageEvent::~MessageEvent() = default;
|
||||
|
||||
auto MessageEvent::create(JSC::JSGlobalObject& globalObject, Ref<SerializedScriptValue>&& data, std::optional<MessageEventSource>&& source, Vector<RefPtr<MessagePort>>&& ports) -> MessageEventWithStrongData
|
||||
auto MessageEvent::create(JSC::JSGlobalObject& globalObject, Ref<SerializedScriptValue>&& data, RefPtr<MessagePort>&& source, Vector<RefPtr<MessagePort>>&& ports) -> MessageEventWithStrongData
|
||||
{
|
||||
return create(globalObject, WTFMove(data), {}, {}, WTFMove(source), WTFMove(ports));
|
||||
}
|
||||
|
||||
auto MessageEvent::create(JSC::JSGlobalObject& globalObject, Ref<SerializedScriptValue>&& data, const String& origin, const String& lastEventId, std::optional<MessageEventSource>&& source, Vector<RefPtr<MessagePort>>&& ports) -> MessageEventWithStrongData
|
||||
auto MessageEvent::create(JSC::JSGlobalObject& globalObject, Ref<SerializedScriptValue>&& data, const String& origin, const String& lastEventId, RefPtr<MessagePort>&& source, Vector<RefPtr<MessagePort>>&& ports) -> MessageEventWithStrongData
|
||||
{
|
||||
auto& vm = globalObject.vm();
|
||||
// Locker<JSC::JSLock> locker(vm.apiLock());
|
||||
@@ -115,7 +115,7 @@ auto MessageEvent::create(JSC::JSGlobalObject& globalObject, Ref<SerializedScrip
|
||||
return MessageEventWithStrongData { event, WTFMove(strongWrapper) };
|
||||
}
|
||||
|
||||
void MessageEvent::initMessageEvent(const AtomString& type, bool canBubble, bool cancelable, JSValue data, const String& origin, const String& lastEventId, std::optional<MessageEventSource>&& source, Vector<RefPtr<MessagePort>>&& ports)
|
||||
void MessageEvent::initMessageEvent(const AtomString& type, bool canBubble, bool cancelable, JSValue data, const String& origin, const String& lastEventId, RefPtr<MessagePort>&& source, Vector<RefPtr<MessagePort>>&& ports)
|
||||
{
|
||||
if (isBeingDispatched())
|
||||
return;
|
||||
|
||||
@@ -39,9 +39,6 @@
|
||||
|
||||
namespace WebCore {
|
||||
|
||||
class MessageEventSource {
|
||||
};
|
||||
|
||||
class MessageEvent final : public Event {
|
||||
WTF_MAKE_TZONE_ALLOCATED(MessageEvent);
|
||||
|
||||
@@ -50,8 +47,8 @@ public:
|
||||
};
|
||||
// using DataType = std::variant<JSValueTag, Ref<SerializedScriptValue>, String, Ref<Blob>, Ref<ArrayBuffer>>;
|
||||
using DataType = std::variant<JSValueTag, Ref<SerializedScriptValue>, String, Ref<ArrayBuffer>>;
|
||||
static Ref<MessageEvent> create(const AtomString& type, DataType&&, const String& origin = {}, const String& lastEventId = {}, std::optional<MessageEventSource>&& = std::nullopt, Vector<RefPtr<MessagePort>>&& = {});
|
||||
static Ref<MessageEvent> create(DataType&&, const String& origin = {}, const String& lastEventId = {}, std::optional<MessageEventSource>&& = std::nullopt, Vector<RefPtr<MessagePort>>&& = {});
|
||||
static Ref<MessageEvent> create(const AtomString& type, DataType&&, const String& origin = {}, const String& lastEventId = {}, RefPtr<MessagePort>&& = nullptr, Vector<RefPtr<MessagePort>>&& = {});
|
||||
static Ref<MessageEvent> create(DataType&&, const String& origin = {}, const String& lastEventId = {}, RefPtr<MessagePort>&& = nullptr, Vector<RefPtr<MessagePort>>&& = {});
|
||||
|
||||
static Ref<MessageEvent> createForBindings();
|
||||
|
||||
@@ -59,7 +56,7 @@ public:
|
||||
JSC::JSValue data;
|
||||
String origin;
|
||||
String lastEventId;
|
||||
std::optional<MessageEventSource> source;
|
||||
RefPtr<MessagePort> source;
|
||||
Vector<RefPtr<MessagePort>> ports;
|
||||
};
|
||||
static Ref<MessageEvent> create(const AtomString& type, Init&&, IsTrusted = IsTrusted::No);
|
||||
@@ -69,17 +66,17 @@ public:
|
||||
JSC::Strong<JSC::JSObject> strongWrapper; // Keep the wrapper alive until the event is fired, since it is what keeps `data` alive.
|
||||
};
|
||||
|
||||
static MessageEventWithStrongData create(JSC::JSGlobalObject&, Ref<SerializedScriptValue>&&, const String& origin = {}, const String& lastEventId = {}, std::optional<MessageEventSource>&& = std::nullopt, Vector<RefPtr<MessagePort>>&& = {});
|
||||
static MessageEventWithStrongData create(JSC::JSGlobalObject&, Ref<SerializedScriptValue>&&, const String& origin = {}, const String& lastEventId = {}, RefPtr<MessagePort>&& = nullptr, Vector<RefPtr<MessagePort>>&& = {});
|
||||
|
||||
static MessageEventWithStrongData create(JSC::JSGlobalObject&, Ref<SerializedScriptValue>&&, std::optional<MessageEventSource>&& = std::nullopt, Vector<RefPtr<MessagePort>>&& = {});
|
||||
static MessageEventWithStrongData create(JSC::JSGlobalObject&, Ref<SerializedScriptValue>&&, RefPtr<MessagePort>&& = nullptr, Vector<RefPtr<MessagePort>>&& = {});
|
||||
|
||||
virtual ~MessageEvent();
|
||||
|
||||
void initMessageEvent(const AtomString& type, bool canBubble, bool cancelable, JSC::JSValue data, const String& origin, const String& lastEventId, std::optional<MessageEventSource>&&, Vector<RefPtr<MessagePort>>&&);
|
||||
void initMessageEvent(const AtomString& type, bool canBubble, bool cancelable, JSC::JSValue data, const String& origin, const String& lastEventId, RefPtr<MessagePort>&&, Vector<RefPtr<MessagePort>>&&);
|
||||
|
||||
const String& origin() const { return m_origin; }
|
||||
const String& lastEventId() const { return m_lastEventId; }
|
||||
const std::optional<MessageEventSource>& source() const { return m_source; }
|
||||
const RefPtr<MessagePort>& source() const { return m_source; }
|
||||
const Vector<RefPtr<MessagePort>>& ports() const { return m_ports; }
|
||||
|
||||
const DataType& data() const { return m_data; }
|
||||
@@ -93,14 +90,14 @@ public:
|
||||
private:
|
||||
MessageEvent();
|
||||
MessageEvent(const AtomString& type, Init&&, IsTrusted);
|
||||
MessageEvent(const AtomString& type, DataType&&, const String& origin, const String& lastEventId = {}, std::optional<MessageEventSource>&& = std::nullopt, Vector<RefPtr<MessagePort>>&& = {});
|
||||
MessageEvent(const AtomString& type, DataType&&, const String& origin, const String& lastEventId = {}, RefPtr<MessagePort>&& = nullptr, Vector<RefPtr<MessagePort>>&& = {});
|
||||
|
||||
EventInterface eventInterface() const final;
|
||||
|
||||
DataType m_data;
|
||||
String m_origin;
|
||||
String m_lastEventId;
|
||||
std::optional<MessageEventSource> m_source;
|
||||
RefPtr<MessagePort> m_source;
|
||||
Vector<RefPtr<MessagePort>> m_ports;
|
||||
|
||||
JSValueInWrappedObject m_jsData;
|
||||
|
||||
@@ -252,7 +252,7 @@ ExceptionOr<void> Worker::postMessage(JSC::JSGlobalObject& state, JSC::JSValue m
|
||||
Zig::GlobalObject* globalObject = jsCast<Zig::GlobalObject*>(context.jsGlobalObject());
|
||||
|
||||
auto ports = MessagePort::entanglePorts(context, WTFMove(message.transferredPorts));
|
||||
auto event = MessageEvent::create(*globalObject, message.message.releaseNonNull(), std::nullopt, WTFMove(ports));
|
||||
auto event = MessageEvent::create(*globalObject, message.message.releaseNonNull(), nullptr, WTFMove(ports));
|
||||
|
||||
globalObject->globalEventScope->dispatchEvent(event.event);
|
||||
});
|
||||
@@ -649,7 +649,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionPostMessage,
|
||||
Zig::GlobalObject* globalObject = jsCast<Zig::GlobalObject*>(context.jsGlobalObject());
|
||||
|
||||
auto ports = MessagePort::entanglePorts(context, WTFMove(message.transferredPorts));
|
||||
auto event = MessageEvent::create(*globalObject, message.message.releaseNonNull(), std::nullopt, WTFMove(ports));
|
||||
auto event = MessageEvent::create(*globalObject, message.message.releaseNonNull(), nullptr, WTFMove(ports));
|
||||
|
||||
protectedThis->dispatchEvent(event.event);
|
||||
});
|
||||
|
||||
93
test/js/node/test/parallel/test-worker-message-event.js
Normal file
93
test/js/node/test/parallel/test-worker-message-event.js
Normal file
@@ -0,0 +1,93 @@
|
||||
'use strict';
|
||||
require('../common');
|
||||
const assert = require('assert');
|
||||
|
||||
const dummyPort = new MessageChannel().port1;
|
||||
{
|
||||
for (const [args, expected] of [
|
||||
[
|
||||
['message'],
|
||||
{
|
||||
type: 'message', data: null, origin: '',
|
||||
lastEventId: '', source: null, ports: []
|
||||
},
|
||||
],
|
||||
[
|
||||
['message', { data: undefined, origin: 'foo' }],
|
||||
{
|
||||
type: 'message', data: null, origin: 'foo',
|
||||
lastEventId: '', source: null, ports: []
|
||||
},
|
||||
],
|
||||
[
|
||||
['message', { data: 2, origin: 1, lastEventId: 0 }],
|
||||
{
|
||||
type: 'message', data: 2, origin: '1',
|
||||
lastEventId: '0', source: null, ports: []
|
||||
},
|
||||
],
|
||||
[
|
||||
['message', { lastEventId: 'foo' }],
|
||||
{
|
||||
type: 'message', data: null, origin: '',
|
||||
lastEventId: 'foo', source: null, ports: []
|
||||
},
|
||||
],
|
||||
[
|
||||
['messageerror', { lastEventId: 'foo', source: dummyPort }],
|
||||
{
|
||||
type: 'messageerror', data: null, origin: '',
|
||||
lastEventId: 'foo', source: dummyPort, ports: []
|
||||
},
|
||||
],
|
||||
[
|
||||
['message', { ports: [dummyPort], source: null }],
|
||||
{
|
||||
type: 'message', data: null, origin: '',
|
||||
lastEventId: '', source: null, ports: [dummyPort]
|
||||
},
|
||||
],
|
||||
]) {
|
||||
const ev = new MessageEvent(...args);
|
||||
const { type, data, origin, lastEventId, source, ports } = ev;
|
||||
assert.deepStrictEqual(expected, {
|
||||
type, data, origin, lastEventId, source, ports
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
assert.throws(() => {
|
||||
new MessageEvent('message', { source: 1 });
|
||||
}, e => (
|
||||
e.name == 'TypeError' &&
|
||||
e.message.includes('eventInitDict.source') && e.message.match(/(an instance of|of type) MessagePort/) && e.message.includes('1')
|
||||
));
|
||||
assert.throws(() => {
|
||||
new MessageEvent('message', { source: {} });
|
||||
}, e => (
|
||||
e.name == 'TypeError' &&
|
||||
e.message.includes('eventInitDict.source') && e.message.match(/(an instance of|of type) MessagePort/) && (e.message.includes('{}') || e.message.includes('an instance of Object'))
|
||||
));
|
||||
assert.throws(() => {
|
||||
new MessageEvent('message', { ports: 0 });
|
||||
}, {
|
||||
message: /MessageEvent constructor: eventInitDict\.ports( \(0\))? is not iterable\./,
|
||||
});
|
||||
assert.throws(() => {
|
||||
new MessageEvent('message', { ports: [ null ] });
|
||||
}, {
|
||||
name: 'TypeError',
|
||||
message: /MessageEvent constructor: Expected (every item of )?eventInitDict\.ports(\[0\])? (\("null"\) )?to be an instance of MessagePort\./,
|
||||
});
|
||||
assert.throws(() => {
|
||||
new MessageEvent('message', { ports: [ {} ] });
|
||||
}, {
|
||||
name: 'TypeError',
|
||||
message: /MessageEvent constructor: Expected (every item of )?eventInitDict\.ports(\[0\])? (\("\{\}"\) )?to be an instance of MessagePort\./,
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
assert(new MessageEvent('message') instanceof Event);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
|
||||
const { parentPort, MessageChannel, Worker } = require('worker_threads');
|
||||
|
||||
// Do not use isMainThread so that this test itself can be run inside a Worker.
|
||||
if (!process.env.HAS_STARTED_WORKER) {
|
||||
process.env.HAS_STARTED_WORKER = 1;
|
||||
const w = new Worker(__filename);
|
||||
w.once('message', common.mustCall(() => {
|
||||
w.once('message', common.mustNotCall());
|
||||
setTimeout(() => w.terminate(), 100);
|
||||
}));
|
||||
} else {
|
||||
const { port1 } = new MessageChannel();
|
||||
|
||||
parentPort.postMessage('ready');
|
||||
|
||||
// Make sure we don’t end up running JS after the infinite loop is broken.
|
||||
port1.postMessage({}, {
|
||||
// eslint-disable-next-line require-yield
|
||||
transfer: (function*() { while (true); })()
|
||||
});
|
||||
|
||||
parentPort.postMessage('UNREACHABLE');
|
||||
process.kill(process.pid, 'SIGINT');
|
||||
}
|
||||
34
test/js/node/test/parallel/test-worker-uncaught-exception.js
Normal file
34
test/js/node/test/parallel/test-worker-uncaught-exception.js
Normal file
@@ -0,0 +1,34 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const { Worker } = require('worker_threads');
|
||||
|
||||
// Do not use isMainThread so that this test itself can be run inside a Worker.
|
||||
if (!process.env.HAS_STARTED_WORKER) {
|
||||
process.env.HAS_STARTED_WORKER = 1;
|
||||
const w = new Worker(__filename);
|
||||
w.on('message', common.mustNotCall());
|
||||
w.on('error', common.mustCall((err) => {
|
||||
console.log(err.message);
|
||||
assert.match(String(err), /^Error: foo$/);
|
||||
}));
|
||||
w.on('exit', common.mustCall((code) => {
|
||||
// uncaughtException is code 1
|
||||
assert.strictEqual(code, 1);
|
||||
}));
|
||||
} else {
|
||||
// Cannot use common.mustCall as it cannot catch this
|
||||
let called = false;
|
||||
process.on('exit', (code) => {
|
||||
if (!called) {
|
||||
called = true;
|
||||
} else {
|
||||
assert.fail('Exit callback called twice in worker');
|
||||
}
|
||||
});
|
||||
|
||||
setTimeout(() => assert.fail('Timeout executed after uncaughtException'),
|
||||
2000);
|
||||
|
||||
throw new Error('foo');
|
||||
}
|
||||
104
test/js/web/workers/message-event.test.ts
Normal file
104
test/js/web/workers/message-event.test.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
|
||||
describe("MessageEvent constructor", () => {
|
||||
test("returns an Event instance", () => {
|
||||
expect(new MessageEvent("message")).toBeInstanceOf(Event);
|
||||
});
|
||||
|
||||
test("has the right defaults", () => {
|
||||
const expected = {
|
||||
type: "custom type",
|
||||
data: null,
|
||||
origin: "",
|
||||
lastEventId: "",
|
||||
source: null,
|
||||
ports: [],
|
||||
};
|
||||
expect(new MessageEvent("custom type")).toMatchObject(expected);
|
||||
expect(new MessageEvent("custom type", undefined)).toMatchObject(expected);
|
||||
expect(new MessageEvent("custom type", {})).toMatchObject(expected);
|
||||
// @ts-expect-error
|
||||
expect(new MessageEvent("custom type", null)).toMatchObject(expected);
|
||||
});
|
||||
|
||||
test("includes all options in the returned object", () => {
|
||||
const { port1 } = new MessageChannel();
|
||||
expect(
|
||||
new MessageEvent("custom type", {
|
||||
data: 123,
|
||||
origin: "origin",
|
||||
lastEventId: "id",
|
||||
source: port1,
|
||||
ports: [port1],
|
||||
}),
|
||||
).toMatchObject({
|
||||
type: "custom type",
|
||||
data: 123,
|
||||
origin: "origin",
|
||||
lastEventId: "id",
|
||||
source: port1,
|
||||
ports: [port1],
|
||||
});
|
||||
});
|
||||
|
||||
test("coerces the type to a string", () => {
|
||||
// @ts-expect-error
|
||||
expect(new MessageEvent(5)).toMatchObject({ type: "5" });
|
||||
// @ts-expect-error
|
||||
expect(new MessageEvent(undefined)).toMatchObject({ type: "undefined" });
|
||||
});
|
||||
|
||||
test("throws if you pass no arguments", () => {
|
||||
// @ts-expect-error
|
||||
expect(() => new MessageEvent()).toThrow({
|
||||
name: "TypeError",
|
||||
message: "Not enough arguments",
|
||||
});
|
||||
});
|
||||
|
||||
test("throws if options is not an object", () => {
|
||||
// @ts-expect-error
|
||||
expect(() => new MessageEvent("message", 5)).toThrow(TypeError);
|
||||
});
|
||||
|
||||
test("coerces options.origin to a string", () => {
|
||||
// @ts-expect-error
|
||||
expect(new MessageEvent("message", { origin: 123 })).toMatchObject({ origin: "123" });
|
||||
});
|
||||
|
||||
test("coerces options.lastEventId to a string", () => {
|
||||
// @ts-expect-error
|
||||
expect(new MessageEvent("message", { lastEventId: 123 })).toMatchObject({ lastEventId: "123" });
|
||||
});
|
||||
|
||||
test("throws if options.source is the wrong type", () => {
|
||||
// @ts-expect-error
|
||||
expect(() => new MessageEvent("message", { source: 1 })).toThrow({
|
||||
name: "TypeError",
|
||||
message: 'The "eventInitDict.source" property must be of type MessagePort. Received type number (1)',
|
||||
});
|
||||
// @ts-expect-error
|
||||
expect(() => new MessageEvent("message", { source: {} })).toThrow({
|
||||
name: "TypeError",
|
||||
message: 'The "eventInitDict.source" property must be of type MessagePort. Received an instance of Object',
|
||||
});
|
||||
});
|
||||
|
||||
test("throws if options.ports is the wrong type", () => {
|
||||
// @ts-expect-error
|
||||
expect(() => new MessageEvent("message", { ports: 1 })).toThrow({
|
||||
name: "TypeError",
|
||||
message: "MessageEvent constructor: eventInitDict.ports is not iterable.",
|
||||
});
|
||||
// @ts-expect-error
|
||||
expect(() => new MessageEvent("message", { ports: [1] })).toThrow({
|
||||
name: "TypeError",
|
||||
message: "MessageEvent constructor: Expected every item of eventInitDict.ports to be an instance of MessagePort.",
|
||||
});
|
||||
// @ts-expect-error
|
||||
expect(() => new MessageEvent("message", { ports: [{}] })).toThrow({
|
||||
name: "TypeError",
|
||||
message: "MessageEvent constructor: Expected every item of eventInitDict.ports to be an instance of MessagePort.",
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user