diff --git a/moli-webapi-declare-derive/src/expand.rs b/moli-webapi-declare-derive/src/expand.rs index a9d4fb2349..89e1c09e35 100644 --- a/moli-webapi-declare-derive/src/expand.rs +++ b/moli-webapi-declare-derive/src/expand.rs @@ -582,6 +582,15 @@ fn static_template_accessor( let Some(name) = webapi_field_name_literal(attrs.name.as_ref()) else { return Ok(None); }; + let getter_name = LitStr::new(&format!("get {}", name.value()), name.span()); + let setter_name = LitStr::new( + &if attrs.setter.is_some() { + format!("set {}", name.value()) + } else { + String::new() + }, + name.span(), + ); let getter = attrs.getter.as_ref().ok_or_else(|| { Error::new( field.span(), @@ -604,7 +613,8 @@ fn static_template_accessor( let setter_receiver = receiver.checks_setter(); Ok(Some(quote! { ::moli_webapi_declare::__private::FunctionTemplateAccessor { - name: #name, + getter_name: #getter_name, + setter_name: #setter_name, getter: #getter, setter: #setter, enumerable: #enumerable, @@ -2254,6 +2264,8 @@ mod tests { struct SampleTemplate { #[webapi(accessor_property, getter = sample_getter)] value: (), + #[webapi(accessor_property = "mutable-Δ", getter = sample_getter, setter = sample_setter)] + mutable: (), #[webapi(accessor_property = "named", getter = sample_getter, setter = sample_setter, data = getter_data, setter_data = setter_data, dont_delete)] named: (), } @@ -2262,6 +2274,10 @@ mod tests { .expect("template accessors should expand") .to_string(); assert!(tokens.contains("FunctionTemplateAccessor")); + assert!(tokens.contains("getter_name : \"get value\"")); + assert!(tokens.contains("setter_name : \"\"")); + assert!(tokens.contains("getter_name : \"get mutable-Δ\"")); + assert!(tokens.contains("setter_name : \"set mutable-Δ\"")); assert!(tokens.contains("String :: new (scope , \"get named\")")); assert!(tokens.contains("String :: new (scope , \"set named\")")); assert!(tokens.contains("install_function_template_accessor")); diff --git a/moli-webapi-declare/src/__private.rs b/moli-webapi-declare/src/__private.rs index 91c4643d88..e69a2afed6 100644 --- a/moli-webapi-declare/src/__private.rs +++ b/moli-webapi-declare/src/__private.rs @@ -171,9 +171,12 @@ pub fn install_function_template_methods<'s>( /// Static metadata for a string-named accessor without callback data. /// Mappings preserve constant tables while using V8's original call-time path. +/// The derive prefixes getter names with "get "; the suffix is the property key. #[doc(hidden)] pub struct FunctionTemplateAccessor { - pub name: &'static str, + pub getter_name: &'static str, + /// Empty when no setter is declared. + pub setter_name: &'static str, pub getter: fn() -> v8::FunctionCallback, pub setter: Option v8::FunctionCallback>, pub enumerable: bool, @@ -192,7 +195,7 @@ pub fn install_function_template_accessors<'s>( accessors: &[FunctionTemplateAccessor], ) { for accessor in accessors { - let key = v8str(scope, accessor.name); + let key = v8str(scope, &accessor.getter_name["get ".len()..]); let mut attributes = v8::PropertyAttribute::NONE; if !accessor.enumerable { attributes = attributes | v8::PropertyAttribute::DONT_ENUM; @@ -207,14 +210,14 @@ pub fn install_function_template_accessors<'s>( callback: (accessor.getter)(), length: 0, data: None, - class_name: v8::String::new(scope, &format!("get {}", accessor.name)), + class_name: v8::String::new(scope, accessor.getter_name), receiver_access_check: accessor.getter_receiver_access_check, }; let setter = accessor.setter.map(|mapping| FunctionTemplateMember { callback: mapping(), length: 1, data: None, - class_name: v8::String::new(scope, &format!("set {}", accessor.name)), + class_name: v8::String::new(scope, accessor.setter_name), receiver_access_check: accessor.setter_receiver_access_check, }); install_function_template_accessor(scope, target, key.into(), getter, setter, attributes); diff --git a/moli-webapi-declare/tests/declare.rs b/moli-webapi-declare/tests/declare.rs index 72b425d0f7..e69f276445 100644 --- a/moli-webapi-declare/tests/declare.rs +++ b/moli-webapi-declare/tests/declare.rs @@ -439,7 +439,7 @@ const DYNAMIC_ATTRIBUTE_NAME: &str = "runtimeAttribute"; struct AttributeMetadataTemplateDeclaration { #[webapi(accessor_property, getter = sample_receiver_getter)] implicit_name: (), - #[webapi(accessor_property = "explicit-name", getter = sample_receiver_getter)] + #[webapi(accessor_property = "explicit-name-Δ", getter = sample_receiver_getter)] explicit: (), #[webapi(native_data_property, getter = sample_native_holder_getter)] native_holder: (), @@ -466,7 +466,7 @@ fn prototype_attribute_metadata_tracks_static_attribute_keys() { let attributes = AttributeMetadataTemplateDeclaration::PROTOTYPE_ATTRIBUTE_NAMES; assert_eq!( attributes, - ["implicitName", "explicit-name", "nativeHolder"] + ["implicitName", "explicit-name-Δ", "nativeHolder"] ); for attribute in attributes { assert!( @@ -477,6 +477,17 @@ fn prototype_attribute_metadata_tracks_static_attribute_keys() { .boolean_value(scope) ); } + assert!( + run_script( + scope, + r#"['implicitName', 'explicit-name-Δ'].every(key => { + const descriptor = Object.getOwnPropertyDescriptor(AttributeMetadata.prototype, key); + return descriptor.get.name === `get ${key}` + && descriptor.get.length === 0 && descriptor.set === undefined; + })"# + ) + .boolean_value(scope) + ); assert!( run_script( scope,