From 19bc8e64a4dbdc613503e2446b9e124e92d525cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=88=B1=E7=89=B9=E6=AF=8F=E7=BE=8A=E9=98=9F?= Date: Sat, 27 Jun 2026 17:23:50 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20defineProperty=20=E7=BA=AF=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E6=8F=8F=E8=BF=B0=E7=AC=A6=E6=8C=89=20ES=20=E8=A7=84?= =?UTF-8?q?=E8=8C=83=E9=BB=98=E8=AE=A4=E5=88=9B=E5=BB=BA=20value=3Dundefin?= =?UTF-8?q?ed=EF=BC=8C=E4=B8=8D=E5=86=8D=E9=94=99=E8=AF=AF=E6=8A=9B=20Type?= =?UTF-8?q?Error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_builtins/src/object.rs | 11 +++++++---- .../tests/define_property_descriptor_tests.rs | 8 ++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/crates/oxide_builtins/src/object.rs b/crates/oxide_builtins/src/object.rs index f576d03..3126be3 100644 --- a/crates/oxide_builtins/src/object.rs +++ b/crates/oxide_builtins/src/object.rs @@ -287,10 +287,13 @@ pub fn object_define_property(vm: &mut H, args: &[u8]) -> NativeResul } } else { if existing_pos.is_none() { - return NativeResult::Err(crate::error::create_type_error( - vm, - "Cannot define new property without value or accessor", - )); + if vm + .define_data_property(obj, si, JsValue::undefined(), PropAttributes::new(false, enumerable, configurable)) + .is_err() + { + return NativeResult::Err(crate::error::create_type_error(vm, "Cannot define property")); + } + return NativeResult::Ok(obj_val); } let is_accessor = existing_meta.map(|m| m.is_accessor).unwrap_or(false); let writable = existing_meta.map(|m| m.attributes.writable()).unwrap_or(true); diff --git a/crates/oxide_vm/tests/define_property_descriptor_tests.rs b/crates/oxide_vm/tests/define_property_descriptor_tests.rs index 7548245..bd53e7b 100644 --- a/crates/oxide_vm/tests/define_property_descriptor_tests.rs +++ b/crates/oxide_vm/tests/define_property_descriptor_tests.rs @@ -92,11 +92,11 @@ fn get_own_property_descriptor_accessor_fields() { ); } -// -- New property without value or accessor throws -- +// -- New property without value or accessor defaults to data descriptor (ES spec behavior) -- #[test] -fn define_property_new_without_value_throws() { - let result = eval_str("var obj={}; Object.defineProperty(obj,'x',{enumerable:true})"); - assert_err_contains(result, "Cannot define new property without value or accessor"); +fn define_property_new_attributes_only_defaults_value_undefined() { + let r = eval_str("var obj={}; Object.defineProperty(obj,'x',{enumerable:true}); obj.x").unwrap(); + assert!(r.is_undefined(), "new prop with only enumerable should default value to undefined, got {:?}", r); } // -- Partial configurable on existing property preserves value --