LibWeb: Move JS::Promise <-> WebIDL conversion into IDL

This change also removes as much direct use of JS::Promise in LibWeb
as possible. When specs refer to `Promise<T>` they should be assumed
to be referring to the WebIDL Promise type, not the JS::Promise type.

The one exception is the HostPromiseRejectionTracker hook on the JS
VM. This facility and its associated sets and events are intended to
expose the exact opaque object handles that were rejected to author
code. This is not possible with the WebIDL Promise type, so we have
to use JS::Promise or JS::Object to hold onto the promises.

It also exposes which specs need some updates in the area of
promises. WebDriver stands out in this regard. WebAudio could use
some more cross-references to WebIDL as well to clarify things.
This commit is contained in:
Andrew Kaster 2024-10-25 12:38:19 -06:00 committed by Andrew Kaster
commit 2c3531ab78
Notes: github-actions[bot] 2024-10-25 20:05:22 +00:00
61 changed files with 323 additions and 306 deletions

View file

@ -665,16 +665,17 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
}
}
} else if (parameter.type->name() == "Promise") {
// NOTE: It's not clear to me where the implicit wrapping of non-Promise values in a resolved
// Promise is defined in the spec; https://webidl.spec.whatwg.org/#idl-promise doesn't say
// anything of this sort. Both Gecko and Blink do it, however, so I'm sure it's correct.
// https://webidl.spec.whatwg.org/#js-promise
scoped_generator.append(R"~~~(
if (!@js_name@@js_suffix@.is_object() || !is<JS::Promise>(@js_name@@js_suffix@.as_object())) {
auto new_promise = JS::Promise::create(realm);
new_promise->fulfill(@js_name@@js_suffix@);
@js_name@@js_suffix@ = new_promise;
if (!@js_name@@js_suffix@.is_cell() || !is<JS::PromiseCapability>(@js_name@@js_suffix@.as_cell())) {
// 1. Let promiseCapability be ? NewPromiseCapability(%Promise%).
auto promise_capability = TRY(JS::new_promise_capability(vm, realm.intrinsics().promise_constructor()));
// 2. Perform ? Call(promiseCapability.[[Resolve]], undefined, « V »).
TRY(JS::call(vm, *promise_capability->resolve(), JS::js_undefined(), @js_name@@js_suffix@));
// 3. Return promiseCapability.
@js_name@@js_suffix@ = promise_capability;
}
auto @cpp_name@ = JS::make_handle(&static_cast<JS::Promise&>(@js_name@@js_suffix@.as_object()));
auto @cpp_name@ = JS::make_handle(static_cast<JS::PromiseCapability&>(@js_name@@js_suffix@.as_cell()));
)~~~");
} else if (parameter.type->name() == "object") {
if (parameter.type->is_nullable()) {
@ -1794,9 +1795,13 @@ static void generate_wrap_statement(SourceGenerator& generator, ByteString const
}
} else if (type.is_integer()) {
generate_from_integral(scoped_generator, type);
} else if (type.name() == "Location" || type.name() == "Promise" || type.name() == "Uint8Array" || type.name() == "Uint8ClampedArray" || type.name() == "any") {
} else if (type.name() == "Location" || type.name() == "Uint8Array" || type.name() == "Uint8ClampedArray" || type.name() == "any") {
scoped_generator.append(R"~~~(
@result_expression@ @value@;
)~~~");
} else if (type.name() == "Promise") {
scoped_generator.append(R"~~~(
@result_expression@ JS::NonnullGCPtr { verify_cast<JS::Promise>(*@value@->promise()) };
)~~~");
} else if (type.name() == "ArrayBufferView" || type.name() == "BufferSource") {
scoped_generator.append(R"~~~(
@ -4243,6 +4248,7 @@ void generate_namespace_implementation(IDL::Interface const& interface, StringBu
#include <LibJS/Runtime/DataView.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/PrimitiveString.h>
#include <LibJS/Runtime/PromiseConstructor.h>
#include <LibJS/Runtime/TypedArray.h>
#include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueInlines.h>
@ -4254,6 +4260,7 @@ void generate_namespace_implementation(IDL::Interface const& interface, StringBu
#include <LibWeb/WebIDL/AbstractOperations.h>
#include <LibWeb/WebIDL/Buffers.h>
#include <LibWeb/WebIDL/OverloadResolution.h>
#include <LibWeb/WebIDL/Promise.h>
#include <LibWeb/WebIDL/Tracing.h>
#include <LibWeb/WebIDL/Types.h>
@ -4663,6 +4670,7 @@ void generate_prototype_implementation(IDL::Interface const& interface, StringBu
#include <LibJS/Runtime/FunctionObject.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Iterator.h>
#include <LibJS/Runtime/PromiseConstructor.h>
#include <LibJS/Runtime/TypedArray.h>
#include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueInlines.h>
@ -4682,8 +4690,9 @@ void generate_prototype_implementation(IDL::Interface const& interface, StringBu
#include <LibWeb/Infra/Strings.h>
#include <LibWeb/WebIDL/AbstractOperations.h>
#include <LibWeb/WebIDL/Buffers.h>
#include <LibWeb/WebIDL/Tracing.h>
#include <LibWeb/WebIDL/OverloadResolution.h>
#include <LibWeb/WebIDL/Promise.h>
#include <LibWeb/WebIDL/Tracing.h>
#include <LibWeb/WebIDL/Types.h>
#if __has_include(<LibWeb/Bindings/@prototype_base_class@.h>)

View file

@ -60,10 +60,10 @@ public:
bool pending() const { return m_pending_play_task == TaskState::Scheduled || m_pending_pause_task == TaskState::Scheduled; }
// https://www.w3.org/TR/web-animations-1/#dom-animation-ready
JS::NonnullGCPtr<JS::Object> ready() const { return *current_ready_promise()->promise(); }
JS::NonnullGCPtr<WebIDL::Promise> ready() const { return current_ready_promise(); }
// https://www.w3.org/TR/web-animations-1/#dom-animation-finished
JS::NonnullGCPtr<JS::Object> finished() const { return *current_finished_promise()->promise(); }
JS::NonnullGCPtr<WebIDL::Promise> finished() const { return current_finished_promise(); }
bool is_finished() const { return m_is_finished; }
JS::GCPtr<WebIDL::CallbackType> onfinish();

View file

@ -14,6 +14,7 @@
#include <LibWeb/CSS/StyleComputer.h>
#include <LibWeb/CSS/StyleSheetList.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
#include <LibWeb/HTML/Window.h>
#include <LibWeb/Platform/EventLoopPlugin.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
@ -186,19 +187,21 @@ WebIDL::ExceptionOr<void> CSSStyleSheet::delete_rule(unsigned index)
}
// https://drafts.csswg.org/cssom/#dom-cssstylesheet-replace
JS::NonnullGCPtr<JS::Promise> CSSStyleSheet::replace(String text)
JS::NonnullGCPtr<WebIDL::Promise> CSSStyleSheet::replace(String text)
{
auto& realm = this->realm();
// 1. Let promise be a promise
auto promise = JS::Promise::create(realm());
auto promise = WebIDL::create_promise(realm);
// 2. If the constructed flag is not set, or the disallow modification flag is set, reject promise with a NotAllowedError DOMException and return promise.
if (!constructed()) {
promise->reject(WebIDL::NotAllowedError::create(realm(), "Can't call replace() on non-constructed stylesheets"_string));
WebIDL::reject_promise(realm, promise, WebIDL::NotAllowedError::create(realm, "Can't call replace() on non-constructed stylesheets"_string));
return promise;
}
if (disallow_modification()) {
promise->reject(WebIDL::NotAllowedError::create(realm(), "Can't call replace() on non-modifiable stylesheets"_string));
WebIDL::reject_promise(realm, promise, WebIDL::NotAllowedError::create(realm, "Can't call replace() on non-modifiable stylesheets"_string));
return promise;
}
@ -206,14 +209,16 @@ JS::NonnullGCPtr<JS::Promise> CSSStyleSheet::replace(String text)
set_disallow_modification(true);
// 4. In parallel, do these steps:
Platform::EventLoopPlugin::the().deferred_invoke([this, text = move(text), promise] {
Platform::EventLoopPlugin::the().deferred_invoke([&realm, this, text = move(text), promise = JS::Handle(promise)] {
HTML::TemporaryExecutionContext execution_context { HTML::relevant_settings_object(*this), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes };
// 1. Let rules be the result of running parse a stylesheets contents from text.
auto context = m_style_sheet_list ? CSS::Parser::ParsingContext { m_style_sheet_list->document() } : CSS::Parser::ParsingContext { realm() };
auto context = m_style_sheet_list ? CSS::Parser::ParsingContext { m_style_sheet_list->document() } : CSS::Parser::ParsingContext { realm };
auto* parsed_stylesheet = parse_css_stylesheet(context, text);
auto& rules = parsed_stylesheet->rules();
// 2. If rules contains one or more @import rules, remove those rules from rules.
JS::MarkedVector<JS::NonnullGCPtr<CSSRule>> rules_without_import(realm().heap());
JS::MarkedVector<JS::NonnullGCPtr<CSSRule>> rules_without_import(realm.heap());
for (auto rule : rules) {
if (rule->type() != CSSRule::Type::Import)
rules_without_import.append(rule);
@ -226,7 +231,7 @@ JS::NonnullGCPtr<JS::Promise> CSSStyleSheet::replace(String text)
set_disallow_modification(false);
// 5. Resolve promise with sheet.
promise->fulfill(this);
WebIDL::resolve_promise(realm, *promise, this);
});
return promise;

View file

@ -53,7 +53,7 @@ public:
WebIDL::ExceptionOr<void> remove_rule(Optional<WebIDL::UnsignedLong> index);
WebIDL::ExceptionOr<void> delete_rule(unsigned index);
JS::NonnullGCPtr<JS::Promise> replace(String text);
JS::NonnullGCPtr<WebIDL::Promise> replace(String text);
WebIDL::ExceptionOr<void> replace_sync(StringView text);
void for_each_effective_rule(TraversalOrder, Function<void(CSSRule const&)> const& callback) const;

View file

@ -205,9 +205,9 @@ void FontFace::visit_edges(JS::Cell::Visitor& visitor)
visitor.visit(m_font_status_promise);
}
JS::NonnullGCPtr<JS::Promise> FontFace::loaded() const
JS::NonnullGCPtr<WebIDL::Promise> FontFace::loaded() const
{
return verify_cast<JS::Promise>(*m_font_status_promise->promise());
return m_font_status_promise;
}
// https://drafts.csswg.org/css-font-loading/#dom-fontface-family
@ -320,7 +320,7 @@ WebIDL::ExceptionOr<void> FontFace::set_line_gap_override(String const&)
}
// https://drafts.csswg.org/css-font-loading/#dom-fontface-load
JS::NonnullGCPtr<JS::Promise> FontFace::load()
JS::NonnullGCPtr<WebIDL::Promise> FontFace::load()
{
// 1. Let font face be the FontFace object on which this method was called.
auto& font_face = *this;

View file

@ -74,8 +74,8 @@ public:
Bindings::FontFaceLoadStatus status() const { return m_status; }
JS::NonnullGCPtr<JS::Promise> load();
JS::NonnullGCPtr<JS::Promise> loaded() const;
JS::NonnullGCPtr<WebIDL::Promise> load();
JS::NonnullGCPtr<WebIDL::Promise> loaded() const;
void load_font_source();

View file

@ -227,7 +227,7 @@ static WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Set>> find_matching_font_faces(J
}
// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-load
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> FontFaceSet::load(String const& font, String const& text)
JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> FontFaceSet::load(String const& font, String const& text)
{
auto& realm = this->realm();
@ -278,18 +278,18 @@ JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> FontFaceSet::load(String co
});
// 2. Return promise. Complete the rest of these steps asynchronously.
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise()) };
return promise;
}
// https://drafts.csswg.org/css-font-loading/#font-face-set-ready
JS::NonnullGCPtr<JS::Promise> FontFaceSet::ready() const
JS::NonnullGCPtr<WebIDL::Promise> FontFaceSet::ready() const
{
return verify_cast<JS::Promise>(*m_ready_promise->promise());
return m_ready_promise;
}
void FontFaceSet::resolve_ready_promise()
{
WebIDL::resolve_promise(realm(), *m_ready_promise);
WebIDL::resolve_promise(realm(), m_ready_promise);
}
}

View file

@ -38,9 +38,9 @@ public:
void set_onloadingerror(WebIDL::CallbackType*);
WebIDL::CallbackType* onloadingerror();
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> load(String const& font, String const& text);
JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> load(String const& font, String const& text);
JS::NonnullGCPtr<JS::Promise> ready() const;
JS::NonnullGCPtr<WebIDL::Promise> ready() const;
Bindings::FontFaceSetLoadStatus status() const { return m_status; }
void resolve_ready_promise();
@ -52,7 +52,7 @@ private:
virtual void visit_edges(Cell::Visitor&) override;
JS::NonnullGCPtr<JS::Set> m_set_entries;
JS::GCPtr<WebIDL::Promise> m_ready_promise; // [[ReadyPromise]]
JS::NonnullGCPtr<WebIDL::Promise> m_ready_promise; // [[ReadyPromise]]
Vector<JS::NonnullGCPtr<FontFace>> m_loading_fonts {}; // [[LoadingFonts]]
Vector<JS::NonnullGCPtr<FontFace>> m_loaded_fonts {}; // [[LoadedFonts]]

View file

@ -30,7 +30,7 @@ JS::NonnullGCPtr<ScreenOrientation> ScreenOrientation::create(JS::Realm& realm)
}
// https://w3c.github.io/screen-orientation/#lock-method
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> ScreenOrientation::lock(Bindings::OrientationLockType)
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> ScreenOrientation::lock(Bindings::OrientationLockType)
{
return WebIDL::NotSupportedError::create(realm(), "FIXME: ScreenOrientation::lock() is not implemented"_string);
}

View file

@ -20,7 +20,7 @@ class ScreenOrientation final : public DOM::EventTarget {
public:
[[nodiscard]] static JS::NonnullGCPtr<ScreenOrientation> create(JS::Realm&);
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> lock(Bindings::OrientationLockType);
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> lock(Bindings::OrientationLockType);
void unlock();
Bindings::OrientationType type() const;
WebIDL::UnsignedShort angle() const;

View file

@ -142,7 +142,7 @@ static bool check_clipboard_write_permission(JS::Realm& realm)
}
// https://w3c.github.io/clipboard-apis/#dom-clipboard-writetext
JS::NonnullGCPtr<JS::Promise> Clipboard::write_text(String data)
JS::NonnullGCPtr<WebIDL::Promise> Clipboard::write_text(String data)
{
// 1. Let realm be this's relevant realm.
auto& realm = HTML::relevant_realm(*this);
@ -194,7 +194,7 @@ JS::NonnullGCPtr<JS::Promise> Clipboard::write_text(String data)
});
// 4. Return p.
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise()) };
return promise;
}
}

