Skip to main content

deps_swift/
types.rs

1//! Swift/SPM dependency types.
2
3use deps_core::parser::DependencySource;
4use tower_lsp_server::ls_types::Range;
5
6/// Parsed dependency from Package.swift with position tracking.
7///
8/// Package names use `owner/repo` format derived from the Git URL.
9/// Position tracking enables hover, completion, and inlay hints.
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct SwiftDependency {
12    /// Package identity: owner/repo (e.g. "apple/swift-nio")
13    pub name: String,
14    /// LSP range of the URL string content (excluding quotes)
15    pub name_range: Range,
16    /// Normalized version requirement or None for branch/revision/path deps
17    pub version_req: Option<String>,
18    /// LSP range of the version string content (excluding quotes), None for non-registry deps
19    pub version_range: Option<Range>,
20    /// Original Git URL from Package.swift
21    pub url: String,
22    /// Dependency source (registry, git, or path)
23    pub source: DependencySource,
24}
25
26impl deps_core::parser::DependencyInfo for SwiftDependency {
27    fn name(&self) -> &str {
28        &self.name
29    }
30
31    fn name_range(&self) -> tower_lsp_server::ls_types::Range {
32        self.name_range
33    }
34
35    fn version_requirement(&self) -> Option<&str> {
36        self.version_req.as_deref()
37    }
38
39    fn version_range(&self) -> Option<tower_lsp_server::ls_types::Range> {
40        self.version_range
41    }
42
43    fn source(&self) -> DependencySource {
44        self.source.clone()
45    }
46}
47
48impl deps_core::ecosystem::Dependency for SwiftDependency {
49    fn name(&self) -> &str {
50        &self.name
51    }
52
53    fn name_range(&self) -> tower_lsp_server::ls_types::Range {
54        self.name_range
55    }
56
57    fn version_requirement(&self) -> Option<&str> {
58        self.version_req.as_deref()
59    }
60
61    fn version_range(&self) -> Option<tower_lsp_server::ls_types::Range> {
62        self.version_range
63    }
64
65    fn source(&self) -> DependencySource {
66        self.source.clone()
67    }
68
69    fn as_any(&self) -> &dyn std::any::Any {
70        self
71    }
72}
73
74/// Version information for a Swift package (GitHub tag).
75#[derive(Debug, Clone)]
76pub struct SwiftVersion {
77    /// Semver version string (v prefix stripped)
78    pub version: String,
79    /// Always false for GitHub tags
80    pub yanked: bool,
81}
82
83deps_core::impl_version!(SwiftVersion {
84    version: version,
85    yanked: yanked,
86});
87
88/// Package metadata from GitHub API.
89#[derive(Debug, Clone)]
90pub struct SwiftPackage {
91    /// owner/repo identity
92    pub name: String,
93    /// GitHub repo description
94    pub description: Option<String>,
95    /// GitHub URL
96    pub repository: Option<String>,
97    /// GitHub URL (same as repository)
98    pub homepage: Option<String>,
99    /// Latest semver tag
100    pub latest_version: String,
101}
102
103deps_core::impl_metadata!(SwiftPackage {
104    name: name,
105    description: description,
106    repository: repository,
107    documentation: homepage,
108    latest_version: latest_version,
109});
110
111/// Result of parsing a Package.swift file.
112#[derive(Debug)]
113pub struct SwiftParseResult {
114    pub dependencies: Vec<SwiftDependency>,
115    pub uri: tower_lsp_server::ls_types::Uri,
116}
117
118impl deps_core::ParseResult for SwiftParseResult {
119    fn dependencies(&self) -> Vec<&dyn deps_core::Dependency> {
120        self.dependencies
121            .iter()
122            .map(|d| d as &dyn deps_core::Dependency)
123            .collect()
124    }
125
126    fn workspace_root(&self) -> Option<&std::path::Path> {
127        None
128    }
129
130    fn uri(&self) -> &tower_lsp_server::ls_types::Uri {
131        &self.uri
132    }
133
134    fn as_any(&self) -> &dyn std::any::Any {
135        self
136    }
137}
138
139#[cfg(test)]
140mod tests {
141    use super::*;
142    use deps_core::{Dependency, Metadata, Version};
143    use tower_lsp_server::ls_types::Position;
144
145    #[test]
146    fn test_swift_dependency_registry() {
147        let dep = SwiftDependency {
148            name: "apple/swift-nio".into(),
149            name_range: Range::new(Position::new(0, 0), Position::new(0, 15)),
150            version_req: Some(">=2.0.0, <3.0.0".into()),
151            version_range: Some(Range::new(Position::new(0, 20), Position::new(0, 27))),
152            url: "https://github.com/apple/swift-nio.git".into(),
153            source: DependencySource::Registry,
154        };
155
156        assert_eq!(dep.name(), "apple/swift-nio");
157        assert_eq!(dep.version_requirement(), Some(">=2.0.0, <3.0.0"));
158        assert!(matches!(dep.source(), DependencySource::Registry));
159    }
160
161    #[test]
162    fn test_swift_version() {
163        let ver = SwiftVersion {
164            version: "2.40.0".into(),
165            yanked: false,
166        };
167        assert_eq!(ver.version_string(), "2.40.0");
168        assert!(!ver.is_yanked());
169    }
170
171    #[test]
172    fn test_swift_package_metadata() {
173        let pkg = SwiftPackage {
174            name: "apple/swift-nio".into(),
175            description: Some("Networking framework".into()),
176            repository: Some("https://github.com/apple/swift-nio".into()),
177            homepage: Some("https://github.com/apple/swift-nio".into()),
178            latest_version: "2.62.0".into(),
179        };
180        assert_eq!(pkg.name(), "apple/swift-nio");
181        assert_eq!(pkg.description(), Some("Networking framework"));
182        assert_eq!(pkg.latest_version(), "2.62.0");
183    }
184}