1use std::any::Any;
4use tower_lsp_server::ls_types::Range;
5
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct DartDependency {
8 pub name: deps_core::PackageName,
9 pub name_range: Range,
10 pub version_req: Option<deps_core::VersionReq>,
11 pub version_range: Option<Range>,
12 pub section: DependencySection,
13 pub source: DependencySource,
14 pub git_path: Option<String>,
17}
18
19#[derive(Debug, Clone, PartialEq, Eq, Default)]
20pub enum DependencySection {
21 #[default]
22 Dependencies,
23 DevDependencies,
24 DependencyOverrides,
25}
26
27pub use deps_core::parser::DependencySource;
28
29#[derive(Debug, Clone)]
30pub struct DartVersion {
31 pub version: deps_core::ConcreteVersion,
32 pub retracted: bool,
33 pub published_at: Option<deps_core::PublishTime>,
39}
40
41#[derive(Debug, Clone)]
42pub struct PackageInfo {
43 pub name: deps_core::PackageName,
44 pub description: Option<String>,
45 pub homepage: Option<String>,
46 pub repository: Option<String>,
47 pub documentation: Option<String>,
48 pub version: deps_core::ConcreteVersion,
49 pub license: Option<String>,
50}
51
52impl deps_core::Dependency for DartDependency {
55 fn name(&self) -> &deps_core::PackageName {
56 &self.name
57 }
58
59 fn name_range(&self) -> Range {
60 self.name_range
61 }
62
63 fn version_requirement(&self) -> Option<&deps_core::VersionReq> {
64 self.version_req.as_ref()
65 }
66
67 fn version_range(&self) -> Option<Range> {
68 self.version_range
69 }
70
71 fn source(&self) -> deps_core::parser::DependencySource {
72 self.source.clone()
73 }
74
75 fn features(&self) -> &[String] {
76 &[]
77 }
78
79 fn as_any(&self) -> &dyn Any {
80 self
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87 use std::assert_matches;
88 use tower_lsp_server::ls_types::Position;
89
90 fn test_dep(source: DependencySource) -> DartDependency {
91 DartDependency {
92 name: "flutter_bloc".into(),
93 name_range: Range::new(Position::new(5, 2), Position::new(5, 14)),
94 version_req: Some("^8.1.0".into()),
95 version_range: Some(Range::new(Position::new(5, 16), Position::new(5, 22))),
96 section: DependencySection::Dependencies,
97 source,
98 git_path: None,
99 }
100 }
101
102 #[test]
103 fn test_dependency_source_variants() {
104 assert_matches!(DependencySource::Registry, DependencySource::Registry);
105 assert_matches!(
106 DependencySource::Git {
107 url: "u".into(),
108 rev: None
109 },
110 DependencySource::Git { .. }
111 );
112 assert_matches!(
113 DependencySource::Path { path: "p".into() },
114 DependencySource::Path { .. }
115 );
116 assert_matches!(
117 DependencySource::Sdk {
118 sdk: "flutter".into()
119 },
120 DependencySource::Sdk { .. }
121 );
122 }
123
124 #[test]
125 fn test_dependency_section_default() {
126 assert_matches!(
127 DependencySection::default(),
128 DependencySection::Dependencies
129 );
130 }
131
132 #[test]
133 fn test_dependency_trait() {
134 use deps_core::Dependency;
135
136 let dep = test_dep(DependencySource::Registry);
137 assert_eq!(dep.name(), "flutter_bloc");
138 assert_eq!(
139 dep.version_requirement().map(deps_core::VersionReq::as_str),
140 Some("^8.1.0")
141 );
142 assert!(dep.as_any().is::<DartDependency>());
143 }
144
145 #[test]
146 fn test_dependency_info_source_registry() {
147 use deps_core::Dependency;
148 let dep = test_dep(DependencySource::Registry);
149 assert!(dep.source().is_registry());
150 }
151
152 #[test]
153 fn test_dependency_info_source_sdk() {
154 use deps_core::Dependency;
155 let dep = test_dep(DependencySource::Sdk {
156 sdk: "flutter".into(),
157 });
158 assert!(!dep.source().is_registry());
159 assert_matches!(dep.source(), DependencySource::Sdk { sdk } if sdk == "flutter");
160 }
161
162 #[test]
163 fn test_dependency_info_source_git() {
164 use deps_core::Dependency;
165 let dep = test_dep(DependencySource::Git {
166 url: "https://github.com/test/repo".into(),
167 rev: Some("main".into()),
168 });
169 match dep.source() {
170 deps_core::parser::DependencySource::Git { url, rev } => {
171 assert_eq!(url, "https://github.com/test/repo");
172 assert_eq!(rev, Some("main".to_string()));
173 }
174 _ => panic!("Expected Git source"),
175 }
176 }
177
178 #[test]
179 fn test_dependency_info_source_path() {
180 use deps_core::Dependency;
181 let dep = test_dep(DependencySource::Path {
182 path: "../local".into(),
183 });
184 match dep.source() {
185 deps_core::parser::DependencySource::Path { path } => {
186 assert_eq!(path, "../local");
187 }
188 _ => panic!("Expected Path source"),
189 }
190 }
191
192 #[test]
193 fn test_version_trait() {
194 use deps_core::Version;
195 let ver = DartVersion {
196 version: "1.0.0".into(),
197 retracted: false,
198 published_at: Some(deps_core::PublishTime::from_unix_secs(1_704_067_200)),
199 };
200 assert_eq!(ver.version_string(), "1.0.0");
201 assert!(!ver.removal_status().blocks_resolution());
202 assert!(ver.features().is_empty());
203 assert!(ver.as_any().is::<DartVersion>());
204 }
205
206 #[test]
207 fn test_version_retracted() {
208 use deps_core::Version;
209 let ver = DartVersion {
210 version: "0.9.0".into(),
211 retracted: true,
212 published_at: None,
213 };
214 assert!(ver.removal_status().blocks_resolution());
215 }
216
217 #[test]
218 fn test_version_is_prerelease() {
219 use deps_core::Version;
220
221 let stable = DartVersion {
222 version: "1.0.0".into(),
223 retracted: false,
224 published_at: None,
225 };
226 let prerelease = DartVersion {
227 version: "2.10.0-nullsafety.1".into(),
228 retracted: false,
229 published_at: None,
230 };
231
232 assert!(!stable.is_prerelease());
233 assert!(stable.is_stable());
234 assert!(prerelease.is_prerelease());
235 assert!(!prerelease.is_stable());
236 }
237
238 #[test]
239 fn test_metadata_trait() {
240 use deps_core::Metadata;
241 let info = PackageInfo {
242 name: "provider".into(),
243 description: Some("A wrapper around InheritedWidget".into()),
244 homepage: Some("https://pub.dev/packages/provider".into()),
245 repository: Some("https://github.com/rrousselGit/provider".into()),
246 documentation: Some("https://pub.dev/documentation/provider".into()),
247 version: "6.1.2".into(),
248 license: Some("MIT".into()),
249 };
250 assert_eq!(info.name(), "provider");
251 assert!(info.description().is_some());
252 assert_eq!(info.latest_version(), "6.1.2");
253 assert!(info.as_any().is::<PackageInfo>());
254 }
255
256 #[test]
257 fn test_metadata_minimal() {
258 use deps_core::Metadata;
259 let info = PackageInfo {
260 name: "minimal".into(),
261 description: None,
262 homepage: None,
263 repository: None,
264 documentation: None,
265 version: "0.1.0".into(),
266 license: None,
267 };
268 assert!(info.description().is_none());
269 assert!(info.repository().is_none());
270 assert!(info.documentation().is_none());
271 }
272
273 #[test]
274 fn test_dependency_without_version() {
275 use deps_core::Dependency;
276 let dep = DartDependency {
277 name: "test".into(),
278 name_range: Range::default(),
279 version_req: None,
280 version_range: None,
281 section: DependencySection::Dependencies,
282 source: DependencySource::Registry,
283 git_path: None,
284 };
285 assert!(dep.version_requirement().is_none());
286 assert!(dep.version_range().is_none());
287 }
288}