View file

@ -23,7 +23,7 @@ public:
static WebIDL::ExceptionOr<JS::NonnullGCPtr<Clipboard>> construct_impl(JS::Realm&);
virtual ~Clipboard() override;
JS::NonnullGCPtr<JS::Promise> write_text(String);
JS::NonnullGCPtr<WebIDL::Promise> write_text(String);
private:
Clipboard(JS::Realm&);

View file

@ -121,7 +121,7 @@ WebIDL::ExceptionOr<NormalizedAlgorithmAndParameter> normalize_an_algorithm(JS::
}
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-encrypt
JS::NonnullGCPtr<JS::Promise> SubtleCrypto::encrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter)
JS::NonnullGCPtr<WebIDL::Promise> SubtleCrypto::encrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter)
{
auto& realm = this->realm();
auto& vm = this->vm();
@ -174,11 +174,11 @@ JS::NonnullGCPtr<JS::Promise> SubtleCrypto::encrypt(AlgorithmIdentifier const& a
WebIDL::resolve_promise(realm, promise, cipher_text.release_value());
});
return verify_cast<JS::Promise>(*promise->promise());
return promise;
}
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-decrypt
JS::NonnullGCPtr<JS::Promise> SubtleCrypto::decrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter)
JS::NonnullGCPtr<WebIDL::Promise> SubtleCrypto::decrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter)
{
auto& realm = this->realm();
auto& vm = this->vm();
@ -231,11 +231,11 @@ JS::NonnullGCPtr<JS::Promise> SubtleCrypto::decrypt(AlgorithmIdentifier const& a
WebIDL::resolve_promise(realm, promise, plain_text.release_value());
});
return verify_cast<JS::Promise>(*promise->promise());
return promise;
}
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-digest
JS::NonnullGCPtr<JS::Promise> SubtleCrypto::digest(AlgorithmIdentifier const& algorithm, JS::Handle<WebIDL::BufferSource> const& data)
JS::NonnullGCPtr<WebIDL::Promise> SubtleCrypto::digest(AlgorithmIdentifier const& algorithm, JS::Handle<WebIDL::BufferSource> const& data)
{
auto& realm = this->realm();
auto& vm = this->vm();
@ -279,11 +279,11 @@ JS::NonnullGCPtr<JS::Promise> SubtleCrypto::digest(AlgorithmIdentifier const& al
WebIDL::resolve_promise(realm, promise, result.release_value());
});
return verify_cast<JS::Promise>(*promise->promise());
return promise;
}
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-generateKey
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::generate_key(AlgorithmIdentifier algorithm, bool extractable, Vector<Bindings::KeyUsage> key_usages)
JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> SubtleCrypto::generate_key(AlgorithmIdentifier algorithm, bool extractable, Vector<Bindings::KeyUsage> key_usages)
{
auto& realm = this->realm();
@ -339,11 +339,11 @@ JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::generate_key(
});
});
return verify_cast<JS::Promise>(*promise->promise());
return promise;
}
// https://w3c.github.io/webcrypto/#SubtleCrypto-method-importKey
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::import_key(Bindings::KeyFormat format, KeyDataType key_data, AlgorithmIdentifier algorithm, bool extractable, Vector<Bindings::KeyUsage> key_usages)
JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> SubtleCrypto::import_key(Bindings::KeyFormat format, KeyDataType key_data, AlgorithmIdentifier algorithm, bool extractable, Vector<Bindings::KeyUsage> key_usages)
{
auto& realm = this->realm();
@ -415,11 +415,11 @@ JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::import_key(Bi
WebIDL::resolve_promise(realm, promise, result);
});
return verify_cast<JS::Promise>(*promise->promise());
return promise;
}
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-exportKey
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::export_key(Bindings::KeyFormat format, JS::NonnullGCPtr<CryptoKey> key)
JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> SubtleCrypto::export_key(Bindings::KeyFormat format, JS::NonnullGCPtr<CryptoKey> key)
{
auto& realm = this->realm();
// 1. Let format and key be the format and key parameters passed to the exportKey() method, respectively.
@ -461,11 +461,11 @@ JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::export_key(Bi
WebIDL::resolve_promise(realm, promise, result_or_error.release_value());
});
return verify_cast<JS::Promise>(*promise->promise());
return promise;
}
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-sign
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::sign(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter)
JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> SubtleCrypto::sign(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter)
{
auto& realm = this->realm();
auto& vm = this->vm();
@ -518,11 +518,11 @@ JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::sign(Algorith
WebIDL::resolve_promise(realm, promise, result.release_value());
});
return verify_cast<JS::Promise>(*promise->promise());
return promise;
}
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-verify
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::verify(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& signature_data, JS::Handle<WebIDL::BufferSource> const& data_parameter)
JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> SubtleCrypto::verify(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& signature_data, JS::Handle<WebIDL::BufferSource> const& data_parameter)
{
auto& realm = this->realm();
auto& vm = this->vm();
@ -582,11 +582,11 @@ JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::verify(Algori
WebIDL::resolve_promise(realm, promise, result.release_value());
});
return verify_cast<JS::Promise>(*promise->promise());
return promise;
}
// https://w3c.github.io/webcrypto/#SubtleCrypto-method-deriveBits
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::derive_bits(AlgorithmIdentifier algorithm, JS::NonnullGCPtr<CryptoKey> base_key, u32 length)
JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> SubtleCrypto::derive_bits(AlgorithmIdentifier algorithm, JS::NonnullGCPtr<CryptoKey> base_key, u32 length)
{
auto& realm = this->realm();
// 1. Let algorithm, baseKey and length, be the algorithm, baseKey and length parameters passed to the deriveBits() method, respectively.
@ -629,10 +629,10 @@ JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::derive_bits(A
WebIDL::resolve_promise(realm, promise, result.release_value());
});
return verify_cast<JS::Promise>(*promise->promise());
return promise;
}
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::derive_key(AlgorithmIdentifier algorithm, JS::NonnullGCPtr<CryptoKey> base_key, AlgorithmIdentifier derived_key_type, bool extractable, Vector<Bindings::KeyUsage> key_usages)
JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> SubtleCrypto::derive_key(AlgorithmIdentifier algorithm, JS::NonnullGCPtr<CryptoKey> base_key, AlgorithmIdentifier derived_key_type, bool extractable, Vector<Bindings::KeyUsage> key_usages)
{
auto& realm = this->realm();
auto& vm = this->vm();
@ -722,7 +722,7 @@ JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::derive_key(Al
WebIDL::resolve_promise(realm, promise, result.release_value());
});
return verify_cast<JS::Promise>(*promise->promise());
return promise;
}
SupportedAlgorithmsMap& supported_algorithms_internal()

View file

@ -27,19 +27,19 @@ public:
virtual ~SubtleCrypto() override;
JS::NonnullGCPtr<JS::Promise> encrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter);
JS::NonnullGCPtr<JS::Promise> decrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter);
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> sign(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter);
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> verify(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& signature, JS::Handle<WebIDL::BufferSource> const& data_parameter);
JS::NonnullGCPtr<WebIDL::Promise> encrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter);
JS::NonnullGCPtr<WebIDL::Promise> decrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter);
JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> sign(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter);
JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> verify(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& signature, JS::Handle<WebIDL::BufferSource> const& data_parameter);
JS::NonnullGCPtr<JS::Promise> digest(AlgorithmIdentifier const& algorithm, JS::Handle<WebIDL::BufferSource> const& data);
JS::NonnullGCPtr<WebIDL::Promise> digest(AlgorithmIdentifier const& algorithm, JS::Handle<WebIDL::BufferSource> const& data);
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> generate_key(AlgorithmIdentifier algorithm, bool extractable, Vector<Bindings::KeyUsage> key_usages);
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> derive_bits(AlgorithmIdentifier algorithm, JS::NonnullGCPtr<CryptoKey> base_key, u32 length);
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> derive_key(AlgorithmIdentifier algorithm, JS::NonnullGCPtr<CryptoKey> base_key, AlgorithmIdentifier derived_key_type, bool extractable, Vector<Bindings::KeyUsage> key_usages);
JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> generate_key(AlgorithmIdentifier algorithm, bool extractable, Vector<Bindings::KeyUsage> key_usages);
JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> derive_bits(AlgorithmIdentifier algorithm, JS::NonnullGCPtr<CryptoKey> base_key, u32 length);
JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> derive_key(AlgorithmIdentifier algorithm, JS::NonnullGCPtr<CryptoKey> base_key, AlgorithmIdentifier derived_key_type, bool extractable, Vector<Bindings::KeyUsage> key_usages);
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> import_key(Bindings::KeyFormat format, KeyDataType key_data, AlgorithmIdentifier algorithm, bool extractable, Vector<Bindings::KeyUsage> key_usages);
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> export_key(Bindings::KeyFormat format, JS::NonnullGCPtr<CryptoKey> key);
JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> import_key(Bindings::KeyFormat format, KeyDataType key_data, AlgorithmIdentifier algorithm, bool extractable, Vector<Bindings::KeyUsage> key_usages);
JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> export_key(Bindings::KeyFormat format, JS::NonnullGCPtr<CryptoKey> key);
private:
explicit SubtleCrypto(JS::Realm&);

View file

@ -55,7 +55,7 @@ bool BodyMixin::body_used() const
}
// https://fetch.spec.whatwg.org/#dom-body-arraybuffer
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> BodyMixin::array_buffer() const
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> BodyMixin::array_buffer() const
{
auto& vm = Bindings::main_thread_vm();
auto& realm = *vm.current_realm();
@ -65,7 +65,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> BodyMixin::array_buffer() con
}
// https://fetch.spec.whatwg.org/#dom-body-blob
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> BodyMixin::blob() const
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> BodyMixin::blob() const
{
auto& vm = Bindings::main_thread_vm();
auto& realm = *vm.current_realm();
@ -75,7 +75,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> BodyMixin::blob() const
}
// https://fetch.spec.whatwg.org/#dom-body-bytes
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> BodyMixin::bytes() const
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> BodyMixin::bytes() const
{
auto& vm = Bindings::main_thread_vm();
auto& realm = *vm.current_realm();
@ -85,7 +85,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> BodyMixin::bytes() const
}
// https://fetch.spec.whatwg.org/#dom-body-formdata
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> BodyMixin::form_data() const
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> BodyMixin::form_data() const
{
auto& vm = Bindings::main_thread_vm();
auto& realm = *vm.current_realm();
@ -95,7 +95,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> BodyMixin::form_data() const
}
// https://fetch.spec.whatwg.org/#dom-body-json
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> BodyMixin::json() const
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> BodyMixin::json() const
{
auto& vm = Bindings::main_thread_vm();
auto& realm = *vm.current_realm();
@ -105,7 +105,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> BodyMixin::json() const
}
// https://fetch.spec.whatwg.org/#dom-body-text
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> BodyMixin::text() const
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> BodyMixin::text() const
{
auto& vm = Bindings::main_thread_vm();
auto& realm = *vm.current_realm();
@ -175,7 +175,7 @@ WebIDL::ExceptionOr<JS::Value> package_data(JS::Realm& realm, ByteBuffer bytes,
}
// https://fetch.spec.whatwg.org/#concept-body-consume-body
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> consume_body(JS::Realm& realm, BodyMixin const& object, PackageDataType type)
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> consume_body(JS::Realm& realm, BodyMixin const& object, PackageDataType type)
{
// 1. If object is unusable, then return a promise rejected with a TypeError.
if (object.is_unusable()) {
@ -229,7 +229,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> consume_body(JS::Realm& realm
}
// 7. Return promise.
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise().ptr()) };
return promise;
}
}

View file

@ -39,15 +39,15 @@ public:
[[nodiscard]] bool body_used() const;
// JS API functions
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> array_buffer() const;
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> blob() const;
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> bytes() const;
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> form_data() const;
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> json() const;
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> text() const;
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> array_buffer() const;
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> blob() const;
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> bytes() const;
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> form_data() const;
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> json() const;
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> text() const;
};
[[nodiscard]] WebIDL::ExceptionOr<JS::Value> package_data(JS::Realm&, ByteBuffer, PackageDataType, Optional<MimeSniff::MimeType> const&);
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> consume_body(JS::Realm&, BodyMixin const&, PackageDataType);
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> consume_body(JS::Realm&, BodyMixin const&, PackageDataType);
}

