6#include <Ultralight/CAPI/CAPI_JSAPI.h>
7#include <Ultralight/CAPI/CAPI_JSValue.h>
8#include <Ultralight/CAPI/CAPI_String.h>
9#include <Ultralight/detail/Expected.h>
10#include <Ultralight/js/detail/Swallow.h>
29class ExceptionDetails {
31 explicit ExceptionDetails(ULJSValue exception) {
32 if (exception && ulJSValueIsAlive(exception))
33 ulJSValueGetErrorDetails(exception, &raw_);
35 ~ExceptionDetails() { ulJSErrorDetailsRelease(&raw_); }
36 ExceptionDetails(
const ExceptionDetails&) =
delete;
37 ExceptionDetails& operator=(
const ExceptionDetails&) =
delete;
39 const ULJSErrorDetails& raw()
const {
return raw_; }
41 static std::string
Text(ULString s) {
42 return s ? std::string(ulStringGetData(s), ulStringGetLength(s)) : std::string();
46 ULJSErrorDetails raw_ {};
132 Error error(Kind::kException);
176 : kind_(other.kind_), type_(other.type_), exception_(other.exception_),
177 message_(std::move(other.message_)), code_(std::move(other.code_)),
178 observed_(other.observed_) {
179 other.exception_ =
nullptr;
186 if (
this != &other) {
190 exception_ = other.exception_;
191 message_ = std::move(other.message_);
192 code_ = std::move(other.code_);
193 observed_ = other.observed_;
194 other.exception_ =
nullptr;
203 : kind_(other.kind_), type_(other.type_),
204 exception_(other.exception_ ? ulCreateJSValueRef(other.exception_) : nullptr),
205 message_(other.message_), code_(other.code_) {
206 other.observed_ =
true;
214 *
this =
Error(other);
235 code_ = std::move(
code);
236 return std::move(*
this);
244 return kind_ == Kind::kException;
252 return kind_ == Kind::kPageGone;
260 return kind_ == Kind::kEmpty;
285 if (kind_ != Kind::kException)
287 return static_cast<ErrorType>(detail::ExceptionDetails(exception_).raw().type);
301 detail::ExceptionDetails details(exception_);
302 return detail::ExceptionDetails::Text(details.raw().stack);
316 detail::ExceptionDetails details(exception_);
317 return detail::ExceptionDetails::Text(details.raw().source_url);
331 return detail::ExceptionDetails(exception_).raw().line;
345 return detail::ExceptionDetails(exception_).raw().column;
359 if (kind_ == Kind::kException && exception_ && ulJSValueIsAlive(exception_)) {
360 detail::SwallowedException swallow;
361 ULJSValue prop = ulJSObjectGetProperty(exception_,
"code", swallow.out());
365 bool ok = ulJSValueGetType(prop) == kULJSType_String
366 && ulJSValueGetUTF8(prop, buffer,
sizeof(buffer), &length, swallow.out());
367 ulDestroyJSValue(prop);
369 return std::string(buffer, length);
390 if (kind_ == Kind::kException && exception_ && ulJSValueIsAlive(exception_))
391 return ulCreateJSValueRef(exception_);
392 static_assert(
static_cast<unsigned>(
ErrorType::Error) == kULJSErrorType_Error
395 == kULJSErrorType_RangeError
397 == kULJSErrorType_SyntaxError
399 == kULJSErrorType_ReferenceError,
400 "js::ErrorType must mirror ULJSErrorType");
401 ULJSValue error = ulCreateJSError(ctx,
static_cast<ULJSErrorType
>(type_),
403 if (error && !code_.empty()) {
404 detail::SwallowedException swallow;
405 ULJSValue code_value = ulCreateJSValueStringUTF8(ctx, code_.data(), code_.size());
406 ulJSObjectSetProperty(error,
"code", code_value, kULJSPropertyAttributes_None,
408 ulDestroyJSValue(code_value);
421 if (kind_ == Kind::kException) {
422 detail::SwallowedException swallow;
423 if (ULString s = ulJSValueToString(exception_, swallow.out())) {
424 std::string result(ulStringGetData(s), ulStringGetLength(s));
428 return "A JavaScript exception was thrown.";
430 if (kind_ == Kind::kPageGone)
431 return "The page behind this handle is gone (it navigated away, its frame was removed, or "
432 "its View was destroyed).";
433 if (kind_ == Kind::kEmpty)
434 return "The handle is empty (it was never assigned, was moved from, or came from a read "
440 friend struct detail::ErrorAccess;
442 enum class Kind { kNative, kException, kPageGone, kEmpty };
444 explicit Error(Kind kind) : kind_(kind) {}
446 : kind_(Kind::kNative), type_(
type), message_(
std::move(
message)) {}
448 void ReleaseException() {
449 if (exception_ && !observed_)
450 ulJSValueReportUnobservedException(exception_);
451 ulDestroyJSValue(exception_);
452 exception_ =
nullptr;
455 Kind kind_ = Kind::kNative;
457 ULJSValue exception_ =
nullptr;
458 std::string message_;
461 mutable bool observed_ =
false;
473inline ultralight::detail::Unexpected<Error> EmptyHandleError() {
474 return ultralight::detail::Unexpected<Error>(ErrorAccess::Empty());
479inline void LogNativeException(
const char* where,
const char* what) {
480 std::string log = std::string(
"C++ exception in ") + (where ? where :
"native code") +
": "
481 + (what ? what :
"unknown exception") +
". The library caught it and continued.";
482 ulJSAPIEmitDiagnostic(
nullptr, log.c_str());
488inline Error NativeExceptionError(
const char* path,
const char* what) {
489 LogNativeException(path, what);
490 std::string prefix = path ? std::string(path) +
": " : std::string();
500using ultralight::detail::Unexpected;
508template <
typename T,
typename E = Error>
509using Expected = ultralight::detail::Expected<T, E>;
538 requires std::is_default_constructible_v<T>
540 return std::move(result).value_or(T());
struct C_JSContext * ULJSContext
Opaque handle to a JavaScript execution context (one page's script world in one View).
Definition View.h:25
An error from a JavaScript operation.
Definition Error.h:115
static Error AdoptException(ULJSValue exception)
Create an error from a JavaScript exception, taking ownership of the handle.
Definition Error.h:131
ULJSValue ToJS(ULJSContext ctx) const
Convert this error to a JavaScript value.
Definition Error.h:388
Error(const Error &other)
Copy constructor (takes its own reference to the exception, if any).
Definition Error.h:202
unsigned line() const
Get the 1-based line where a JavaScript exception was created.
Definition Error.h:329
std::string stack() const
Get the stack trace of a JavaScript exception.
Definition Error.h:299
Error(Error &&other) noexcept
Move constructor (other no longer holds the exception).
Definition Error.h:175
static Error TypeError(std::string message)
Create a native TypeError.
Definition Error.h:144
Error & operator=(const Error &other)
Copy assignment (takes its own reference to the exception, if any).
Definition Error.h:212
static Error PageGone()
Create a page-gone error (is_page_gone() returns true).
Definition Error.h:122
bool is_empty() const
Whether or not this error means the handle holds nothing (see the class notes).
Definition Error.h:258
std::string code() const
Get the error's code (an empty string if it has none).
Definition Error.h:357
ErrorType type() const
Get the error's type.
Definition Error.h:283
~Error()
Destructor (logs the exception first if nothing read it; see the class notes).
Definition Error.h:221
std::string message() const
Get a readable description of the error.
Definition Error.h:419
static Error Make(ErrorType type, std::string message)
Create a native error of any type.
Definition Error.h:168
ULJSValue exception() const
Get the JavaScript exception (NULL if is_exception() is false).
Definition Error.h:268
unsigned column() const
Get the 1-based column where a JavaScript exception was created.
Definition Error.h:343
bool is_page_gone() const
Whether or not this error means the handle's page is gone.
Definition Error.h:250
Error WithCode(std::string code) &&
Add a code that page script gets as the error's code property when it's thrown.
Definition Error.h:234
Error & operator=(Error &&other) noexcept
Move assignment (other no longer holds the exception).
Definition Error.h:185
bool is_exception() const
Whether or not this error holds a JavaScript exception.
Definition Error.h:242
static Error RangeError(std::string message)
Create a native RangeError.
Definition Error.h:155
std::string source_url() const
Get the URL of the script that created a JavaScript exception.
Definition Error.h:314
Definition StringSTL.h:166
@ Empty
No number (an Empty StyleValue; writing it removes the property).
Definition StyleValue.h:33
@ Text
A text node.
Definition Node.h:70
Type-checked JavaScript bridge between C++ and web pages.
Definition JSInterop.h:141
ultralight::detail::Expected< T, E > Expected
A value of type T or an error of type E (like std::expected).
Definition Error.h:509
T OrEmpty(Result< T > result)
Get a Result's value, or a default-constructed T if it holds an error.
Definition Error.h:539
ErrorType
The type of a JavaScript error, matching the standard error constructors.
Definition Error.h:54
@ TypeError
Definition Error.h:56
@ RangeError
Definition Error.h:57
@ Error
A plain Error, or an error type with no dedicated constant.
Definition Error.h:55
@ SyntaxError
Definition Error.h:58
@ ReferenceError
Definition Error.h:59
Expected< T, Error > Result
The result of a JavaScript operation that can fail: a T or a js::Error.
Definition Error.h:520
Root namespace for every public Ultralight type, function, and enumeration.
@ Error
Error icon.
Definition Dialogs.h:57