i_slint_compiler/passes/
check_public_api.rs1use std::rc::Rc;
8
9use crate::diagnostics::{BuildDiagnostics, DiagnosticLevel};
10use crate::langtype::ElementType;
11use crate::object_tree::{Component, Document, ExportedName, PropertyVisibility};
12use crate::{CompilerConfiguration, ComponentSelection};
13use itertools::Either;
14
15pub fn check_public_api(
16 doc: &mut Document,
17 config: &CompilerConfiguration,
18 diag: &mut BuildDiagnostics,
19) {
20 let last = doc.last_exported_component();
21
22 if last.is_none() && !matches!(&config.components_to_generate, ComponentSelection::Named(_)) {
23 let last_imported = doc
24 .node
25 .as_ref()
26 .and_then(|n| {
27 let import_node = n.ImportSpecifier().last()?;
28 let import = crate::typeloader::ImportedName::extract_imported_names(&import_node.ImportIdentifierList()?).last()?;
29 let ElementType::Component(c) = doc.local_registry.lookup_element(&import.internal_name).ok()? else { return None };
30 diag.push_warning(format!("No component is exported. The last imported component '{}' will be used. This is deprecated", import.internal_name), &import_node);
31 let exported_name = ExportedName{ name: import.internal_name, name_ident: import_node.into() };
32 Some((exported_name, Either::Left(c)))
33 });
34 doc.exports.add_reexports(last_imported, diag);
35 }
36
37 match &config.components_to_generate {
38 ComponentSelection::ExportedWindows => doc.exports.retain(|export| {
39 if let Either::Left(c) = &export.1
41 && !c.is_global() && !super::windows::inherits_window(c) {
42 #[cfg(feature = "slint-sc")]
43 if diag.slint_sc {
44 diag.slint_sc_error(
45 "Exporting a component that doesn't inherit Window is",
46 &export.0.name_ident,
47 );
48 return true;
50 }
51 let is_last = last.as_ref().is_some_and(|last| !Rc::ptr_eq(last, c));
52
53 if cfg!(feature = "experimental-library-module") && config.library_name.is_some() {
54 return !is_last;
57 }
58
59 if is_last {
60 diag.push_warning(format!("Exported component '{}' doesn't inherit Window. No code will be generated for it", export.0.name), &export.0.name_ident);
61 return false;
62 } else {
63 diag.push_warning(format!("Exported component '{}' doesn't inherit Window. This is deprecated", export.0.name), &export.0.name_ident);
64 }
65 }
66 true
67 }),
68 ComponentSelection::LastExported => doc.exports.retain(|export| {
70 if let Either::Left(c) = &export.1 {
71 c.is_global() || last.as_ref().is_none_or(|last| Rc::ptr_eq(last, c))
72 } else {
73 true
74 }
75 }),
76 ComponentSelection::Named(name) => {
78 doc.exports.retain(|export| {
79 if let Either::Left(c) = &export.1 {
80 c.is_global() || c.id == name
81 } else {
82 true
83 }
84 });
85 if doc.last_exported_component().is_none() {
86 if let Ok(ElementType::Component(c)) = doc.local_registry.lookup_element(name)
88 && let Some(name_ident) = c.node.as_ref().map(|n| n.DeclaredIdentifier().into()) {
89 doc.exports.add_reexports(
90 [(ExportedName{ name: name.into(), name_ident }, Either::Left(c))],
91 diag,
92 );
93 }
94 }
95 },
96 }
97
98 for c in doc.exported_roots() {
99 check_public_api_component(&c, diag);
100 }
101 for (export_name, e) in &*doc.exports {
102 if let Some(c) = e.as_ref().left()
103 && c.is_global()
104 {
105 c.exported_global_names.borrow_mut().push(export_name.clone());
107 check_public_api_component(c, diag)
108 }
109 }
110}
111
112fn check_public_api_component(root_component: &Rc<Component>, diag: &mut BuildDiagnostics) {
113 let mut root_elem = root_component.root_element.borrow_mut();
114 let root_elem = &mut *root_elem;
115 let mut pa = root_elem.property_analysis.borrow_mut();
116 root_elem.property_declarations.iter_mut().for_each(|(n, d)| {
117 if d.property_type.ok_for_public_api() {
118 if d.visibility == PropertyVisibility::Private {
119 root_component.private_properties.borrow_mut().push((d.declared_name(n).clone(), d.property_type.clone()));
120 } else {
121 d.expose_in_public_api = true;
122 if d.visibility != PropertyVisibility::Output {
123 pa.entry(n.clone()).or_default().is_set = true;
124 }
125 }
126 } else {
127 diag.push_diagnostic(
128 format!("Properties of type {} are not supported yet for public API. The property will not be exposed", d.property_type),
129 &d.type_node(),
130 DiagnosticLevel::Warning
131 );
132 }
133 });
134}