View file

@ -26,7 +26,7 @@
namespace Web::Fetch {
// https://fetch.spec.whatwg.org/#dom-global-fetch
JS::NonnullGCPtr<JS::Promise> fetch(JS::VM& vm, RequestInfo const& input, RequestInit const& init)
JS::NonnullGCPtr<WebIDL::Promise> fetch(JS::VM& vm, RequestInfo const& input, RequestInit const& init)
{
auto& realm = *vm.current_realm();
@ -39,7 +39,7 @@ JS::NonnullGCPtr<JS::Promise> fetch(JS::VM& vm, RequestInfo const& input, Reques
if (exception_or_request_object.is_exception()) {
auto throw_completion = Bindings::dom_exception_to_throw_completion(vm, exception_or_request_object.exception());
WebIDL::reject_promise(realm, promise_capability, *throw_completion.value());
return verify_cast<JS::Promise>(*promise_capability->promise().ptr());
return promise_capability;
}
auto request_object = exception_or_request_object.release_value();
@ -52,7 +52,7 @@ JS::NonnullGCPtr<JS::Promise> fetch(JS::VM& vm, RequestInfo const& input, Reques
abort_fetch(realm, promise_capability, request, nullptr, request_object->signal()->reason());
// 2. Return p.
return verify_cast<JS::Promise>(*promise_capability->promise().ptr());
return promise_capability;
}
// 5. Let globalObject be requests clients global object.
@ -150,7 +150,7 @@ JS::NonnullGCPtr<JS::Promise> fetch(JS::VM& vm, RequestInfo const& input, Reques
});
// 13. Return p.
return verify_cast<JS::Promise>(*promise_capability->promise().ptr());
return promise_capability;
}
// https://fetch.spec.whatwg.org/#abort-fetch

View file

@ -14,7 +14,7 @@
namespace Web::Fetch {
JS::NonnullGCPtr<JS::Promise> fetch(JS::VM&, RequestInfo const& input, RequestInit const& init = {});
JS::NonnullGCPtr<WebIDL::Promise> fetch(JS::VM&, RequestInfo const& input, RequestInit const& init = {});
void abort_fetch(JS::Realm&, WebIDL::Promise const&, JS::NonnullGCPtr<Infrastructure::Request>, JS::GCPtr<Response>, JS::Value error);
}

View file

@ -377,7 +377,7 @@ JS::NonnullGCPtr<Streams::ReadableStream> Blob::get_stream()
}
// https://w3c.github.io/FileAPI/#dom-blob-text
JS::NonnullGCPtr<JS::Promise> Blob::text()
JS::NonnullGCPtr<WebIDL::Promise> Blob::text()
{
auto& realm = this->realm();
auto& vm = realm.vm();
@ -407,7 +407,7 @@ JS::NonnullGCPtr<JS::Promise> Blob::text()
}
// https://w3c.github.io/FileAPI/#dom-blob-arraybuffer
JS::NonnullGCPtr<JS::Promise> Blob::array_buffer()
JS::NonnullGCPtr<WebIDL::Promise> Blob::array_buffer()
{
auto& realm = this->realm();
@ -434,7 +434,7 @@ JS::NonnullGCPtr<JS::Promise> Blob::array_buffer()
}
// https://w3c.github.io/FileAPI/#dom-blob-bytes
JS::NonnullGCPtr<JS::Promise> Blob::bytes()
JS::NonnullGCPtr<WebIDL::Promise> Blob::bytes()
{
auto& realm = this->realm();

View file

@ -48,9 +48,9 @@ public:
WebIDL::ExceptionOr<JS::NonnullGCPtr<Blob>> slice(Optional<i64> start = {}, Optional<i64> end = {}, Optional<String> const& content_type = {});
JS::NonnullGCPtr<Streams::ReadableStream> stream();
JS::NonnullGCPtr<JS::Promise> text();
JS::NonnullGCPtr<JS::Promise> array_buffer();
JS::NonnullGCPtr<JS::Promise> bytes();
JS::NonnullGCPtr<WebIDL::Promise> text();
JS::NonnullGCPtr<WebIDL::Promise> array_buffer();
JS::NonnullGCPtr<WebIDL::Promise> bytes();
ReadonlyBytes raw_bytes() const { return m_byte_buffer.bytes(); }

View file

@ -147,20 +147,23 @@ WebIDL::ExceptionOr<void> FileReader::read_operation(Blob& blob, Type type, Opti
// 10. In parallel, while true:
Platform::EventLoopPlugin::the().deferred_invoke([this, chunk_promise, reader, bytes, is_first_chunk, &realm, type, encoding_name, blobs_type]() mutable {
HTML::TemporaryExecutionContext execution_context { Bindings::host_defined_environment_settings_object(realm) };
HTML::TemporaryExecutionContext execution_context { Bindings::host_defined_environment_settings_object(realm), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes };
Optional<MonotonicTime> progress_timer;
while (true) {
auto& vm = realm.vm();
// FIXME: Try harder to not reach into the [[Promise]] slot of chunkPromise
auto promise = JS::NonnullGCPtr { verify_cast<JS::Promise>(*chunk_promise->promise()) };
// 1. Wait for chunkPromise to be fulfilled or rejected.
// FIXME: Create spec issue to use WebIDL react to promise steps here instead of this custom logic
Platform::EventLoopPlugin::the().spin_until([&]() {
return chunk_promise->state() == JS::Promise::State::Fulfilled || chunk_promise->state() == JS::Promise::State::Rejected;
return promise->state() == JS::Promise::State::Fulfilled || promise->state() == JS::Promise::State::Rejected;
});
// 2. If chunkPromise is fulfilled, and isFirstChunk is true, queue a task to fire a progress event called loadstart at fr.
// NOTE: ISSUE 2 We might change loadstart to be dispatched synchronously, to align with XMLHttpRequest behavior. [Issue #119]
if (chunk_promise->state() == JS::Promise::State::Fulfilled && is_first_chunk) {
if (promise->state() == JS::Promise::State::Fulfilled && is_first_chunk) {
HTML::queue_global_task(HTML::Task::Source::FileReading, realm.global_object(), JS::create_heap_function(heap(), [this, &realm]() {
dispatch_event(DOM::Event::create(realm, HTML::EventNames::loadstart));
}));
@ -169,14 +172,14 @@ WebIDL::ExceptionOr<void> FileReader::read_operation(Blob& blob, Type type, Opti
// 3. Set isFirstChunk to false.
is_first_chunk = false;
VERIFY(chunk_promise->result().is_object());
auto& result = chunk_promise->result().as_object();
VERIFY(promise->result().is_object());
auto& result = promise->result().as_object();
auto value = MUST(result.get(vm.names.value));
auto done = MUST(result.get(vm.names.done));
// 4. If chunkPromise is fulfilled with an object whose done property is false and whose value property is a Uint8Array object, run these steps:
if (chunk_promise->state() == JS::Promise::State::Fulfilled && !done.as_bool() && is<JS::Uint8Array>(value.as_object())) {
if (promise->state() == JS::Promise::State::Fulfilled && !done.as_bool() && is<JS::Uint8Array>(value.as_object())) {
// 1. Let bs be the byte sequence represented by the Uint8Array object.
auto const& byte_sequence = verify_cast<JS::Uint8Array>(value.as_object());
@ -200,7 +203,7 @@ WebIDL::ExceptionOr<void> FileReader::read_operation(Blob& blob, Type type, Opti
chunk_promise = reader->read();
}
// 5. Otherwise, if chunkPromise is fulfilled with an object whose done property is true, queue a task to run the following steps and abort this algorithm:
else if (chunk_promise->state() == JS::Promise::State::Fulfilled && done.as_bool()) {
else if (promise->state() == JS::Promise::State::Fulfilled && done.as_bool()) {
HTML::queue_global_task(HTML::Task::Source::FileReading, realm.global_object(), JS::create_heap_function(heap(), [this, bytes, type, &realm, encoding_name, blobs_type]() {
// 1. Set frs state to "done".
m_state = State::Done;
@ -234,7 +237,7 @@ WebIDL::ExceptionOr<void> FileReader::read_operation(Blob& blob, Type type, Opti
return;
}
// 6. Otherwise, if chunkPromise is rejected with an error error, queue a task to run the following steps and abort this algorithm:
else if (chunk_promise->state() == JS::Promise::State::Rejected) {
else if (promise->state() == JS::Promise::State::Rejected) {
HTML::queue_global_task(HTML::Task::Source::FileReading, realm.global_object(), JS::create_heap_function(heap(), [this, &realm]() {
// 1. Set frs state to "done".
m_state = State::Done;
@ -250,6 +253,8 @@ WebIDL::ExceptionOr<void> FileReader::read_operation(Blob& blob, Type type, Opti
// 5. Note: Event handler for the error event could have started another load, if that happens the loadend event for this load is not fired.
}));
return;
}
}
});

View file

@ -313,7 +313,7 @@ JS::ThrowCompletionOr<void> CustomElementRegistry::define(String const& name, We
auto promise = promise_when_defined_iterator->value;
// 2. Resolve promise with constructor.
promise->fulfill(constructor->callback);
WebIDL::resolve_promise(realm, promise, constructor->callback);
// 3. Delete the entry with key name from this CustomElementRegistry's when-defined promise map.
m_when_defined_promise_map.remove(name);
@ -353,40 +353,34 @@ Optional<String> CustomElementRegistry::get_name(JS::Handle<WebIDL::CallbackType
}
// https://html.spec.whatwg.org/multipage/custom-elements.html#dom-customelementregistry-whendefined
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> CustomElementRegistry::when_defined(String const& name)
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> CustomElementRegistry::when_defined(String const& name)
{
auto& realm = this->realm();
// 1. If name is not a valid custom element name, then return a new promise rejected with a "SyntaxError" DOMException.
if (!is_valid_custom_element_name(name)) {
auto promise = JS::Promise::create(realm);
promise->reject(WebIDL::SyntaxError::create(realm, MUST(String::formatted("'{}' is not a valid custom element name"sv, name))));
return promise;
}
if (!is_valid_custom_element_name(name))
return WebIDL::create_rejected_promise(realm, WebIDL::SyntaxError::create(realm, MUST(String::formatted("'{}' is not a valid custom element name"sv, name))));
// 2. If this CustomElementRegistry contains an entry with name name, then return a new promise resolved with that entry's constructor.
auto existing_definition_iterator = m_custom_element_definitions.find_if([&name](JS::Handle<CustomElementDefinition> const& definition) {
return definition->name() == name;
});
if (existing_definition_iterator != m_custom_element_definitions.end()) {
auto promise = JS::Promise::create(realm);
promise->fulfill((*existing_definition_iterator)->constructor().callback);
return promise;
}
if (existing_definition_iterator != m_custom_element_definitions.end())
return WebIDL::create_resolved_promise(realm, (*existing_definition_iterator)->constructor().callback);
// 3. Let map be this CustomElementRegistry's when-defined promise map.
// NOTE: Not necessary.
// 4. If map does not contain an entry with key name, create an entry in map with key name and whose value is a new promise.
// 5. Let promise be the value of the entry in map with key name.
JS::GCPtr<JS::Promise> promise;
JS::GCPtr<WebIDL::Promise> promise;
auto existing_promise_iterator = m_when_defined_promise_map.find(name);
if (existing_promise_iterator != m_when_defined_promise_map.end()) {
promise = existing_promise_iterator->value;
} else {
promise = JS::Promise::create(realm);
promise = WebIDL::create_promise(realm);
m_when_defined_promise_map.set(name, *promise);
}

View file

@ -27,7 +27,7 @@ public:
JS::ThrowCompletionOr<void> define(String const& name, WebIDL::CallbackType* constructor, ElementDefinitionOptions options);
Variant<JS::Handle<WebIDL::CallbackType>, JS::Value> get(String const& name) const;
Optional<String> get_name(JS::Handle<WebIDL::CallbackType> const& constructor) const;
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> when_defined(String const& name);
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> when_defined(String const& name);
void upgrade(JS::NonnullGCPtr<DOM::Node> root) const;
JS::GCPtr<CustomElementDefinition> get_definition_with_name_and_local_name(String const& name, String const& local_name) const;
@ -48,7 +48,7 @@ private:
// https://html.spec.whatwg.org/multipage/custom-elements.html#when-defined-promise-map
// Every CustomElementRegistry also has a when-defined promise map, mapping valid custom element names to promises. It is used to implement the whenDefined() method.
OrderedHashMap<String, JS::NonnullGCPtr<JS::Promise>> m_when_defined_promise_map;
OrderedHashMap<String, JS::NonnullGCPtr<WebIDL::Promise>> m_when_defined_promise_map;
};
}

View file

@ -282,7 +282,7 @@ String HTMLImageElement::current_src() const
}
// https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-decode
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> HTMLImageElement::decode() const
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> HTMLImageElement::decode() const
{
auto& realm = this->realm();
@ -360,7 +360,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> HTMLImageElement::decode() co
});
}));
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise()) };
return promise;
}
Optional<ARIA::Role> HTMLImageElement::default_role() const

View file

@ -61,7 +61,7 @@ public:
String current_src() const;
// https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-decode
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> decode() const;
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> decode() const;
virtual Optional<ARIA::Role> default_role() const override;

View file

@ -334,7 +334,7 @@ void HTMLMediaElement::set_duration(double duration)
paintable->set_needs_display();
}
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> HTMLMediaElement::play()
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> HTMLMediaElement::play()
{
auto& realm = this->realm();
@ -355,7 +355,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> HTMLMediaElement::play()
TRY(play_element());
// 5. Return promise.
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise()) };
return promise;
}
// https://html.spec.whatwg.org/multipage/media.html#dom-media-pause

View file

@ -89,7 +89,7 @@ public:
bool paused() const { return m_paused; }
bool ended() const;
bool potentially_playing() const;
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> play();
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> play();
WebIDL::ExceptionOr<void> pause();
WebIDL::ExceptionOr<void> toggle_playback();

View file

@ -495,14 +495,13 @@ i64 Navigation::get_the_navigation_api_entry_index(SessionHistoryEntry const& sh
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigation-api-early-error-result
NavigationResult Navigation::early_error_result(AnyException e)
{
auto& vm = this->vm();
auto& realm = this->realm();
// An early error result for an exception e is a NavigationResult dictionary instance given by
// «[ "committed" → a promise rejected with e, "finished" → a promise rejected with e ]».
auto throw_completion = Bindings::dom_exception_to_throw_completion(vm, e);
return {
.committed = WebIDL::create_rejected_promise(realm(), *throw_completion.value())->promise(),
.finished = WebIDL::create_rejected_promise(realm(), *throw_completion.value())->promise(),
.committed = WebIDL::create_rejected_promise_from_exception(realm, e),
.finished = WebIDL::create_rejected_promise_from_exception(realm, e),
};
}
@ -512,8 +511,8 @@ NavigationResult navigation_api_method_tracker_derived_result(JS::NonnullGCPtr<N
// A navigation API method tracker-derived result for a navigation API method tracker is a NavigationResult
/// dictionary instance given by «[ "committed" apiMethodTracker's committed promise, "finished" → apiMethodTracker's finished promise ]».
return {
api_method_tracker->committed_promise->promise(),
api_method_tracker->finished_promise->promise(),
api_method_tracker->committed_promise,
api_method_tracker->finished_promise,
};
}
@ -639,8 +638,8 @@ WebIDL::ExceptionOr<NavigationResult> Navigation::perform_a_navigation_api_trave
// «[ "committed" → a promise resolved with current, "finished" → a promise resolved with current ]».
if (key == current->session_history_entry().navigation_api_key()) {
return NavigationResult {
.committed = WebIDL::create_resolved_promise(realm, current)->promise(),
.finished = WebIDL::create_resolved_promise(realm, current)->promise()
.committed = WebIDL::create_resolved_promise(realm, current),
.finished = WebIDL::create_resolved_promise(realm, current)
};
}
@ -788,7 +787,7 @@ void Navigation::abort_the_ongoing_navigation(JS::GCPtr<WebIDL::DOMException> er
// 11. If navigation's transition is not null, then:
if (m_transition != nullptr) {
// 1. Reject navigation's transition's finished promise with error.
m_transition->finished()->reject(error);
WebIDL::reject_promise(realm, m_transition->finished(), error);
// 2. Set navigation's transition to null.
m_transition = nullptr;
@ -1105,10 +1104,10 @@ bool Navigation::inner_navigate_event_firing_algorithm(
// 4. Set navigation's transition to a new NavigationTransition created in navigation's relevant realm,
// whose navigation type is navigationType, from entry is fromNHE, and whose finished promise is a new promise
// created in navigation's relevant realm.
m_transition = NavigationTransition::create(realm, navigation_type, *from_nhe, JS::Promise::create(realm));
m_transition = NavigationTransition::create(realm, navigation_type, *from_nhe, WebIDL::create_promise(realm));
// 5. Mark as handled navigation's transition's finished promise.
m_transition->finished()->set_is_handled();
WebIDL::mark_promise_as_handled(*m_transition->finished());
// 6. If navigationType is "traverse", then set navigation's suppress normal scroll restoration during ongoing navigation to true.
// NOTE: If event's scroll behavior was set to "after-transition", then scroll restoration will happen as part of finishing
@ -1187,7 +1186,7 @@ bool Navigation::inner_navigate_event_firing_algorithm(
// 8. If navigation's transition is not null, then resolve navigation's transition's finished promise with undefined.
if (m_transition != nullptr)
m_transition->finished()->fulfill(JS::js_undefined());
WebIDL::resolve_promise(realm, m_transition->finished(), JS::js_undefined());
// 9. Set navigation's transition to null.
m_transition = nullptr; },
@ -1231,7 +1230,7 @@ bool Navigation::inner_navigate_event_firing_algorithm(
// 9. If navigation's transition is not null, then reject navigation's transition's finished promise with rejectionReason.
if (m_transition)
m_transition->finished()->reject(rejection_reason);
WebIDL::reject_promise(realm, m_transition->finished(), rejection_reason);
// 10. Set navigation's transition to null.
m_transition = nullptr;

View file

@ -39,9 +39,8 @@ struct NavigationReloadOptions : public NavigationOptions {
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigationresult
struct NavigationResult {
// FIXME: Are we supposed to return a PromiseCapability (WebIDL::Promise) here?
JS::NonnullGCPtr<JS::Object> committed;
JS::NonnullGCPtr<JS::Object> finished;
JS::NonnullGCPtr<WebIDL::Promise> committed;
JS::NonnullGCPtr<WebIDL::Promise> finished;
};
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigation-api-method-tracker

View file

@ -5,23 +5,23 @@
*/
#include <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/Promise.h>
#include <LibJS/Runtime/Realm.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Bindings/NavigationTransitionPrototype.h>
#include <LibWeb/HTML/NavigationHistoryEntry.h>
#include <LibWeb/HTML/NavigationTransition.h>
#include <LibWeb/WebIDL/Promise.h>
namespace Web::HTML {
JS_DEFINE_ALLOCATOR(NavigationTransition);
JS::NonnullGCPtr<NavigationTransition> NavigationTransition::create(JS::Realm& realm, Bindings::NavigationType navigation_type, JS::NonnullGCPtr<NavigationHistoryEntry> from_entry, JS::GCPtr<JS::Promise> finished_promise)
JS::NonnullGCPtr<NavigationTransition> NavigationTransition::create(JS::Realm& realm, Bindings::NavigationType navigation_type, JS::NonnullGCPtr<NavigationHistoryEntry> from_entry, JS::NonnullGCPtr<WebIDL::Promise> finished_promise)
{
return realm.heap().allocate<NavigationTransition>(realm, realm, navigation_type, from_entry, finished_promise);
}
NavigationTransition::NavigationTransition(JS::Realm& realm, Bindings::NavigationType navigation_type, JS::NonnullGCPtr<NavigationHistoryEntry> from_entry, JS::GCPtr<JS::Promise> finished_promise)
NavigationTransition::NavigationTransition(JS::Realm& realm, Bindings::NavigationType navigation_type, JS::NonnullGCPtr<NavigationHistoryEntry> from_entry, JS::NonnullGCPtr<WebIDL::Promise> finished_promise)
: Bindings::PlatformObject(realm)
, m_navigation_type(navigation_type)
, m_from_entry(from_entry)

View file

@ -17,7 +17,7 @@ class NavigationTransition : public Bindings::PlatformObject {
JS_DECLARE_ALLOCATOR(NavigationTransition);
public:
[[nodiscard]] static JS::NonnullGCPtr<NavigationTransition> create(JS::Realm&, Bindings::NavigationType, JS::NonnullGCPtr<NavigationHistoryEntry>, JS::GCPtr<JS::Promise>);
[[nodiscard]] static JS::NonnullGCPtr<NavigationTransition> create(JS::Realm&, Bindings::NavigationType, JS::NonnullGCPtr<NavigationHistoryEntry>, JS::NonnullGCPtr<WebIDL::Promise>);
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-navigationtransition-navigationtype
Bindings::NavigationType navigation_type() const { return m_navigation_type; }
@ -26,12 +26,12 @@ public:
JS::NonnullGCPtr<NavigationHistoryEntry> from() const { return m_from_entry; }
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-navigationtransition-finished
JS::GCPtr<JS::Promise> finished() const { return m_finished_promise; }
JS::NonnullGCPtr<WebIDL::Promise> finished() const { return m_finished_promise; }
virtual ~NavigationTransition() override;
private:
NavigationTransition(JS::Realm&, Bindings::NavigationType, JS::NonnullGCPtr<NavigationHistoryEntry>, JS::GCPtr<JS::Promise>);
NavigationTransition(JS::Realm&, Bindings::NavigationType, JS::NonnullGCPtr<NavigationHistoryEntry>, JS::NonnullGCPtr<WebIDL::Promise>);
virtual void initialize(JS::Realm&) override;
virtual void visit_edges(JS::Cell::Visitor&) override;
@ -43,7 +43,7 @@ private:
JS::NonnullGCPtr<NavigationHistoryEntry> m_from_entry;
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#concept-navigationtransition-finished
JS::GCPtr<JS::Promise> m_finished_promise;
JS::NonnullGCPtr<WebIDL::Promise> m_finished_promise;
};
}

View file

@ -6,6 +6,7 @@
#pragma once
#include <LibJS/Heap/GCPtr.h>
#include <LibWeb/Forward.h>
namespace Web::HTML {

View file

@ -44,7 +44,7 @@ JS::NonnullGCPtr<ServiceWorkerContainer> ServiceWorkerContainer::create(JS::Real
}
// https://w3c.github.io/ServiceWorker/#navigator-service-worker-register
JS::NonnullGCPtr<JS::Promise> ServiceWorkerContainer::register_(String script_url, RegistrationOptions const& options)
JS::NonnullGCPtr<WebIDL::Promise> ServiceWorkerContainer::register_(String script_url, RegistrationOptions const& options)
{
auto& realm = this->realm();
// Note: The register(scriptURL, options) method creates or updates a service worker registration for the given scope url.
@ -76,7 +76,7 @@ JS::NonnullGCPtr<JS::Promise> ServiceWorkerContainer::register_(String script_ur
start_register(scope_url, parsed_script_url, p, client, client->creation_url, options.type, options.update_via_cache);
// 8. Return p.
return verify_cast<JS::Promise>(*p->promise());
return p;
}
// https://w3c.github.io/ServiceWorker/#start-register-algorithm

View file

@ -34,7 +34,7 @@ public:
[[nodiscard]] static JS::NonnullGCPtr<ServiceWorkerContainer> create(JS::Realm& realm);
virtual ~ServiceWorkerContainer() override;
JS::NonnullGCPtr<JS::Promise> register_(String script_url, RegistrationOptions const& options);
JS::NonnullGCPtr<WebIDL::Promise> register_(String script_url, RegistrationOptions const& options);
#undef __ENUMERATE
#define __ENUMERATE(attribute_name, event_name) \

View file

@ -27,6 +27,7 @@
#include <LibWeb/HTML/Scripting/Environments.h>
#include <LibWeb/HTML/Scripting/ExceptionReporter.h>
#include <LibWeb/HTML/Scripting/Fetching.h>
#include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
#include <LibWeb/HTML/StructuredSerialize.h>
#include <LibWeb/HTML/StructuredSerializeOptions.h>
#include <LibWeb/HTML/Timer.h>
@ -166,25 +167,26 @@ void WindowOrWorkerGlobalScopeMixin::queue_microtask(WebIDL::CallbackType& callb
}
// https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#dom-createimagebitmap
JS::NonnullGCPtr<JS::Promise> WindowOrWorkerGlobalScopeMixin::create_image_bitmap(ImageBitmapSource image, Optional<ImageBitmapOptions> options) const
JS::NonnullGCPtr<WebIDL::Promise> WindowOrWorkerGlobalScopeMixin::create_image_bitmap(ImageBitmapSource image, Optional<ImageBitmapOptions> options) const
{
return create_image_bitmap_impl(image, {}, {}, {}, {}, options);
}
// https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#dom-createimagebitmap
JS::NonnullGCPtr<JS::Promise> WindowOrWorkerGlobalScopeMixin::create_image_bitmap(ImageBitmapSource image, WebIDL::Long sx, WebIDL::Long sy, WebIDL::Long sw, WebIDL::Long sh, Optional<ImageBitmapOptions> options) const
JS::NonnullGCPtr<WebIDL::Promise> WindowOrWorkerGlobalScopeMixin::create_image_bitmap(ImageBitmapSource image, WebIDL::Long sx, WebIDL::Long sy, WebIDL::Long sw, WebIDL::Long sh, Optional<ImageBitmapOptions> options) const
{
return create_image_bitmap_impl(image, sx, sy, sw, sh, options);
}
JS::NonnullGCPtr<JS::Promise> WindowOrWorkerGlobalScopeMixin::create_image_bitmap_impl(ImageBitmapSource& image, Optional<WebIDL::Long> sx, Optional<WebIDL::Long> sy, Optional<WebIDL::Long> sw, Optional<WebIDL::Long> sh, Optional<ImageBitmapOptions>& options) const
JS::NonnullGCPtr<WebIDL::Promise> WindowOrWorkerGlobalScopeMixin::create_image_bitmap_impl(ImageBitmapSource& image, Optional<WebIDL::Long> sx, Optional<WebIDL::Long> sy, Optional<WebIDL::Long> sw, Optional<WebIDL::Long> sh, Optional<ImageBitmapOptions>& options) const
{
auto& realm = this_impl().realm();
// 1. If either sw or sh is given and is 0, then return a promise rejected with a RangeError.
if (sw == 0 || sh == 0) {
auto promise = JS::Promise::create(this_impl().realm());
auto error_message = MUST(String::formatted("{} is an invalid value for {}", sw == 0 ? *sw : *sh, sw == 0 ? "sw"sv : "sh"sv));
promise->reject(JS::RangeError::create(this_impl().realm(), move(error_message)));
return promise;
auto error = JS::RangeError::create(realm, move(error_message));
return WebIDL::create_rejected_promise(realm, move(error));
}
// FIXME:
@ -195,14 +197,13 @@ JS::NonnullGCPtr<JS::Promise> WindowOrWorkerGlobalScopeMixin::create_image_bitma
// FIXME: "Check the usability of the image argument" is only defined for CanvasImageSource, let's skip it for other types
if (image.has<CanvasImageSource>()) {
if (auto usability = check_usability_of_image(image.get<CanvasImageSource>()); usability.is_error() or usability.value() == CanvasImageSourceUsability::Bad) {
auto promise = JS::Promise::create(this_impl().realm());
promise->reject(WebIDL::InvalidStateError::create(this_impl().realm(), "image argument is not usable"_string));
return promise;
auto error = WebIDL::InvalidStateError::create(this_impl().realm(), "image argument is not usable"_string);
return WebIDL::create_rejected_promise_from_exception(realm, error);
}
}
// 4. Let p be a new promise.
auto p = JS::Promise::create(this_impl().realm());
auto p = WebIDL::create_promise(realm);
// 5. Let imageBitmap be a new ImageBitmap object.
auto image_bitmap = ImageBitmap::create(this_impl().realm());
@ -226,7 +227,9 @@ JS::NonnullGCPtr<JS::Promise> WindowOrWorkerGlobalScopeMixin::create_image_bitma
// imageData is corrupted in some fatal way such that the image dimensions cannot be obtained
// (e.g., a vector graphic with no natural size), then reject p with an "InvalidStateError" DOMException
// and abort these steps.
p->reject(WebIDL::InvalidStateError::create(relevant_realm(*p), "image does not contain a supported image format"_string));
auto& realm = relevant_realm(p->promise());
TemporaryExecutionContext context { relevant_settings_object(p->promise()), TemporaryExecutionContext::CallbacksEnabled::Yes };
WebIDL::reject_promise(realm, *p, WebIDL::InvalidStateError::create(realm, "image does not contain a supported image format"_string));
};
auto on_successful_decode = [image_bitmap = JS::Handle(*image_bitmap), p = JS::Handle(*p)](Web::Platform::DecodedImage& result) -> ErrorOr<void> {
@ -236,8 +239,11 @@ JS::NonnullGCPtr<JS::Promise> WindowOrWorkerGlobalScopeMixin::create_image_bitma
// or is disabled), or, if there is no such image, the first frame of the animation.
image_bitmap->set_bitmap(result.frames.take_first().bitmap);
auto& realm = relevant_realm(p->promise());
// 5. Resolve p with imageBitmap.
p->fulfill(image_bitmap);
TemporaryExecutionContext context { relevant_settings_object(*image_bitmap), TemporaryExecutionContext::CallbacksEnabled::Yes };
WebIDL::resolve_promise(realm, *p, image_bitmap);
return {};
};
@ -248,7 +254,9 @@ JS::NonnullGCPtr<JS::Promise> WindowOrWorkerGlobalScopeMixin::create_image_bitma
dbgln("(STUBBED) createImageBitmap() for non-blob types");
(void)sx;
(void)sy;
p->reject(JS::Error::create(relevant_realm(*p), "Not Implemented: createImageBitmap() for non-blob types"sv));
auto error = JS::Error::create(realm, "Not Implemented: createImageBitmap() for non-blob types"sv);
TemporaryExecutionContext context { relevant_settings_object(p->promise()), TemporaryExecutionContext::CallbacksEnabled::Yes };
WebIDL::reject_promise(realm, *p, error);
});
// 7. Return p.
@ -273,7 +281,7 @@ WebIDL::ExceptionOr<JS::Value> WindowOrWorkerGlobalScopeMixin::structured_clone(
return deserialized;
}
JS::NonnullGCPtr<JS::Promise> WindowOrWorkerGlobalScopeMixin::fetch(Fetch::RequestInfo const& input, Fetch::RequestInit const& init) const
JS::NonnullGCPtr<WebIDL::Promise> WindowOrWorkerGlobalScopeMixin::fetch(Fetch::RequestInfo const& input, Fetch::RequestInit const& init) const
{
auto& vm = this_impl().vm();
return Fetch::fetch(vm, input, init);
@ -926,7 +934,7 @@ void WindowOrWorkerGlobalScopeMixin::notify_about_rejected_promises(Badge<EventL
.composed = false,
},
// Sadly we can't use .promise and .reason here, as we can't use the designator on the initialization of DOM::EventInit above.
/* .promise = */ JS::make_handle(*promise),
/* .promise = */ *promise,
/* .reason = */ promise->result(),
};

View file

@ -39,10 +39,10 @@ public:
WebIDL::ExceptionOr<String> btoa(String const& data) const;
WebIDL::ExceptionOr<String> atob(String const& data) const;
void queue_microtask(WebIDL::CallbackType&);
JS::NonnullGCPtr<JS::Promise> create_image_bitmap(ImageBitmapSource image, Optional<ImageBitmapOptions> options = {}) const;
JS::NonnullGCPtr<JS::Promise> create_image_bitmap(ImageBitmapSource image, WebIDL::Long sx, WebIDL::Long sy, WebIDL::Long sw, WebIDL::Long sh, Optional<ImageBitmapOptions> options = {}) const;
JS::NonnullGCPtr<WebIDL::Promise> create_image_bitmap(ImageBitmapSource image, Optional<ImageBitmapOptions> options = {}) const;
JS::NonnullGCPtr<WebIDL::Promise> create_image_bitmap(ImageBitmapSource image, WebIDL::Long sx, WebIDL::Long sy, WebIDL::Long sw, WebIDL::Long sh, Optional<ImageBitmapOptions> options = {}) const;
WebIDL::ExceptionOr<JS::Value> structured_clone(JS::Value, StructuredSerializeOptions const&) const;
JS::NonnullGCPtr<JS::Promise> fetch(Fetch::RequestInfo const&, Fetch::RequestInit const&) const;
JS::NonnullGCPtr<WebIDL::Promise> fetch(Fetch::RequestInfo const&, Fetch::RequestInit const&) const;
i32 set_timeout(TimerHandler, i32 timeout, JS::MarkedVector<JS::Value> arguments);
i32 set_interval(TimerHandler, i32 timeout, JS::MarkedVector<JS::Value> arguments);
@ -105,7 +105,7 @@ private:
i32 run_timer_initialization_steps(TimerHandler handler, i32 timeout, JS::MarkedVector<JS::Value> arguments, Repeat repeat, Optional<i32> previous_id = {});
void run_steps_after_a_timeout_impl(i32 timeout, Function<void()> completion_step, Optional<i32> timer_key = {});
JS::NonnullGCPtr<JS::Promise> create_image_bitmap_impl(ImageBitmapSource& image, Optional<WebIDL::Long> sx, Optional<WebIDL::Long> sy, Optional<WebIDL::Long> sw, Optional<WebIDL::Long> sh, Optional<ImageBitmapOptions>& options) const;
JS::NonnullGCPtr<WebIDL::Promise> create_image_bitmap_impl(ImageBitmapSource& image, Optional<WebIDL::Long> sx, Optional<WebIDL::Long> sy, Optional<WebIDL::Long> sw, Optional<WebIDL::Long> sh, Optional<ImageBitmapOptions>& options) const;
IDAllocator m_timer_id_allocator;
HashMap<int, JS::NonnullGCPtr<Timer>> m_timers;

View file

@ -131,7 +131,7 @@ JS::NonnullGCPtr<WebIDL::Promise> readable_stream_cancel(ReadableStream& stream,
JS::create_heap_function(stream.heap(), [](JS::Value) -> WebIDL::ExceptionOr<JS::Value> { return JS::js_undefined(); }),
{});
return WebIDL::create_resolved_promise(realm, react_result);
return react_result;
}
// https://streams.spec.whatwg.org/#readable-stream-fulfill-read-into-request
@ -431,9 +431,9 @@ public:
// 3. Resolve cancelPromise with ! ReadableStreamCancel(stream, cloneResult.[[Value]]).
auto cancel_result = readable_stream_cancel(m_stream, completion.value().value());
JS::NonnullGCPtr cancel_value = verify_cast<JS::Promise>(*cancel_result->promise().ptr());
WebIDL::resolve_promise(m_realm, m_cancel_promise, cancel_value);
// Note: We need to manually convert the result to an ECMAScript value here, by extracting its [[Promise]] slot.
WebIDL::resolve_promise(m_realm, m_cancel_promise, cancel_result->promise());
// 4. Return.
return;
@ -584,8 +584,7 @@ WebIDL::ExceptionOr<ReadableStreamPair> readable_stream_default_tee(JS::Realm& r
auto cancel_result = readable_stream_cancel(stream, composite_reason);
// 3. Resolve cancelPromise with cancelResult.
JS::NonnullGCPtr cancel_value = verify_cast<JS::Promise>(*cancel_result->promise().ptr());
WebIDL::resolve_promise(realm, cancel_promise, cancel_value);
WebIDL::resolve_promise(realm, cancel_promise, cancel_result->promise());
}
// 4. Return cancelPromise.
@ -609,8 +608,7 @@ WebIDL::ExceptionOr<ReadableStreamPair> readable_stream_default_tee(JS::Realm& r
auto cancel_result = readable_stream_cancel(stream, composite_reason);
// 3. Resolve cancelPromise with cancelResult.
JS::NonnullGCPtr cancel_value = verify_cast<JS::Promise>(*cancel_result->promise().ptr());
WebIDL::resolve_promise(realm, cancel_promise, cancel_value);
WebIDL::resolve_promise(realm, cancel_promise, cancel_result->promise());
}
// 4. Return cancelPromise.
@ -744,9 +742,8 @@ public:
// 3. Resolve cancelPromise with ! ReadableStreamCancel(stream, cloneResult.[[Value]]).
auto cancel_result = readable_stream_cancel(m_stream, completion.value().value());
JS::NonnullGCPtr cancel_value = verify_cast<JS::Promise>(*cancel_result->promise().ptr());
WebIDL::resolve_promise(m_realm, m_cancel_promise, cancel_value);
WebIDL::resolve_promise(m_realm, m_cancel_promise, cancel_result->promise());
// 4. Return.
return;
@ -909,9 +906,8 @@ public:
// 3. Resolve cancelPromise with ! ReadableStreamCancel(stream, cloneResult.[[Value]]).
auto cancel_result = readable_stream_cancel(m_stream, completion.value().value());
JS::NonnullGCPtr cancel_value = verify_cast<JS::Promise>(*cancel_result->promise().ptr());
WebIDL::resolve_promise(m_realm, m_cancel_promise, cancel_value);
WebIDL::resolve_promise(m_realm, m_cancel_promise, cancel_result->promise());
// 4. Return.
return;
@ -1221,8 +1217,7 @@ WebIDL::ExceptionOr<ReadableStreamPair> readable_byte_stream_tee(JS::Realm& real
auto cancel_result = readable_stream_cancel(stream, composite_reason);
// 3. Resolve cancelPromise with cancelResult.
JS::NonnullGCPtr cancel_value = verify_cast<JS::Promise>(*cancel_result->promise().ptr());
WebIDL::resolve_promise(realm, cancel_promise, cancel_value);
WebIDL::resolve_promise(realm, cancel_promise, cancel_result->promise());
}
// 4. Return cancelPromise.
@ -1246,8 +1241,7 @@ WebIDL::ExceptionOr<ReadableStreamPair> readable_byte_stream_tee(JS::Realm& real
auto cancel_result = readable_stream_cancel(stream, composite_reason);
// 3. Resolve cancelPromise with cancelResult.
JS::NonnullGCPtr cancel_value = verify_cast<JS::Promise>(*cancel_result->promise().ptr());
WebIDL::resolve_promise(realm, cancel_promise, cancel_value);
WebIDL::resolve_promise(realm, cancel_promise, cancel_result->promise());
}
// 4. Return cancelPromise.
@ -1442,7 +1436,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<ReadableStream>> readable_stream_from_itera
}),
{});
return WebIDL::create_resolved_promise(realm, react_result);
return react_result;
});
// 5. Let cancelAlgorithm be the following steps, given reason:
@ -1483,7 +1477,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<ReadableStream>> readable_stream_from_itera
}),
{});
return WebIDL::create_resolved_promise(realm, react_result);
return react_result;
});
// 6. Set stream to ! CreateReadableStream(startAlgorithm, pullAlgorithm, cancelAlgorithm, 0).
@ -4711,7 +4705,7 @@ void writable_stream_default_controller_write(WritableStreamDefaultController& c
}
// https://streams.spec.whatwg.org/#initialize-transform-stream
void initialize_transform_stream(TransformStream& stream, JS::NonnullGCPtr<JS::PromiseCapability> start_promise, double writable_high_water_mark, JS::NonnullGCPtr<SizeAlgorithm> writable_size_algorithm, double readable_high_water_mark, JS::NonnullGCPtr<SizeAlgorithm> readable_size_algorithm)
void initialize_transform_stream(TransformStream& stream, JS::NonnullGCPtr<WebIDL::Promise> start_promise, double writable_high_water_mark, JS::NonnullGCPtr<SizeAlgorithm> writable_size_algorithm, double readable_high_water_mark, JS::NonnullGCPtr<SizeAlgorithm> readable_size_algorithm)
{
auto& realm = stream.realm();
@ -4970,7 +4964,7 @@ JS::NonnullGCPtr<WebIDL::Promise> transform_stream_default_controller_perform_tr
return JS::throw_completion(reason);
}));
return WebIDL::create_resolved_promise(realm, react_result);
return react_result;
}
// https://streams.spec.whatwg.org/#transform-stream-default-sink-abort-algorithm
@ -5031,7 +5025,7 @@ JS::NonnullGCPtr<WebIDL::Promise> transform_stream_default_sink_abort_algorithm(
}));
// 8. Return controller.[[finishPromise]].
return JS::NonnullGCPtr { *controller->finish_promise() };
return *controller->finish_promise();
}
// https://streams.spec.whatwg.org/#transform-stream-default-sink-close-algorithm
@ -5075,7 +5069,7 @@ JS::NonnullGCPtr<WebIDL::Promise> transform_stream_default_sink_close_algorithm(
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, readable->stored_error().as_string().utf8_string() };
}));
return WebIDL::create_resolved_promise(realm, react_result);
return react_result;
}
// https://streams.spec.whatwg.org/#transform-stream-default-sink-write-algorithm
@ -5118,7 +5112,7 @@ JS::NonnullGCPtr<WebIDL::Promise> transform_stream_default_sink_write_algorithm(
}),
{});
return WebIDL::create_resolved_promise(realm, react_result);
return react_result;
}
// 4. Return ! TransformStreamDefaultControllerPerformTransform(controller, chunk).
@ -5196,7 +5190,7 @@ JS::NonnullGCPtr<WebIDL::Promise> transform_stream_default_source_cancel_algorit
}));
// 8. Return controller.[[finishPromise]].
return JS::NonnullGCPtr { *controller->finish_promise() };
return *controller->finish_promise();
}
// https://streams.spec.whatwg.org/#transform-stream-error

