1use deps_core::parser::DependencySource;
4use std::any::Any;
5use tower_lsp_server::ls_types::Range;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct GoDependency {
10 pub module_path: deps_core::PackageName,
12 pub module_path_range: Range,
14 pub version: Option<deps_core::VersionReq>,
16 pub version_range: Option<Range>,
18 pub directive: GoDirective,
20 pub indirect: bool,
22 pub source: DependencySource,
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
29pub enum GoDirective {
30 Require,
32 Replace,
34 Exclude,
36 Retract,
38}
39
40#[derive(Debug, Clone)]
42pub struct GoVersion {
43 pub version: deps_core::ConcreteVersion,
45 pub published_at: Option<deps_core::PublishTime>,
53 pub is_pseudo: bool,
55 pub retracted: bool,
57}
58
59#[derive(Debug, Clone)]
61pub struct GoMetadata {
62 pub module_path: deps_core::PackageName,
64 pub latest_version: deps_core::ConcreteVersion,
66 pub description: Option<String>,
68 pub repository: Option<String>,
70 pub documentation: Option<String>,
72}
73
74impl deps_core::ecosystem::Dependency for GoDependency {
78 fn name(&self) -> &deps_core::PackageName {
79 &self.module_path
80 }
81
82 fn name_range(&self) -> Range {
83 self.module_path_range
84 }
85
86 fn version_requirement(&self) -> Option<&deps_core::VersionReq> {
87 self.version.as_ref()
88 }
89
90 fn version_range(&self) -> Option<Range> {
91 self.version_range
92 }
93
94 fn source(&self) -> DependencySource {
95 self.source.clone()
96 }
97
98 fn features(&self) -> &[String] {
99 &[]
100 }
101
102 fn as_any(&self) -> &dyn Any {
103 self
104 }
105}
106
107impl deps_core::registry::Version for GoVersion {
110 fn version_string(&self) -> &deps_core::ConcreteVersion {
111 &self.version
112 }
113
114 fn removal_status(&self) -> deps_core::RemovalStatus {
115 deps_core::RemovalStatus::from_yanked(self.retracted)
116 }
117
118 fn published_at(&self) -> Option<deps_core::PublishTime> {
119 self.published_at
120 }
121
122 fn is_prerelease(&self) -> bool {
123 self.is_pseudo
127 || (self.version.as_str().contains('-')
128 && !self.version.as_str().contains("+incompatible"))
129 }
130
131 fn features(&self) -> Vec<String> {
132 vec![]
133 }
134
135 fn as_any(&self) -> &dyn Any {
136 self
137 }
138}
139
140deps_core::impl_metadata!(GoMetadata {
141 name: module_path,
142 description: description,
143 repository: repository,
144 documentation: documentation,
145 latest_version: latest_version,
146});
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151 use deps_core::ecosystem::Dependency;
152 use deps_core::registry::{Metadata, Version};
153 use std::assert_matches;
154 use tower_lsp_server::ls_types::Position;
155
156 #[test]
157 fn test_go_dependency_trait() {
158 let dep = GoDependency {
159 module_path: "github.com/gin-gonic/gin".into(),
160 module_path_range: Range::new(Position::new(0, 0), Position::new(0, 10)),
161 version: Some("v1.9.1".into()),
162 version_range: Some(Range::new(Position::new(0, 11), Position::new(0, 17))),
163 directive: GoDirective::Require,
164 indirect: false,
165 source: DependencySource::Registry,
166 };
167
168 assert_eq!(dep.name(), "github.com/gin-gonic/gin");
169 assert_eq!(
170 dep.version_requirement().map(deps_core::VersionReq::as_str),
171 Some("v1.9.1")
172 );
173 assert_matches!(dep.source(), DependencySource::Registry);
174 assert_eq!(dep.features().len(), 0);
175 }
176
177 #[test]
178 fn test_go_version_trait() {
179 let version = GoVersion {
180 version: "v1.9.1".into(),
181 published_at: deps_core::PublishTime::parse_rfc3339("2023-01-01T00:00:00Z"),
182 is_pseudo: false,
183 retracted: false,
184 };
185
186 assert_eq!(version.version_string().as_str(), "v1.9.1");
187 assert!(!version.removal_status().blocks_resolution());
188 assert!(!version.is_prerelease());
189 assert!(version.is_stable());
190 assert_eq!(
191 version.published_at(),
192 deps_core::PublishTime::parse_rfc3339("2023-01-01T00:00:00Z")
193 );
194 }
195
196 #[test]
197 fn test_pseudo_version_is_prerelease() {
198 let version = GoVersion {
199 version: "v0.0.0-20191109021931-daa7c04131f5".into(),
200 published_at: None,
201 is_pseudo: true,
202 retracted: false,
203 };
204
205 assert!(version.is_prerelease());
206 assert!(!version.is_stable());
207 }
208
209 #[test]
210 fn test_retracted_version_is_yanked() {
211 let version = GoVersion {
212 version: "v1.0.0".into(),
213 published_at: None,
214 is_pseudo: false,
215 retracted: true,
216 };
217
218 assert!(version.removal_status().blocks_resolution());
219 assert!(!version.is_stable());
220 }
221
222 #[test]
223 fn test_go_metadata_trait() {
224 let metadata = GoMetadata {
225 module_path: "github.com/gin-gonic/gin".into(),
226 latest_version: "v1.9.1".into(),
227 description: Some("Gin is a HTTP web framework".to_string()),
228 repository: Some("https://github.com/gin-gonic/gin".to_string()),
229 documentation: Some("https://pkg.go.dev/github.com/gin-gonic/gin".to_string()),
230 };
231
232 assert_eq!(metadata.name(), "github.com/gin-gonic/gin");
233 assert_eq!(metadata.latest_version(), "v1.9.1");
234 assert_eq!(metadata.description(), Some("Gin is a HTTP web framework"));
235 assert_eq!(
236 metadata.repository(),
237 Some("https://github.com/gin-gonic/gin")
238 );
239 assert_eq!(
240 metadata.documentation(),
241 Some("https://pkg.go.dev/github.com/gin-gonic/gin")
242 );
243 }
244
245 #[test]
246 fn test_go_directive_equality() {
247 assert_eq!(GoDirective::Require, GoDirective::Require);
248 assert_ne!(GoDirective::Require, GoDirective::Replace);
249 }
250}