apple_bindgen/deps/
analyzer.rs1use regex::Regex;
4use std::collections::HashSet;
5use std::path::Path;
6
7pub struct DependencyAnalyzer {
9 sdk_path: std::path::PathBuf,
10}
11
12impl DependencyAnalyzer {
13 pub fn new(sdk_path: impl AsRef<Path>) -> Self {
15 Self {
16 sdk_path: sdk_path.as_ref().to_path_buf(),
17 }
18 }
19
20 pub fn umbrella_header_path(&self, framework: &str) -> std::path::PathBuf {
22 self.sdk_path
23 .join("System/Library/Frameworks")
24 .join(format!("{}.framework", framework))
25 .join("Headers")
26 .join(format!("{}.h", framework))
27 }
28
29 pub fn analyze(&self, framework: &str) -> std::io::Result<Vec<String>> {
33 let header_path = self.umbrella_header_path(framework);
34 let content = std::fs::read_to_string(&header_path)?;
35 Ok(extract_framework_imports(&content, framework))
36 }
37}
38
39fn extract_framework_imports(content: &str, self_framework: &str) -> Vec<String> {
46 let mut frameworks = HashSet::new();
47
48 let import_re = Regex::new(r#"#(?:import|include)\s+<(\w+)/"#).unwrap();
50 for cap in import_re.captures_iter(content) {
51 let fw = &cap[1];
52 if fw != self_framework {
53 frameworks.insert(fw.to_string());
54 }
55 }
56
57 let module_re = Regex::new(r"@import\s+(\w+)\s*;").unwrap();
59 for cap in module_re.captures_iter(content) {
60 let fw = &cap[1];
61 if fw != self_framework {
62 frameworks.insert(fw.to_string());
63 }
64 }
65
66 let mut result: Vec<_> = frameworks.into_iter().collect();
67 result.sort();
68 result
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[test]
76 fn test_extract_import() {
77 let content = r#"
78 #import <Foundation/Foundation.h>
79 #import <CoreGraphics/CoreGraphics.h>
80 #import <AppKit/NSView.h>
81 "#;
82 let deps = extract_framework_imports(content, "AppKit");
83 assert!(deps.contains(&"Foundation".to_string()));
84 assert!(deps.contains(&"CoreGraphics".to_string()));
85 assert!(!deps.contains(&"AppKit".to_string()));
87 }
88
89 #[test]
90 fn test_extract_include() {
91 let content = r#"
92 #include <CoreFoundation/CoreFoundation.h>
93 "#;
94 let deps = extract_framework_imports(content, "Foundation");
95 assert!(deps.contains(&"CoreFoundation".to_string()));
96 }
97
98 #[test]
99 fn test_extract_module_import() {
100 let content = r#"
101 @import Foundation;
102 @import CoreGraphics;
103 "#;
104 let deps = extract_framework_imports(content, "AppKit");
105 assert!(deps.contains(&"Foundation".to_string()));
106 assert!(deps.contains(&"CoreGraphics".to_string()));
107 }
108}