View file

@ -168,7 +168,7 @@ void writable_stream_default_controller_process_close(WritableStreamDefaultContr
void writable_stream_default_controller_process_write(WritableStreamDefaultController&, JS::Value chunk);
void writable_stream_default_controller_write(WritableStreamDefaultController&, JS::Value chunk, JS::Value chunk_size);
void initialize_transform_stream(TransformStream&, JS::NonnullGCPtr<JS::PromiseCapability> start_promise, double writable_high_water_mark, JS::NonnullGCPtr<SizeAlgorithm> writable_size_algorithm, double readable_high_water_mark, JS::NonnullGCPtr<SizeAlgorithm> readable_size_algorithm);
void initialize_transform_stream(TransformStream&, JS::NonnullGCPtr<WebIDL::Promise> start_promise, double writable_high_water_mark, JS::NonnullGCPtr<SizeAlgorithm> writable_size_algorithm, double readable_high_water_mark, JS::NonnullGCPtr<SizeAlgorithm> readable_size_algorithm);
void set_up_transform_stream_default_controller(TransformStream&, TransformStreamDefaultController&, JS::NonnullGCPtr<TransformAlgorithm>, JS::NonnullGCPtr<FlushAlgorithm>, JS::NonnullGCPtr<CancelAlgorithm>);
void set_up_transform_stream_default_controller_from_transformer(TransformStream&, JS::Value transformer, Transformer&);
void transform_stream_default_controller_clear_algorithms(TransformStreamDefaultController&);

View file

@ -90,18 +90,18 @@ bool ReadableStream::locked() const
}
// https://streams.spec.whatwg.org/#rs-cancel
JS::NonnullGCPtr<JS::Object> ReadableStream::cancel(JS::Value reason)
JS::NonnullGCPtr<WebIDL::Promise> ReadableStream::cancel(JS::Value reason)
{
auto& realm = this->realm();
// 1. If ! IsReadableStreamLocked(this) is true, return a promise rejected with a TypeError exception.
if (is_readable_stream_locked(*this)) {
auto exception = JS::TypeError::create(realm, "Cannot cancel a locked stream"sv);
return WebIDL::create_rejected_promise(realm, JS::Value { exception })->promise();
return WebIDL::create_rejected_promise(realm, exception);
}
// 2. Return ! ReadableStreamCancel(this, reason).
return readable_stream_cancel(*this, reason)->promise();
return readable_stream_cancel(*this, reason);
}
// https://streams.spec.whatwg.org/#rs-get-reader
@ -141,29 +141,26 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<ReadableStream>> ReadableStream::pipe_throu
return JS::NonnullGCPtr { *transform.readable };
}
JS::NonnullGCPtr<JS::Object> ReadableStream::pipe_to(WritableStream& destination, StreamPipeOptions const& options)
JS::NonnullGCPtr<WebIDL::Promise> ReadableStream::pipe_to(WritableStream& destination, StreamPipeOptions const& options)
{
auto& realm = this->realm();
auto& vm = realm.vm();
// 1. If ! IsReadableStreamLocked(this) is true, return a promise rejected with a TypeError exception.
if (is_readable_stream_locked(*this)) {
auto promise = WebIDL::create_promise(realm);
WebIDL::reject_promise(realm, promise, JS::TypeError::create(realm, "Failed to execute 'pipeTo' on 'ReadableStream': Cannot pipe a locked stream"sv));
return promise->promise();
return WebIDL::create_rejected_promise_from_exception(realm, vm.throw_completion<JS::TypeError>("Failed to execute 'pipeTo' on 'ReadableStream': Cannot pipe a locked stream"sv));
}
// 2. If ! IsWritableStreamLocked(destination) is true, return a promise rejected with a TypeError exception.
if (is_writable_stream_locked(destination)) {
auto promise = WebIDL::create_promise(realm);
WebIDL::reject_promise(realm, promise, JS::TypeError::create(realm, "Failed to execute 'pipeTo' on 'ReadableStream': Cannot pipe to a locked stream"sv));
return promise->promise();
return WebIDL::create_rejected_promise_from_exception(realm, vm.throw_completion<JS::TypeError>("Failed to execute 'pipeTo' on 'ReadableStream': Cannot pipe to a locked stream"sv));
}
// 3. Let signal be options["signal"] if it exists, or undefined otherwise.
auto signal = options.signal ? JS::Value(options.signal) : JS::js_undefined();
// 4. Return ! ReadableStreamPipeTo(this, destination, options["preventClose"], options["preventAbort"], options["preventCancel"], signal).
return readable_stream_pipe_to(*this, destination, options.prevent_close, options.prevent_abort, options.prevent_cancel, signal)->promise();
return readable_stream_pipe_to(*this, destination, options.prevent_close, options.prevent_abort, options.prevent_cancel, signal);
}
// https://streams.spec.whatwg.org/#readablestream-tee

