normalize_package_index/index/
pub_dev.rs1use super::{IndexError, PackageIndex, PackageMeta, VersionMeta};
12
13pub struct Pub;
15
16impl Pub {
17 const API_BASE: &'static str = "https://pub.dev/api";
19}
20
21impl PackageIndex for Pub {
22 fn ecosystem(&self) -> &'static str {
23 "pub"
24 }
25
26 fn display_name(&self) -> &'static str {
27 "pub.dev (Dart/Flutter)"
28 }
29
30 fn fetch(&self, name: &str) -> Result<PackageMeta, IndexError> {
31 let url = format!("{}/packages/{}", Self::API_BASE, name);
32 let response: serde_json::Value = ureq::get(&url).call()?.into_json()?;
33
34 let latest = &response["latest"];
35 let pubspec = &latest["pubspec"];
36
37 Ok(PackageMeta {
38 name: response["name"].as_str().unwrap_or(name).to_string(),
39 version: latest["version"].as_str().unwrap_or("unknown").to_string(),
40 description: pubspec["description"].as_str().map(String::from),
41 homepage: pubspec["homepage"].as_str().map(String::from),
42 repository: pubspec["repository"].as_str().map(String::from),
43 license: None, binaries: Vec::new(),
45 keywords: Vec::new(), maintainers: pubspec["authors"]
47 .as_array()
48 .map(|a| {
49 a.iter()
50 .filter_map(|author| author.as_str().map(String::from))
51 .collect()
52 })
53 .unwrap_or_default(),
54 published: latest["published"].as_str().map(String::from),
55 downloads: None, archive_url: latest["archive_url"].as_str().map(String::from),
57 checksum: latest["archive_sha256"]
58 .as_str()
59 .map(|h| format!("sha256:{}", h)),
60 extra: Default::default(),
61 })
62 }
63
64 fn fetch_versions(&self, name: &str) -> Result<Vec<VersionMeta>, IndexError> {
65 let url = format!("{}/packages/{}", Self::API_BASE, name);
66 let response: serde_json::Value = ureq::get(&url).call()?.into_json()?;
67
68 let versions = response["versions"]
69 .as_array()
70 .ok_or_else(|| IndexError::NotFound(name.to_string()))?;
71
72 Ok(versions
73 .iter()
74 .filter_map(|v| {
75 Some(VersionMeta {
76 version: v["version"].as_str()?.to_string(),
77 released: v["published"].as_str().map(String::from),
78 yanked: v["retracted"].as_bool().unwrap_or(false),
79 })
80 })
81 .collect())
82 }
83
84 fn search(&self, query: &str) -> Result<Vec<PackageMeta>, IndexError> {
85 let url = format!("{}/search?q={}", Self::API_BASE, urlencoding::encode(query));
86 let response: serde_json::Value = ureq::get(&url).call()?.into_json()?;
87
88 let packages = response["packages"]
89 .as_array()
90 .ok_or_else(|| IndexError::Parse("missing packages".into()))?;
91
92 Ok(packages
95 .iter()
96 .take(50)
97 .filter_map(|pkg| {
98 Some(PackageMeta {
99 name: pkg["package"].as_str()?.to_string(),
100 version: "unknown".to_string(), description: None,
102 homepage: None,
103 repository: None,
104 license: None,
105 binaries: Vec::new(),
106 keywords: Vec::new(),
107 maintainers: Vec::new(),
108 published: None,
109 downloads: None,
110 archive_url: None,
111 checksum: None,
112 extra: Default::default(),
113 })
114 })
115 .collect())
116 }
117}