1#[path = "roles_surface_assignment.rs"]
2mod assignment;
3#[path = "roles_surface_config.rs"]
4mod config;
5#[path = "roles_surface_contract.rs"]
6mod contract;
7#[path = "roles_surface_facade.rs"]
8mod facade;
9#[path = "roles_surface_hooks.rs"]
10mod hooks;
11#[path = "roles_surface_presentation.rs"]
12mod presentation;
13#[path = "roles_surface_protocol.rs"]
14mod protocol;
15
16use crate::types::FileRecord;
17
18fn source_has_export_markers(source: &str) -> bool {
19 let lower = source.to_lowercase();
20 (lower.contains("from ") && lower.contains(" import "))
21 || lower.contains("export * from")
22 || lower.contains("export {")
23 || lower.contains("pub use ")
24 || lower.contains("__all__")
25 || lower.contains(" as _")
26}
27
28fn source_has_only_exports(source: &str) -> bool {
29 let lower = source.to_lowercase();
30 source_has_export_markers(source) && !lower.contains("def ") && !lower.contains("class ")
31}
32
33fn source_has_only_module_declarations(source: &str) -> bool {
34 let mut saw_declaration = false;
35
36 for line in source.lines() {
37 let trimmed = line.trim();
38 if trimmed.is_empty()
39 || trimmed.starts_with("//")
40 || trimmed.starts_with("/*")
41 || trimmed.starts_with('*')
42 {
43 continue;
44 }
45
46 let is_module_declaration = trimmed.starts_with("mod ")
47 || trimmed.starts_with("pub mod ")
48 || (trimmed.starts_with("pub(")
49 && (trimmed.contains(" mod ") || trimmed.contains(" use ")));
50 let is_use_declaration = trimmed.starts_with("use ")
51 || trimmed.starts_with("pub use ")
52 || (trimmed.starts_with("pub(") && trimmed.contains(" use "));
53 let is_attribute = trimmed.starts_with("#![") || trimmed.starts_with("#[");
54
55 if is_module_declaration || is_use_declaration || is_attribute {
56 saw_declaration = true;
57 continue;
58 }
59
60 return false;
61 }
62
63 saw_declaration
64}
65
66pub fn source_looks_like_wrapper_module(source: &str) -> bool {
67 source_has_export_markers(source)
68}
69
70pub fn is_pure_reexport_module(file: &FileRecord) -> bool {
71 source_has_only_exports(&file.source)
72 || (file.methods.is_empty()
73 && source_has_export_markers(&file.source)
74 && !file.source.to_lowercase().contains("def "))
75}
76
77pub fn is_module_barrel_module(file: &FileRecord) -> bool {
78 file.methods.is_empty() && source_has_only_module_declarations(&file.source)
79}
80
81pub fn is_wrapper_only_module(file: &FileRecord) -> bool {
82 if file.methods.is_empty() {
83 return false;
84 }
85
86 file.methods.iter().all(|method| {
87 facade::is_thin_wrapper_export(method) || facade::is_thin_delegation_method(method)
88 })
89}
90
91pub use assignment::is_wrapper_assignment;
92pub use config::is_config_validation_module;
93pub use contract::is_callback_contract_module;
94pub use facade::{is_detector_facade_module, is_thin_delegation_method, is_thin_wrapper_export};
95pub use hooks::is_hydration_hook_module;
96pub use presentation::is_presentation_surface_module;
97pub use protocol::{is_protocol_stub_method, is_protocol_surface_module};