View file

@ -75,10 +75,10 @@ public:
virtual ~ReadableStream() override;
bool locked() const;
JS::NonnullGCPtr<JS::Object> cancel(JS::Value reason);
JS::NonnullGCPtr<WebIDL::Promise> cancel(JS::Value reason);
WebIDL::ExceptionOr<ReadableStreamReader> get_reader(ReadableStreamGetReaderOptions const& = {});
WebIDL::ExceptionOr<JS::NonnullGCPtr<ReadableStream>> pipe_through(ReadableWritablePair transform, StreamPipeOptions const& = {});
JS::NonnullGCPtr<JS::Object> pipe_to(WritableStream& destination, StreamPipeOptions const& = {});
JS::NonnullGCPtr<WebIDL::Promise> pipe_to(WritableStream& destination, StreamPipeOptions const& = {});
WebIDL::ExceptionOr<ReadableStreamPair> tee();
void close();

View file

@ -107,7 +107,7 @@ private:
JS_DEFINE_ALLOCATOR(BYOBReaderReadIntoRequest);
// https://streams.spec.whatwg.org/#byob-reader-read
JS::NonnullGCPtr<JS::Promise> ReadableStreamBYOBReader::read(JS::Handle<WebIDL::ArrayBufferView>& view, ReadableStreamBYOBReaderReadOptions options)
JS::NonnullGCPtr<WebIDL::Promise> ReadableStreamBYOBReader::read(JS::Handle<WebIDL::ArrayBufferView>& view, ReadableStreamBYOBReaderReadOptions options)
{
auto& realm = this->realm();
@ -177,6 +177,6 @@ JS::NonnullGCPtr<JS::Promise> ReadableStreamBYOBReader::read(JS::Handle<WebIDL::
readable_stream_byob_reader_read(*this, *view, options.min, *read_into_request);
// 11. Return promise.
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise_capability->promise()) };
return promise_capability;
}
}

