From 52a16eccabc0f4ad0951704cca6ab4ba3aa87ed7 Mon Sep 17 00:00:00 2001 From: Jeff Charles Date: Mon, 8 Jun 2026 15:36:50 -0400 Subject: [PATCH] Fix serializing proto key --- src/ser.rs | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/ser.rs b/src/ser.rs index e11f35f..ce3e006 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -1,6 +1,6 @@ use alloc::string::ToString as _; -use rquickjs::{Array, Ctx, Object, String as JSString, Value}; +use rquickjs::{Array, Ctx, Object, String as JSString, Value, object::Property}; use serde::{Serialize, ser}; use crate::err::{Error, Result}; @@ -367,7 +367,8 @@ impl<'se, 'js> ser::SerializeMap for MapSerializer<'se, 'js> { .ok_or_else(|| Error::new("serialize_value before serialize_key"))?; let value = value.serialize(&mut *self.ser)?; - self.value.set(key, value).map_err(Error::new) + let prop = Property::from(value).writable().configurable().enumerable(); + self.value.prop::<_, _, _>(key, prop).map_err(Error::new) } fn end(self) -> Result { @@ -641,6 +642,22 @@ mod tests { }); } + #[test] + fn test_map_proto_key_is_own_data_property() { + let rt = Runtime::default(); + + rt.context().with(|cx| { + let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap(); + + let mut map = BTreeMap::new(); + map.insert("__proto__", "bar"); + + let value = map.serialize(&mut serializer).unwrap(); + + assert_has_own_proto_data_property(cx, value, "'bar'"); + }); + } + #[test] fn test_struct_into_map() { let rt = Runtime::default(); @@ -756,6 +773,20 @@ mod tests { }); } + fn assert_has_own_proto_data_property<'js>( + cx: Ctx<'js>, + value: Value<'js>, + expected_value_source: &str, + ) { + cx.globals().set("__rquickjs_serde_value", value).unwrap(); + let assertion = format!( + "Object.getPrototypeOf(__rquickjs_serde_value) === Object.prototype && \ + Object.prototype.hasOwnProperty.call(__rquickjs_serde_value, '__proto__') && \ + Object.getOwnPropertyDescriptor(__rquickjs_serde_value, '__proto__').value === {expected_value_source}" + ); + assert!(cx.eval::(assertion.as_str()).unwrap()); + } + fn json_stringify<'js>(cx: Ctx<'js>, value: Value<'js>) -> String { let obj: Object = cx.globals().get("JSON").unwrap(); let stringify: Function = obj.get("stringify").unwrap();