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