View file

@ -51,7 +51,7 @@ public:
virtual ~ReadableStreamBYOBReader() override = default;
JS::NonnullGCPtr<JS::Promise> read(JS::Handle<WebIDL::ArrayBufferView>&, ReadableStreamBYOBReaderReadOptions options = {});
JS::NonnullGCPtr<WebIDL::Promise> read(JS::Handle<WebIDL::ArrayBufferView>&, ReadableStreamBYOBReaderReadOptions options = {});
void release_lock();

View file

@ -162,7 +162,7 @@ private:
JS_DEFINE_ALLOCATOR(DefaultReaderReadRequest);
// https://streams.spec.whatwg.org/#default-reader-read
JS::NonnullGCPtr<JS::Promise> ReadableStreamDefaultReader::read()
JS::NonnullGCPtr<WebIDL::Promise> ReadableStreamDefaultReader::read()
{
auto& realm = this->realm();
@ -188,7 +188,7 @@ JS::NonnullGCPtr<JS::Promise> ReadableStreamDefaultReader::read()
readable_stream_default_reader_read(*this, read_request);
// 5. Return promise.
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise_capability->promise()) };
return promise_capability;
}
void ReadableStreamDefaultReader::read_a_chunk(Fetch::Infrastructure::IncrementalReadLoopReadRequest& read_request)

View file

@ -77,7 +77,7 @@ public:
virtual ~ReadableStreamDefaultReader() override = default;
JS::NonnullGCPtr<JS::Promise> read();
JS::NonnullGCPtr<WebIDL::Promise> read();
void read_a_chunk(Fetch::Infrastructure::IncrementalReadLoopReadRequest& read_request);
void read_all_bytes(JS::NonnullGCPtr<ReadLoopReadRequest::SuccessSteps>, JS::NonnullGCPtr<ReadLoopReadRequest::FailureSteps>);

View file

@ -14,14 +14,14 @@
namespace Web::Streams {
// https://streams.spec.whatwg.org/#generic-reader-closed
JS::GCPtr<JS::Promise> ReadableStreamGenericReaderMixin::closed()
JS::GCPtr<WebIDL::Promise> ReadableStreamGenericReaderMixin::closed()
{
// 1. Return this.[[closedPromise]].
return JS::GCPtr { verify_cast<JS::Promise>(*m_closed_promise->promise()) };
return m_closed_promise;
}
// https://streams.spec.whatwg.org/#generic-reader-cancel
JS::NonnullGCPtr<JS::Promise> ReadableStreamGenericReaderMixin::cancel(JS::Value reason)
JS::NonnullGCPtr<WebIDL::Promise> ReadableStreamGenericReaderMixin::cancel(JS::Value reason)
{
// 1. If this.[[stream]] is undefined, return a promise rejected with a TypeError exception.
if (!m_stream) {
@ -30,8 +30,7 @@ JS::NonnullGCPtr<JS::Promise> ReadableStreamGenericReaderMixin::cancel(JS::Value
}
// 2. Return ! ReadableStreamReaderGenericCancel(this, reason).
auto promise_capability = readable_stream_reader_generic_cancel(*this, reason);
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise_capability->promise().ptr()) };
return readable_stream_reader_generic_cancel(*this, reason);
}
ReadableStreamGenericReaderMixin::ReadableStreamGenericReaderMixin(JS::Realm& realm)

View file

@ -19,9 +19,9 @@ class ReadableStreamGenericReaderMixin {
public:
virtual ~ReadableStreamGenericReaderMixin() = default;
JS::GCPtr<JS::Promise> closed();
JS::GCPtr<WebIDL::Promise> closed();
JS::NonnullGCPtr<JS::Promise> cancel(JS::Value reason);
JS::NonnullGCPtr<WebIDL::Promise> cancel(JS::Value reason);
JS::GCPtr<ReadableStream> stream() const { return m_stream; }
void set_stream(JS::GCPtr<ReadableStream> stream) { m_stream = stream; }

View file

@ -58,39 +58,39 @@ bool WritableStream::locked() const
}
// https://streams.spec.whatwg.org/#ws-close
JS::GCPtr<JS::Object> WritableStream::close()
JS::GCPtr<WebIDL::Promise> WritableStream::close()
{
auto& realm = this->realm();
// 1. If ! IsWritableStreamLocked(this) is true, return a promise rejected with a TypeError exception.
if (is_writable_stream_locked(*this)) {
auto exception = JS::TypeError::create(realm, "Cannot close a locked stream"sv);
return WebIDL::create_rejected_promise(realm, exception)->promise();
return WebIDL::create_rejected_promise(realm, exception);
}
// 2. If ! WritableStreamCloseQueuedOrInFlight(this) is true, return a promise rejected with a TypeError exception.
if (writable_stream_close_queued_or_in_flight(*this)) {
auto exception = JS::TypeError::create(realm, "Cannot close a stream that is already closed or errored"sv);
return WebIDL::create_rejected_promise(realm, exception)->promise();
return WebIDL::create_rejected_promise(realm, exception);
}
// 3. Return ! WritableStreamClose(this).
return writable_stream_close(*this)->promise();
return writable_stream_close(*this);
}
// https://streams.spec.whatwg.org/#ws-abort
JS::GCPtr<JS::Object> WritableStream::abort(JS::Value reason)
JS::GCPtr<WebIDL::Promise> WritableStream::abort(JS::Value reason)
{
auto& realm = this->realm();
// 1. If ! IsWritableStreamLocked(this) is true, return a promise rejected with a TypeError exception.
if (is_writable_stream_locked(*this)) {
auto exception = JS::TypeError::create(realm, "Cannot abort a locked stream"sv);
return WebIDL::create_rejected_promise(realm, exception)->promise();
return WebIDL::create_rejected_promise(realm, exception);
}
// 2. Return ! WritableStreamAbort(this, reason).
return writable_stream_abort(*this, reason)->promise();
return writable_stream_abort(*this, reason);
}
// https://streams.spec.whatwg.org/#ws-get-writer

