interpreter: Expose visibility of exported components

This commit is contained in:
Tobias Hunger 2025-01-24 09:57:35 +01:00 committed by Tobias Hunger
parent 2f03bad1cc
commit b5520ef370
4 changed files with 56 additions and 21 deletions

View file

@ -46,7 +46,7 @@ impl JsComponentInstance {
#[napi] #[napi]
pub fn set_property(&self, env: Env, prop_name: String, js_value: JsUnknown) -> Result<()> { pub fn set_property(&self, env: Env, prop_name: String, js_value: JsUnknown) -> Result<()> {
let ty = self let (ty, _) = self
.inner .inner
.definition() .definition()
.properties_and_callbacks() .properties_and_callbacks()
@ -88,7 +88,7 @@ impl JsComponentInstance {
prop_name: String, prop_name: String,
js_value: JsUnknown, js_value: JsUnknown,
) -> Result<()> { ) -> Result<()> {
let ty = self let (ty, _) = self
.inner .inner
.definition() .definition()
.global_properties_and_callbacks(global_name.as_str()) .global_properties_and_callbacks(global_name.as_str())
@ -121,7 +121,7 @@ impl JsComponentInstance {
) -> Result<()> { ) -> Result<()> {
let function_ref = RefCountedReference::new(&env, callback)?; let function_ref = RefCountedReference::new(&env, callback)?;
let ty = self let (ty, _) = self
.inner .inner
.definition() .definition()
.properties_and_callbacks() .properties_and_callbacks()
@ -188,7 +188,7 @@ impl JsComponentInstance {
) -> Result<()> { ) -> Result<()> {
let function_ref = RefCountedReference::new(&env, callback)?; let function_ref = RefCountedReference::new(&env, callback)?;
let ty = self let (ty, _) = self
.inner .inner
.definition() .definition()
.global_properties_and_callbacks(global_name.as_str()) .global_properties_and_callbacks(global_name.as_str())
@ -283,7 +283,7 @@ impl JsComponentInstance {
callback_name: String, callback_name: String,
callback_arguments: Vec<JsUnknown>, callback_arguments: Vec<JsUnknown>,
) -> Result<JsUnknown> { ) -> Result<JsUnknown> {
let ty = self let (ty, _) = self
.inner .inner
.definition() .definition()
.properties_and_callbacks() .properties_and_callbacks()
@ -321,7 +321,7 @@ impl JsComponentInstance {
callback_name: String, callback_name: String,
callback_arguments: Vec<JsUnknown>, callback_arguments: Vec<JsUnknown>,
) -> Result<JsUnknown> { ) -> Result<JsUnknown> {
let ty = self let (ty, _) = self
.inner .inner
.definition() .definition()
.global_properties_and_callbacks(global_name.as_str()) .global_properties_and_callbacks(global_name.as_str())

View file

@ -1021,11 +1021,16 @@ impl ComponentDefinition {
#[cfg(feature = "internal")] #[cfg(feature = "internal")]
pub fn properties_and_callbacks( pub fn properties_and_callbacks(
&self, &self,
) -> impl Iterator<Item = (String, i_slint_compiler::langtype::Type)> + '_ { ) -> impl Iterator<
Item = (
String,
(i_slint_compiler::langtype::Type, i_slint_compiler::object_tree::PropertyVisibility),
),
> + '_ {
// We create here a 'static guard, because unfortunately the returned type would be restricted to the guard lifetime // We create here a 'static guard, because unfortunately the returned type would be restricted to the guard lifetime
// which is not required, but this is safe because there is only one instance of the unerased type // which is not required, but this is safe because there is only one instance of the unerased type
let guard = unsafe { generativity::Guard::new(generativity::Id::new()) }; let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };
self.inner.unerase(guard).properties().map(|(s, t)| (s.to_string(), t)) self.inner.unerase(guard).properties().map(|(s, t, v)| (s.to_string(), (t, v)))
} }
/// Returns an iterator over all publicly declared properties. Each iterator item is a tuple of property name /// Returns an iterator over all publicly declared properties. Each iterator item is a tuple of property name
@ -1034,7 +1039,7 @@ impl ComponentDefinition {
// We create here a 'static guard, because unfortunately the returned type would be restricted to the guard lifetime // We create here a 'static guard, because unfortunately the returned type would be restricted to the guard lifetime
// which is not required, but this is safe because there is only one instance of the unerased type // which is not required, but this is safe because there is only one instance of the unerased type
let guard = unsafe { generativity::Guard::new(generativity::Id::new()) }; let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };
self.inner.unerase(guard).properties().filter_map(|(prop_name, prop_type)| { self.inner.unerase(guard).properties().filter_map(|(prop_name, prop_type, _)| {
if prop_type.is_property_type() { if prop_type.is_property_type() {
Some((prop_name.to_string(), prop_type.into())) Some((prop_name.to_string(), prop_type.into()))
} else { } else {
@ -1048,7 +1053,7 @@ impl ComponentDefinition {
// We create here a 'static guard, because unfortunately the returned type would be restricted to the guard lifetime // We create here a 'static guard, because unfortunately the returned type would be restricted to the guard lifetime
// which is not required, but this is safe because there is only one instance of the unerased type // which is not required, but this is safe because there is only one instance of the unerased type
let guard = unsafe { generativity::Guard::new(generativity::Id::new()) }; let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };
self.inner.unerase(guard).properties().filter_map(|(prop_name, prop_type)| { self.inner.unerase(guard).properties().filter_map(|(prop_name, prop_type, _)| {
if matches!(prop_type, LangType::Callback { .. }) { if matches!(prop_type, LangType::Callback { .. }) {
Some(prop_name.to_string()) Some(prop_name.to_string())
} else { } else {
@ -1062,7 +1067,7 @@ impl ComponentDefinition {
// We create here a 'static guard, because unfortunately the returned type would be restricted to the guard lifetime // We create here a 'static guard, because unfortunately the returned type would be restricted to the guard lifetime
// which is not required, but this is safe because there is only one instance of the unerased type // which is not required, but this is safe because there is only one instance of the unerased type
let guard = unsafe { generativity::Guard::new(generativity::Id::new()) }; let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };
self.inner.unerase(guard).properties().filter_map(|(prop_name, prop_type)| { self.inner.unerase(guard).properties().filter_map(|(prop_name, prop_type, _)| {
if matches!(prop_type, LangType::Function { .. }) { if matches!(prop_type, LangType::Function { .. }) {
Some(prop_name.to_string()) Some(prop_name.to_string())
} else { } else {
@ -1090,14 +1095,24 @@ impl ComponentDefinition {
pub fn global_properties_and_callbacks( pub fn global_properties_and_callbacks(
&self, &self,
global_name: &str, global_name: &str,
) -> Option<impl Iterator<Item = (String, i_slint_compiler::langtype::Type)> + '_> { ) -> Option<
impl Iterator<
Item = (
String,
(
i_slint_compiler::langtype::Type,
i_slint_compiler::object_tree::PropertyVisibility,
),
),
> + '_,
> {
// We create here a 'static guard, because unfortunately the returned type would be restricted to the guard lifetime // We create here a 'static guard, because unfortunately the returned type would be restricted to the guard lifetime
// which is not required, but this is safe because there is only one instance of the unerased type // which is not required, but this is safe because there is only one instance of the unerased type
let guard = unsafe { generativity::Guard::new(generativity::Id::new()) }; let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };
self.inner self.inner
.unerase(guard) .unerase(guard)
.global_properties(global_name) .global_properties(global_name)
.map(|o| o.map(|(s, t)| (s.to_string(), t))) .map(|o| o.map(|(s, t, v)| (s.to_string(), (t, v))))
} }
/// List of publicly declared properties in the exported global singleton specified by its name. /// List of publicly declared properties in the exported global singleton specified by its name.
@ -1109,7 +1124,7 @@ impl ComponentDefinition {
// which is not required, but this is safe because there is only one instance of the unerased type // which is not required, but this is safe because there is only one instance of the unerased type
let guard = unsafe { generativity::Guard::new(generativity::Id::new()) }; let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };
self.inner.unerase(guard).global_properties(global_name).map(|iter| { self.inner.unerase(guard).global_properties(global_name).map(|iter| {
iter.filter_map(|(prop_name, prop_type)| { iter.filter_map(|(prop_name, prop_type, _)| {
if prop_type.is_property_type() { if prop_type.is_property_type() {
Some((prop_name.to_string(), prop_type.into())) Some((prop_name.to_string(), prop_type.into()))
} else { } else {
@ -1125,7 +1140,7 @@ impl ComponentDefinition {
// which is not required, but this is safe because there is only one instance of the unerased type // which is not required, but this is safe because there is only one instance of the unerased type
let guard = unsafe { generativity::Guard::new(generativity::Id::new()) }; let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };
self.inner.unerase(guard).global_properties(global_name).map(|iter| { self.inner.unerase(guard).global_properties(global_name).map(|iter| {
iter.filter_map(|(prop_name, prop_type)| { iter.filter_map(|(prop_name, prop_type, _)| {
if matches!(prop_type, LangType::Callback { .. }) { if matches!(prop_type, LangType::Callback { .. }) {
Some(prop_name.to_string()) Some(prop_name.to_string())
} else { } else {
@ -1141,7 +1156,7 @@ impl ComponentDefinition {
// which is not required, but this is safe because there is only one instance of the unerased type // which is not required, but this is safe because there is only one instance of the unerased type
let guard = unsafe { generativity::Guard::new(generativity::Id::new()) }; let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };
self.inner.unerase(guard).global_properties(global_name).map(|iter| { self.inner.unerase(guard).global_properties(global_name).map(|iter| {
iter.filter_map(|(prop_name, prop_type)| { iter.filter_map(|(prop_name, prop_type, _)| {
if matches!(prop_type, LangType::Function { .. }) { if matches!(prop_type, LangType::Function { .. }) {
Some(prop_name.to_string()) Some(prop_name.to_string())
} else { } else {

View file

@ -432,7 +432,13 @@ impl PopupMenuDescription {
fn internal_properties_to_public<'a>( fn internal_properties_to_public<'a>(
prop_iter: impl Iterator<Item = (&'a SmolStr, &'a PropertyDeclaration)> + 'a, prop_iter: impl Iterator<Item = (&'a SmolStr, &'a PropertyDeclaration)> + 'a,
) -> impl Iterator<Item = (SmolStr, i_slint_compiler::langtype::Type)> + 'a { ) -> impl Iterator<
Item = (
SmolStr,
i_slint_compiler::langtype::Type,
i_slint_compiler::object_tree::PropertyVisibility,
),
> + 'a {
prop_iter.filter(|(_, v)| v.expose_in_public_api).map(|(s, v)| { prop_iter.filter(|(_, v)| v.expose_in_public_api).map(|(s, v)| {
let name = v let name = v
.node .node
@ -443,7 +449,7 @@ fn internal_properties_to_public<'a>(
}) })
.map(|n| n.to_smolstr()) .map(|n| n.to_smolstr())
.unwrap_or_else(|| s.to_smolstr()); .unwrap_or_else(|| s.to_smolstr());
(name, v.property_type.clone()) (name, v.property_type.clone(), v.visibility.clone())
}) })
} }
@ -471,7 +477,13 @@ impl ItemTreeDescription<'_> {
/// We try to preserve the dashes and underscore as written in the property declaration /// We try to preserve the dashes and underscore as written in the property declaration
pub fn properties( pub fn properties(
&self, &self,
) -> impl Iterator<Item = (SmolStr, i_slint_compiler::langtype::Type)> + '_ { ) -> impl Iterator<
Item = (
SmolStr,
i_slint_compiler::langtype::Type,
i_slint_compiler::object_tree::PropertyVisibility,
),
> + '_ {
internal_properties_to_public(self.public_properties.iter()) internal_properties_to_public(self.public_properties.iter())
} }
@ -489,7 +501,15 @@ impl ItemTreeDescription<'_> {
pub fn global_properties( pub fn global_properties(
&self, &self,
name: &str, name: &str,
) -> Option<impl Iterator<Item = (SmolStr, i_slint_compiler::langtype::Type)> + '_> { ) -> Option<
impl Iterator<
Item = (
SmolStr,
i_slint_compiler::langtype::Type,
i_slint_compiler::object_tree::PropertyVisibility,
),
> + '_,
> {
let g = self.compiled_globals.as_ref().expect("Root component should have globals"); let g = self.compiled_globals.as_ref().expect("Root component should have globals");
g.exported_globals_by_name g.exported_globals_by_name
.get(crate::normalize_identifier(name).as_ref()) .get(crate::normalize_identifier(name).as_ref())

View file

@ -344,7 +344,7 @@ fn load_data(
let obj = json.as_object().ok_or("The data is not a JSON object")?; let obj = json.as_object().ok_or("The data is not a JSON object")?;
for (name, v) in obj { for (name, v) in obj {
match types.get(name.as_str()) { match types.get(name.as_str()) {
Some(t) => match slint_interpreter::Value::from_json(t, v) { Some((t, _)) => match slint_interpreter::Value::from_json(t, v) {
Ok(v) => match instance.set_property(name, v) { Ok(v) => match instance.set_property(name, v) {
Ok(()) => (), Ok(()) => (),
Err(e) => { Err(e) => {