1use std::any::Any;
4use tower_lsp_server::ls_types::Range;
5
6#[derive(Debug, Clone, PartialEq, Eq)]
29pub struct DenoDependency {
30 pub name: deps_core::PackageName,
32 pub name_range: Range,
34 pub version_req: Option<deps_core::VersionReq>,
36 pub version_range: Option<Range>,
38 pub section: DenoDependencySection,
40}
41
42deps_core::impl_dependency!(DenoDependency {
43 name: name,
44 name_range: name_range,
45 version: version_req,
46 version_range: version_range,
47});
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum DenoDependencySection {
56 Imports,
58}
59
60#[derive(Debug, Clone)]
80pub struct JsrVersion {
81 pub version: deps_core::ConcreteVersion,
83 pub yanked: bool,
85 pub published_at: Option<deps_core::PublishTime>,
87}
88
89deps_core::impl_version!(JsrVersion {
94 version: version,
95 status: |v: &JsrVersion| deps_core::RemovalStatus::from_yanked(v.yanked),
96 published_at: published_at,
97 prerelease: |v: &JsrVersion| {
98 node_semver::Version::parse(v.version.as_str()).is_ok_and(|parsed| parsed.is_prerelease())
99 },
100});
101
102#[derive(Debug, Clone)]
123pub struct JsrPackage {
124 pub name: deps_core::PackageName,
126 pub description: Option<String>,
128 pub repository: Option<String>,
130 pub documentation: Option<String>,
133 pub latest_version: deps_core::ConcreteVersion,
135}
136
137deps_core::impl_metadata!(JsrPackage {
138 name: name,
139 description: description,
140 repository: repository,
141 documentation: documentation,
142 latest_version: latest_version,
143});
144
145pub struct DenoMetadata {
154 name: deps_core::PackageName,
155 inner: Box<dyn deps_core::Metadata>,
156}
157
158impl DenoMetadata {
159 #[must_use]
162 pub fn new(name: deps_core::PackageName, inner: Box<dyn deps_core::Metadata>) -> Self {
163 Self { name, inner }
164 }
165}
166
167impl deps_core::Metadata for DenoMetadata {
168 fn name(&self) -> &deps_core::PackageName {
169 &self.name
170 }
171
172 fn description(&self) -> Option<&str> {
173 self.inner.description()
174 }
175
176 fn repository(&self) -> Option<&str> {
177 self.inner.repository()
178 }
179
180 fn documentation(&self) -> Option<&str> {
181 self.inner.documentation()
182 }
183
184 fn latest_version(&self) -> &deps_core::ConcreteVersion {
185 self.inner.latest_version()
186 }
187
188 fn as_any(&self) -> &dyn Any {
189 self
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use super::*;
196 use deps_core::{Metadata, Version};
197 use tower_lsp_server::ls_types::Position;
198
199 #[test]
200 fn test_deno_dependency_creation() {
201 let dep = DenoDependency {
202 name: "jsr:@std/fs".into(),
203 name_range: Range::new(Position::new(0, 0), Position::new(0, 11)),
204 version_req: Some("^1.0".into()),
205 version_range: Some(Range::new(Position::new(0, 13), Position::new(0, 17))),
206 section: DenoDependencySection::Imports,
207 };
208
209 assert_eq!(dep.name, "jsr:@std/fs");
210 assert_eq!(dep.version_req, Some("^1.0".into()));
211 }
212
213 #[test]
214 fn test_jsr_version_trait() {
215 let version = JsrVersion {
216 version: "1.0.24".into(),
217 yanked: true,
218 published_at: None,
219 };
220
221 assert_eq!(version.version_string().as_str(), "1.0.24");
222 assert!(version.removal_status().blocks_resolution());
223 }
224
225 #[test]
226 fn test_jsr_version_is_prerelease() {
227 let stable = JsrVersion {
228 version: "1.0.24".into(),
229 yanked: false,
230 published_at: None,
231 };
232 let prerelease = JsrVersion {
233 version: "1.0.24-rc.1".into(),
234 yanked: false,
235 published_at: None,
236 };
237
238 assert!(!stable.is_prerelease());
239 assert!(stable.is_stable());
240 assert!(prerelease.is_prerelease());
241 assert!(!prerelease.is_stable());
242 }
243
244 #[test]
245 fn test_jsr_package_metadata_trait() {
246 let pkg = JsrPackage {
247 name: "jsr:@std/fs".into(),
248 description: Some("File system utilities".into()),
249 repository: Some("https://github.com/denoland/std".into()),
250 documentation: None,
251 latest_version: "1.0.24".into(),
252 };
253
254 assert_eq!(pkg.name(), "jsr:@std/fs");
255 assert_eq!(pkg.description(), Some("File system utilities"));
256 assert_eq!(pkg.repository(), Some("https://github.com/denoland/std"));
257 assert_eq!(pkg.documentation(), None);
258 assert_eq!(pkg.latest_version().as_str(), "1.0.24");
259 }
260
261 #[test]
262 fn test_deno_metadata_reprefixes_name_and_forwards_everything_else() {
263 struct Inner;
264 impl Metadata for Inner {
265 fn name(&self) -> &deps_core::PackageName {
266 static NAME: std::sync::LazyLock<deps_core::PackageName> =
267 std::sync::LazyLock::new(|| deps_core::PackageName::new("react"));
268 &NAME
269 }
270 fn description(&self) -> Option<&str> {
271 Some("A JS library")
272 }
273 fn repository(&self) -> Option<&str> {
274 Some("facebook/react")
275 }
276 fn documentation(&self) -> Option<&str> {
277 Some("https://react.dev")
278 }
279 fn latest_version(&self) -> &deps_core::ConcreteVersion {
280 static VERSION: std::sync::LazyLock<deps_core::ConcreteVersion> =
281 std::sync::LazyLock::new(|| deps_core::ConcreteVersion::new("18.3.1"));
282 &VERSION
283 }
284 fn as_any(&self) -> &dyn Any {
285 self
286 }
287 }
288
289 let wrapped = DenoMetadata::new(
290 deps_core::PackageName::new("npm:react"),
291 Box::new(Inner) as Box<dyn Metadata>,
292 );
293
294 assert_eq!(wrapped.name(), "npm:react");
295 assert_eq!(wrapped.description(), Some("A JS library"));
296 assert_eq!(wrapped.repository(), Some("facebook/react"));
297 assert_eq!(wrapped.documentation(), Some("https://react.dev"));
298 assert_eq!(wrapped.latest_version().as_str(), "18.3.1");
299 }
300}