View file

@ -49,8 +49,8 @@ public:
virtual ~WritableStream() = default;
bool locked() const;
JS::GCPtr<JS::Object> abort(JS::Value reason);
JS::GCPtr<JS::Object> close();
JS::GCPtr<WebIDL::Promise> abort(JS::Value reason);
JS::GCPtr<WebIDL::Promise> close();
WebIDL::ExceptionOr<JS::NonnullGCPtr<WritableStreamDefaultWriter>> get_writer();
bool backpressure() const { return m_backpressure; }

View file

@ -27,10 +27,10 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<WritableStreamDefaultWriter>> WritableStrea
}
// https://streams.spec.whatwg.org/#default-writer-closed
JS::GCPtr<JS::Object> WritableStreamDefaultWriter::closed()
JS::GCPtr<WebIDL::Promise> WritableStreamDefaultWriter::closed()
{
// 1. Return this.[[closedPromise]].
return m_closed_promise->promise();
return m_closed_promise;
}
// https://streams.spec.whatwg.org/#default-writer-desired-size
@ -45,29 +45,29 @@ WebIDL::ExceptionOr<Optional<double>> WritableStreamDefaultWriter::desired_size(
}
// https://streams.spec.whatwg.org/#default-writer-ready
JS::GCPtr<JS::Object> WritableStreamDefaultWriter::ready()
JS::GCPtr<WebIDL::Promise> WritableStreamDefaultWriter::ready()
{
// 1. Return this.[[readyPromise]].
return m_ready_promise->promise();
return m_ready_promise;
}
// https://streams.spec.whatwg.org/#default-writer-abort
JS::GCPtr<JS::Object> WritableStreamDefaultWriter::abort(JS::Value reason)
JS::GCPtr<WebIDL::Promise> WritableStreamDefaultWriter::abort(JS::Value reason)
{
auto& realm = this->realm();
// 1. If this.[[stream]] is undefined, return a promise rejected with a TypeError exception.
if (!m_stream) {
auto exception = JS::TypeError::create(realm, "Cannot abort a writer that has no locked stream"sv);
return WebIDL::create_rejected_promise(realm, exception)->promise();
return WebIDL::create_rejected_promise(realm, exception);
}
// 2. Return ! WritableStreamDefaultWriterAbort(this, reason).
return writable_stream_default_writer_abort(*this, reason)->promise();
return writable_stream_default_writer_abort(*this, reason);
}
// https://streams.spec.whatwg.org/#default-writer-close
JS::GCPtr<JS::Object> WritableStreamDefaultWriter::close()
JS::GCPtr<WebIDL::Promise> WritableStreamDefaultWriter::close()
{
auto& realm = this->realm();
@ -76,17 +76,17 @@ JS::GCPtr<JS::Object> WritableStreamDefaultWriter::close()
// 2. If stream is undefined, return a promise rejected with a TypeError exception.
if (!m_stream) {
auto exception = JS::TypeError::create(realm, "Cannot close a writer that has no locked stream"sv);
return WebIDL::create_rejected_promise(realm, exception)->promise();
return WebIDL::create_rejected_promise(realm, exception);
}
// 3. If ! WritableStreamCloseQueuedOrInFlight(stream) is true, return a promise rejected with a TypeError exception.
if (writable_stream_close_queued_or_in_flight(*m_stream)) {
auto exception = JS::TypeError::create(realm, "Cannot close a stream that is already closed or errored"sv);
return WebIDL::create_rejected_promise(realm, exception)->promise();
return WebIDL::create_rejected_promise(realm, exception);
}
// 4. Return ! WritableStreamDefaultWriterClose(this).
return writable_stream_default_writer_close(*this)->promise();
return writable_stream_default_writer_close(*this);
}
// https://streams.spec.whatwg.org/#default-writer-release-lock
@ -106,18 +106,18 @@ void WritableStreamDefaultWriter::release_lock()
}
// https://streams.spec.whatwg.org/#default-writer-write
JS::GCPtr<JS::Object> WritableStreamDefaultWriter::write(JS::Value chunk)
JS::GCPtr<WebIDL::Promise> WritableStreamDefaultWriter::write(JS::Value chunk)
{
auto& realm = this->realm();
// 1. If this.[[stream]] is undefined, return a promise rejected with a TypeError exception.
if (!m_stream) {
auto exception = JS::TypeError::create(realm, "Cannot write to a writer that has no locked stream"sv);
return WebIDL::create_rejected_promise(realm, exception)->promise();
return WebIDL::create_rejected_promise(realm, exception);
}
// 2. Return ! WritableStreamDefaultWriterWrite(this, chunk).
return writable_stream_default_writer_write(*this, chunk)->promise();
return writable_stream_default_writer_write(*this, chunk);
}
WritableStreamDefaultWriter::WritableStreamDefaultWriter(JS::Realm& realm)

View file

@ -25,13 +25,13 @@ public:
virtual ~WritableStreamDefaultWriter() override = default;
JS::GCPtr<JS::Object> closed();
JS::GCPtr<WebIDL::Promise> closed();
WebIDL::ExceptionOr<Optional<double>> desired_size() const;
JS::GCPtr<JS::Object> ready();
JS::GCPtr<JS::Object> abort(JS::Value reason);
JS::GCPtr<JS::Object> close();
JS::GCPtr<WebIDL::Promise> ready();
JS::GCPtr<WebIDL::Promise> abort(JS::Value reason);
JS::GCPtr<WebIDL::Promise> close();
void release_lock();
JS::GCPtr<JS::Object> write(JS::Value chunk);
JS::GCPtr<WebIDL::Promise> write(JS::Value chunk);
JS::GCPtr<WebIDL::Promise> closed_promise() { return m_closed_promise; }
void set_closed_promise(JS::GCPtr<WebIDL::Promise> value) { m_closed_promise = value; }

View file

@ -19,12 +19,14 @@
#include <LibJS/Runtime/TypedArray.h>
#include <LibJS/Runtime/VM.h>
#include <LibWasm/AbstractMachine/Validator.h>
#include <LibWeb/Platform/EventLoopPlugin.h>
#include <LibWeb/WebAssembly/Instance.h>
#include <LibWeb/WebAssembly/Memory.h>
#include <LibWeb/WebAssembly/Module.h>
#include <LibWeb/WebAssembly/Table.h>
#include <LibWeb/WebAssembly/WebAssembly.h>
#include <LibWeb/WebIDL/Buffers.h>
#include <LibWeb/WebIDL/Promise.h>
namespace Web::WebAssembly {
@ -80,26 +82,25 @@ bool validate(JS::VM& vm, JS::Handle<WebIDL::BufferSource>& bytes)
}
// https://webassembly.github.io/spec/js-api/#dom-webassembly-compile
WebIDL::ExceptionOr<JS::Value> compile(JS::VM& vm, JS::Handle<WebIDL::BufferSource>& bytes)
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> compile(JS::VM& vm, JS::Handle<WebIDL::BufferSource>& bytes)
{
auto& realm = *vm.current_realm();
// FIXME: This shouldn't block!
auto compiled_module_or_error = Detail::parse_module(vm, bytes->raw_object());
auto promise = JS::Promise::create(realm);
auto promise = WebIDL::create_promise(realm);
if (compiled_module_or_error.is_error()) {
promise->reject(*compiled_module_or_error.release_error().value());
WebIDL::reject_promise(realm, promise, compiled_module_or_error.error_value());
} else {
auto module_object = vm.heap().allocate<Module>(realm, realm, compiled_module_or_error.release_value());
promise->fulfill(module_object);
WebIDL::resolve_promise(realm, promise, module_object);
}
return promise;
}
// https://webassembly.github.io/spec/js-api/#dom-webassembly-instantiate
WebIDL::ExceptionOr<JS::Value> instantiate(JS::VM& vm, JS::Handle<WebIDL::BufferSource>& bytes, Optional<JS::Handle<JS::Object>>& import_object)
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> instantiate(JS::VM& vm, JS::Handle<WebIDL::BufferSource>& bytes, Optional<JS::Handle<JS::Object>>& import_object)
{
// FIXME: Implement the importObject parameter.
(void)import_object;
@ -108,10 +109,10 @@ WebIDL::ExceptionOr<JS::Value> instantiate(JS::VM& vm, JS::Handle<WebIDL::Buffer
// FIXME: This shouldn't block!
auto compiled_module_or_error = Detail::parse_module(vm, bytes->raw_object());
auto promise = JS::Promise::create(realm);
auto promise = WebIDL::create_promise(realm);
if (compiled_module_or_error.is_error()) {
promise->reject(*compiled_module_or_error.release_error().value());
WebIDL::reject_promise(realm, promise, compiled_module_or_error.error_value());
return promise;
}
@ -119,7 +120,7 @@ WebIDL::ExceptionOr<JS::Value> instantiate(JS::VM& vm, JS::Handle<WebIDL::Buffer
auto result = Detail::instantiate_module(vm, compiled_module->module);
if (result.is_error()) {
promise->reject(*result.release_error().value());
WebIDL::reject_promise(realm, promise, result.error_value());
} else {
auto module_object = vm.heap().allocate<Module>(realm, realm, move(compiled_module));
auto instance_object = vm.heap().allocate<Instance>(realm, realm, result.release_value());
@ -127,29 +128,30 @@ WebIDL::ExceptionOr<JS::Value> instantiate(JS::VM& vm, JS::Handle<WebIDL::Buffer
auto object = JS::Object::create(realm, nullptr);
object->define_direct_property("module", module_object, JS::default_attributes);
object->define_direct_property("instance", instance_object, JS::default_attributes);
promise->fulfill(object);
WebIDL::resolve_promise(realm, promise, object);
}
return promise;
}
// https://webassembly.github.io/spec/js-api/#dom-webassembly-instantiate-moduleobject-importobject
WebIDL::ExceptionOr<JS::Value> instantiate(JS::VM& vm, Module const& module_object, Optional<JS::Handle<JS::Object>>& import_object)
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> instantiate(JS::VM& vm, Module const& module_object, Optional<JS::Handle<JS::Object>>& import_object)
{
// FIXME: Implement the importObject parameter.
(void)import_object;
auto& realm = *vm.current_realm();
auto promise = JS::Promise::create(realm);
auto promise = WebIDL::create_promise(realm);
// FIXME: This shouldn't block!
auto const& compiled_module = module_object.compiled_module();
auto result = Detail::instantiate_module(vm, compiled_module->module);
if (result.is_error()) {
promise->reject(*result.release_error().value());
WebIDL::reject_promise(realm, promise, result.error_value());
} else {
auto instance_object = vm.heap().allocate<Instance>(realm, realm, result.release_value());
promise->fulfill(instance_object);
WebIDL::resolve_promise(realm, promise, instance_object);
}
return promise;

View file

@ -22,10 +22,10 @@ void visit_edges(JS::Object&, JS::Cell::Visitor&);
void finalize(JS::Object&);
bool validate(JS::VM&, JS::Handle<WebIDL::BufferSource>& bytes);
WebIDL::ExceptionOr<JS::Value> compile(JS::VM&, JS::Handle<WebIDL::BufferSource>& bytes);
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> compile(JS::VM&, JS::Handle<WebIDL::BufferSource>& bytes);
WebIDL::ExceptionOr<JS::Value> instantiate(JS::VM&, JS::Handle<WebIDL::BufferSource>& bytes, Optional<JS::Handle<JS::Object>>& import_object);
WebIDL::ExceptionOr<JS::Value> instantiate(JS::VM&, Module const& module_object, Optional<JS::Handle<JS::Object>>& import_object);
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> instantiate(JS::VM&, JS::Handle<WebIDL::BufferSource>& bytes, Optional<JS::Handle<JS::Object>>& import_object);
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> instantiate(JS::VM&, Module const& module_object, Optional<JS::Handle<JS::Object>>& import_object);
namespace Detail {
struct CompiledWebAssemblyModule : public RefCounted<CompiledWebAssemblyModule> {

View file

@ -103,7 +103,7 @@ AudioTimestamp AudioContext::get_output_timestamp()
}
// https://www.w3.org/TR/webaudio/#dom-audiocontext-resume
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> AudioContext::resume()
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> AudioContext::resume()
{
auto& realm = this->realm();
@ -118,7 +118,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> AudioContext::resume()
// 3. If the [[control thread state]] on the AudioContext is closed reject the promise with InvalidStateError, abort these steps, returning promise.
if (state() == Bindings::AudioContextState::Closed) {
WebIDL::reject_promise(realm, promise, WebIDL::InvalidStateError::create(realm, "Audio context is already closed."_string));
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise()) };
return promise;
}
// 4. Set [[suspended by user]] to true.
@ -187,11 +187,11 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> AudioContext::resume()
}));
// 8. Return promise.
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise()) };
return promise;
}
// https://www.w3.org/TR/webaudio/#dom-audiocontext-suspend
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> AudioContext::suspend()
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> AudioContext::suspend()
{
auto& realm = this->realm();
@ -206,7 +206,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> AudioContext::suspend()
// 3. If the [[control thread state]] on the AudioContext is closed reject the promise with InvalidStateError, abort these steps, returning promise.
if (state() == Bindings::AudioContextState::Closed) {
WebIDL::reject_promise(realm, promise, WebIDL::InvalidStateError::create(realm, "Audio context is already closed."_string));
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise()) };
return promise;
}
// 4. Append promise to [[pending promises]].
@ -244,11 +244,11 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> AudioContext::suspend()
}));
// 8. Return promise.
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise()) };
return promise;
}
// https://www.w3.org/TR/webaudio/#dom-audiocontext-close
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> AudioContext::close()
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> AudioContext::close()
{
auto& realm = this->realm();
@ -263,7 +263,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> AudioContext::close()
// 3. If the [[control thread state]] flag on the AudioContext is closed reject the promise with InvalidStateError, abort these steps, returning promise.
if (state() == Bindings::AudioContextState::Closed) {
WebIDL::reject_promise(realm, promise, WebIDL::InvalidStateError::create(realm, "Audio context is already closed."_string));
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise()) };
return promise;
}
// 4. Set the [[control thread state]] flag on the AudioContext to closed.
@ -296,7 +296,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> AudioContext::close()
}));
// 6. Return promise
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise()) };
return promise;
}
// FIXME: Actually implement the rendering thread

