diff --git a/Cargo.lock b/Cargo.lock index daeb63dd7..73735e41f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -635,6 +635,7 @@ dependencies = [ "pretty_assertions", "prettyplease", "testing_macros", + "thiserror 2.0.6", "tokio", "url", ] diff --git a/core/00_infra.js b/core/00_infra.js index 39e7a3c66..253ea1dde 100644 --- a/core/00_infra.js +++ b/core/00_infra.js @@ -102,10 +102,7 @@ for (const property of new SafeArrayIterator(additionalProperties)) { const key = property[0]; if (!(key in error)) { - ObjectDefineProperty(error, key, { - value: property[1], - writable: false, - }); + error[key] = property[1]; } } } diff --git a/testing/Cargo.toml b/testing/Cargo.toml index 1b415b2b9..b9cbf6520 100644 --- a/testing/Cargo.toml +++ b/testing/Cargo.toml @@ -20,6 +20,7 @@ deno_core.workspace = true deno_core.features = ["unsafe_use_unprotected_platform", "snapshot_flags_eager_parse"] deno_error.workspace = true futures.workspace = true +thiserror.workspace = true tokio.workspace = true url.workspace = true diff --git a/testing/checkin/runner/extensions.rs b/testing/checkin/runner/extensions.rs index ad51fab8b..3bad7976f 100644 --- a/testing/checkin/runner/extensions.rs +++ b/testing/checkin/runner/extensions.rs @@ -39,6 +39,7 @@ deno_core::extension!( ops_error::op_async_throw_error_lazy, ops_error::op_async_throw_error_deferred, ops_error::op_error_custom_sync, + ops_error::op_error_custom_with_code_sync, ops_buffer::op_v8slice_store, ops_buffer::op_v8slice_clone, ops_worker::op_worker_spawn, diff --git a/testing/checkin/runner/ops_error.rs b/testing/checkin/runner/ops_error.rs index 66d57fbcf..3fee67903 100644 --- a/testing/checkin/runner/ops_error.rs +++ b/testing/checkin/runner/ops_error.rs @@ -24,3 +24,20 @@ pub fn op_error_custom_sync( ) -> Result<(), JsErrorBox> { Err(JsErrorBox::new("BadResource", message)) } + +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(type)] +#[error("{message}")] +struct MyError { + message: String, + #[property] + code: u32, +} + +#[op2(fast)] +pub fn op_error_custom_with_code_sync( + #[string] message: String, + code: u32, +) -> Result<(), MyError> { + Err(MyError { message, code }) +} diff --git a/testing/checkin/runtime/error.ts b/testing/checkin/runtime/error.ts index 5c5b62a29..b109154c4 100644 --- a/testing/checkin/runtime/error.ts +++ b/testing/checkin/runtime/error.ts @@ -4,6 +4,7 @@ import { op_async_throw_error_eager, op_async_throw_error_lazy, op_error_custom_sync, + op_error_custom_with_code_sync, } from "ext:core/ops"; export async function asyncThrow(kind: "lazy" | "eager" | "deferred") { @@ -18,3 +19,7 @@ export async function asyncThrow(kind: "lazy" | "eager" | "deferred") { export function throwCustomError(message: string) { op_error_custom_sync(message); } + +export function throwCustomErrorWithCode(message: string, code: number) { + op_error_custom_with_code_sync(message, code); +} diff --git a/testing/lib.rs b/testing/lib.rs index 2e69a26b7..510b27a63 100644 --- a/testing/lib.rs +++ b/testing/lib.rs @@ -41,6 +41,7 @@ unit_test!( microtask_test, ops_async_test, ops_buffer_test, + ops_error_test, resource_test, serialize_deserialize_test, stats_test, diff --git a/testing/ops.d.ts b/testing/ops.d.ts index 74a109ad2..e603d0b03 100644 --- a/testing/ops.d.ts +++ b/testing/ops.d.ts @@ -12,6 +12,7 @@ export function op_async_throw_error_lazy(...any: any[]): any; export function op_error_context_async(...any: any[]): any; export function op_error_context_sync(...any: any[]): any; export function op_error_custom_sync(...any: any[]): any; +export function op_error_custom_with_code_sync(...any: any[]): any; export function op_worker_await_close(...any: any[]): any; export function op_worker_parent(...any: any[]): any; diff --git a/testing/unit/ops_error_test.ts b/testing/unit/ops_error_test.ts new file mode 100644 index 000000000..6ac870e7a --- /dev/null +++ b/testing/unit/ops_error_test.ts @@ -0,0 +1,13 @@ +// Copyright 2018-2025 the Deno authors. MIT license. +import { assertEquals, test } from "checkin:testing"; +import { throwCustomErrorWithCode } from "checkin:error"; + +test(function additionalPropertyIsWritable() { + try { + throwCustomErrorWithCode("foo", 1); + } catch (e) { + assertEquals(e.message, "foo"); + assertEquals(e.code, 1); + e.code = 2; + } +});