View file

@ -35,9 +35,9 @@ public:
double base_latency() const { return m_base_latency; }
double output_latency() const { return m_output_latency; }
AudioTimestamp get_output_timestamp();
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> resume();
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> suspend();
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> close();
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> resume();
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> suspend();
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> close();
private:
explicit AudioContext(JS::Realm&, AudioContextOptions const& context_options);

View file

@ -128,7 +128,7 @@ void BaseAudioContext::queue_a_media_element_task(JS::NonnullGCPtr<JS::HeapFunct
}
// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-decodeaudiodata
JS::NonnullGCPtr<JS::Promise> BaseAudioContext::decode_audio_data(JS::Handle<WebIDL::BufferSource> audio_data, JS::GCPtr<WebIDL::CallbackType> success_callback, JS::GCPtr<WebIDL::CallbackType> error_callback)
JS::NonnullGCPtr<WebIDL::Promise> BaseAudioContext::decode_audio_data(JS::Handle<WebIDL::BufferSource> audio_data, JS::GCPtr<WebIDL::CallbackType> success_callback, JS::GCPtr<WebIDL::CallbackType> error_callback)
{
auto& realm = this->realm();
@ -178,7 +178,7 @@ JS::NonnullGCPtr<JS::Promise> BaseAudioContext::decode_audio_data(JS::Handle<Web
}
// 5. Return promise.
return verify_cast<JS::Promise>(*promise->promise());
return promise;
}
// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-decodeaudiodata

View file

@ -61,7 +61,7 @@ public:
WebIDL::ExceptionOr<JS::NonnullGCPtr<DynamicsCompressorNode>> create_dynamics_compressor();
JS::NonnullGCPtr<GainNode> create_gain();
JS::NonnullGCPtr<JS::Promise> decode_audio_data(JS::Handle<WebIDL::BufferSource>, JS::GCPtr<WebIDL::CallbackType>, JS::GCPtr<WebIDL::CallbackType>);
JS::NonnullGCPtr<WebIDL::Promise> decode_audio_data(JS::Handle<WebIDL::BufferSource>, JS::GCPtr<WebIDL::CallbackType>, JS::GCPtr<WebIDL::CallbackType>);
protected:
explicit BaseAudioContext(JS::Realm&, float m_sample_rate = 0);

View file

@ -32,17 +32,17 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<OfflineAudioContext>> OfflineAudioContext::
OfflineAudioContext::~OfflineAudioContext() = default;
// https://webaudio.github.io/web-audio-api/#dom-offlineaudiocontext-startrendering
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> OfflineAudioContext::start_rendering()
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> OfflineAudioContext::start_rendering()
{
return WebIDL::NotSupportedError::create(realm(), "FIXME: Implement OfflineAudioContext::start_rendering"_string);
}
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> OfflineAudioContext::resume()
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> OfflineAudioContext::resume()
{
return WebIDL::NotSupportedError::create(realm(), "FIXME: Implement OfflineAudioContext::resume"_string);
}
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> OfflineAudioContext::suspend(double suspend_time)
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> OfflineAudioContext::suspend(double suspend_time)
{
(void)suspend_time;
return WebIDL::NotSupportedError::create(realm(), "FIXME: Implement OfflineAudioContext::suspend"_string);

View file

@ -32,9 +32,9 @@ public:
virtual ~OfflineAudioContext() override;
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> start_rendering();
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> resume();
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> suspend(double suspend_time);
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> start_rendering();
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> resume();
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> suspend(double suspend_time);
WebIDL::UnsignedLong length() const;

View file

@ -376,24 +376,24 @@ void execute_script(HTML::BrowsingContext const& browsing_context, ByteString bo
HTML::TemporaryExecutionContext execution_context { document->relevant_settings_object(), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes };
// 7. Let promise be a new Promise.
auto promise_capability = WebIDL::create_promise(realm);
JS::NonnullGCPtr promise { verify_cast<JS::Promise>(*promise_capability->promise()) };
auto promise = WebIDL::create_promise(realm);
// 8. Run the following substeps in parallel:
Platform::EventLoopPlugin::the().deferred_invoke([&realm, &browsing_context, promise_capability, document, promise, body = move(body), arguments = move(arguments)]() mutable {
Platform::EventLoopPlugin::the().deferred_invoke([&realm, &browsing_context, promise, document, body = move(body), arguments = move(arguments)]() mutable {
HTML::TemporaryExecutionContext execution_context { document->relevant_settings_object() };
// 1. Let scriptPromise be the result of promise-calling execute a function body, with arguments body and arguments.
auto script_result = execute_a_function_body(browsing_context, body, move(arguments));
// FIXME: This isn't right, we should be reacting to this using WebIDL::react_to_promise()
// 2. Upon fulfillment of scriptPromise with value v, resolve promise with value v.
if (script_result.has_value()) {
WebIDL::resolve_promise(realm, promise_capability, script_result.release_value());
WebIDL::resolve_promise(realm, promise, script_result.release_value());
}
// 3. Upon rejection of scriptPromise with value r, reject promise with value r.
if (script_result.is_throw_completion()) {
promise->reject(*script_result.throw_completion().value());
WebIDL::reject_promise(realm, promise, *script_result.throw_completion().value());
}
});
@ -403,7 +403,9 @@ void execute_script(HTML::BrowsingContext const& browsing_context, ByteString bo
return JS::js_undefined();
timer->stop();
auto json_value_or_error = json_clone(realm, browsing_context, promise->result());
auto promise_promise = JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise()) };
auto json_value_or_error = json_clone(realm, browsing_context, promise_promise->result());
if (json_value_or_error.is_error()) {
auto error_object = JsonObject {};
error_object.set("name", "Error");
@ -416,19 +418,19 @@ void execute_script(HTML::BrowsingContext const& browsing_context, ByteString bo
// NOTE: This is handled by the HeapTimer.
// 11. If promise is fulfilled with value v, let result be JSON clone with session and v, and return success with data result.
else if (promise->state() == JS::Promise::State::Fulfilled) {
else if (promise_promise->state() == JS::Promise::State::Fulfilled) {
on_complete->function()({ ExecuteScriptResultType::PromiseResolved, json_value_or_error.release_value() });
}
// 12. If promise is rejected with reason r, let result be JSON clone with session and r, and return error with error code javascript error and data result.
else if (promise->state() == JS::Promise::State::Rejected) {
else if (promise_promise->state() == JS::Promise::State::Rejected) {
on_complete->function()({ ExecuteScriptResultType::PromiseRejected, json_value_or_error.release_value() });
}
return JS::js_undefined();
});
WebIDL::react_to_promise(promise_capability, reaction_steps, reaction_steps);
WebIDL::react_to_promise(promise, reaction_steps, reaction_steps);
}
void execute_async_script(HTML::BrowsingContext const& browsing_context, ByteString body, JS::MarkedVector<JS::Value> arguments, Optional<u64> const& timeout_ms, JS::NonnullGCPtr<OnScriptComplete> on_complete)

View file

@ -93,7 +93,7 @@ void reject_promise(JS::Realm& realm, Promise const& promise, JS::Value reason)
}
// https://webidl.spec.whatwg.org/#dfn-perform-steps-once-promise-is-settled
JS::NonnullGCPtr<JS::Promise> react_to_promise(Promise const& promise, JS::GCPtr<ReactionSteps> on_fulfilled_callback, JS::GCPtr<ReactionSteps> on_rejected_callback)
JS::NonnullGCPtr<Promise> react_to_promise(Promise const& promise, JS::GCPtr<ReactionSteps> on_fulfilled_callback, JS::GCPtr<ReactionSteps> on_rejected_callback)
{
auto& realm = promise.promise()->shape().realm();
auto& vm = realm.vm();
@ -140,13 +140,17 @@ JS::NonnullGCPtr<JS::Promise> react_to_promise(Promise const& promise, JS::GCPtr
auto new_capability = MUST(JS::new_promise_capability(vm, constructor));
// 7. Return PerformPromiseThen(promise.[[Promise]], onFulfilled, onRejected, newCapability).
// FIXME: https://github.com/whatwg/webidl/issues/1443
// Returning newCapability instead of newCapability.[[Promise].
auto promise_object = verify_cast<JS::Promise>(promise.promise().ptr());
auto value = promise_object->perform_then(on_fulfilled, on_rejected, new_capability);
return verify_cast<JS::Promise>(value.as_object());
VERIFY(value == new_capability->promise());
return new_capability;
}
// https://webidl.spec.whatwg.org/#upon-fulfillment
JS::NonnullGCPtr<JS::Promise> upon_fulfillment(Promise const& promise, JS::NonnullGCPtr<ReactionSteps> steps)
JS::NonnullGCPtr<Promise> upon_fulfillment(Promise const& promise, JS::NonnullGCPtr<ReactionSteps> steps)
{
// 1. Return the result of reacting to promise:
return react_to_promise(promise,
@ -157,7 +161,7 @@ JS::NonnullGCPtr<JS::Promise> upon_fulfillment(Promise const& promise, JS::Nonnu
}
// https://webidl.spec.whatwg.org/#upon-rejection
JS::NonnullGCPtr<JS::Promise> upon_rejection(Promise const& promise, JS::NonnullGCPtr<ReactionSteps> steps)
JS::NonnullGCPtr<Promise> upon_rejection(Promise const& promise, JS::NonnullGCPtr<ReactionSteps> steps)
{
// 1. Return the result of reacting to promise:
return react_to_promise(promise, {},
@ -287,11 +291,10 @@ void wait_for_all(JS::Realm& realm, Vector<JS::NonnullGCPtr<Promise>> const& pro
}
}
JS::NonnullGCPtr<JS::Promise> create_rejected_promise_from_exception(JS::Realm& realm, Exception exception)
JS::NonnullGCPtr<Promise> create_rejected_promise_from_exception(JS::Realm& realm, Exception exception)
{
auto throw_completion = Bindings::dom_exception_to_throw_completion(realm.vm(), move(exception));
auto promise_capability = WebIDL::create_rejected_promise(realm, *throw_completion.value());
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise_capability->promise().ptr()) };
return WebIDL::create_rejected_promise(realm, *throw_completion.value());
}
}

View file

@ -27,13 +27,13 @@ JS::NonnullGCPtr<Promise> create_resolved_promise(JS::Realm&, JS::Value);
JS::NonnullGCPtr<Promise> create_rejected_promise(JS::Realm&, JS::Value);
void resolve_promise(JS::Realm&, Promise const&, JS::Value = JS::js_undefined());
void reject_promise(JS::Realm&, Promise const&, JS::Value);
JS::NonnullGCPtr<JS::Promise> react_to_promise(Promise const&, JS::GCPtr<ReactionSteps> on_fulfilled_callback, JS::GCPtr<ReactionSteps> on_rejected_callback);
JS::NonnullGCPtr<JS::Promise> upon_fulfillment(Promise const&, JS::NonnullGCPtr<ReactionSteps>);
JS::NonnullGCPtr<JS::Promise> upon_rejection(Promise const&, JS::NonnullGCPtr<ReactionSteps>);
JS::NonnullGCPtr<Promise> react_to_promise(Promise const&, JS::GCPtr<ReactionSteps> on_fulfilled_callback, JS::GCPtr<ReactionSteps> on_rejected_callback);
JS::NonnullGCPtr<Promise> upon_fulfillment(Promise const&, JS::NonnullGCPtr<ReactionSteps>);
JS::NonnullGCPtr<Promise> upon_rejection(Promise const&, JS::NonnullGCPtr<ReactionSteps>);
void mark_promise_as_handled(Promise const&);
void wait_for_all(JS::Realm&, Vector<JS::NonnullGCPtr<Promise>> const& promises, Function<void(Vector<JS::Value> const&)> success_steps, Function<void(JS::Value)> failure_steps);
// Non-spec, convenience method.
JS::NonnullGCPtr<JS::Promise> create_rejected_promise_from_exception(JS::Realm&, Exception);
JS::NonnullGCPtr<Promise> create_rejected_promise_from_exception(JS::Realm&, Exception);
}