aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/mozart-core/src/package.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/mozart-core/src/package.rs')
-rw-r--r--crates/mozart-core/src/package.rs228
1 files changed, 228 insertions, 0 deletions
diff --git a/crates/mozart-core/src/package.rs b/crates/mozart-core/src/package.rs
index 64974fd..0d5c482 100644
--- a/crates/mozart-core/src/package.rs
+++ b/crates/mozart-core/src/package.rs
@@ -686,6 +686,234 @@ pub fn read_from_file(path: &Path) -> anyhow::Result<RawPackageData> {
Ok(data)
}
+impl RootPackageData {
+ /// Mirrors `Composer\Package\Loader\RootPackageLoader::load()`:
+ /// converts the raw, untyped `RawPackageData` (the parsed-JSON form)
+ /// into the fully typed `RootPackageData`, applying field defaults and
+ /// constructing [`Link`] objects from the raw constraint strings.
+ pub fn from_raw(raw: RawPackageData) -> Self {
+ fn make_links(
+ source: &str,
+ deps: BTreeMap<String, String>,
+ description: &str,
+ ) -> BTreeMap<String, Link> {
+ deps.into_iter()
+ .map(|(target, constraint)| {
+ let normalized = target.to_lowercase();
+ let link = Link {
+ source: source.to_string(),
+ target: normalized.clone(),
+ constraint,
+ pretty_constraint: None,
+ description: description.to_string(),
+ };
+ (normalized, link)
+ })
+ .collect()
+ }
+
+ let pretty_name = raw.name.clone();
+ let name = raw.name.to_lowercase();
+
+ let pretty_version = raw
+ .version
+ .unwrap_or_else(|| "1.0.0+no-version-set".to_string());
+ let version = pretty_version.clone();
+
+ let package_type = raw
+ .package_type
+ .map(|t| t.to_lowercase())
+ .unwrap_or_else(|| "library".to_string());
+
+ let requires = make_links(&name, raw.require, "requires");
+ let dev_requires = make_links(&name, raw.require_dev, "requires (for development)");
+ let conflicts = make_links(&name, raw.conflict, "conflicts");
+ let provides = make_links(&name, raw.provide, "provides");
+ let replaces = make_links(&name, raw.replace, "replaces");
+
+ let autoload = raw
+ .autoload
+ .map(|a| AutoloadRules {
+ psr4: a
+ .psr4
+ .into_iter()
+ .map(|(ns, path)| (ns, vec![path]))
+ .collect(),
+ ..Default::default()
+ })
+ .unwrap_or_default();
+
+ let extra: BTreeMap<String, serde_json::Value> = raw
+ .extra_fields
+ .get("extra")
+ .and_then(|v| v.as_object())
+ .map(|obj| obj.iter().map(|(k, v)| (k.clone(), v.clone())).collect())
+ .unwrap_or_default();
+
+ let license = raw.license.into_iter().collect();
+
+ let authors = raw
+ .authors
+ .into_iter()
+ .map(|a| Author {
+ name: Some(a.name),
+ email: a.email,
+ homepage: None,
+ role: None,
+ })
+ .collect();
+
+ let repositories = raw
+ .repositories
+ .into_iter()
+ .filter_map(|r| serde_json::to_value(r).ok())
+ .collect();
+
+ let keywords = raw
+ .extra_fields
+ .get("keywords")
+ .and_then(|v| v.as_array())
+ .map(|arr| {
+ arr.iter()
+ .filter_map(|v| v.as_str())
+ .map(String::from)
+ .collect()
+ })
+ .unwrap_or_default();
+
+ let scripts: BTreeMap<String, Vec<String>> = raw
+ .extra_fields
+ .get("scripts")
+ .and_then(|v| v.as_object())
+ .map(|obj| {
+ obj.iter()
+ .map(|(k, v)| {
+ let handlers = match v {
+ serde_json::Value::String(s) => vec![s.clone()],
+ serde_json::Value::Array(arr) => arr
+ .iter()
+ .filter_map(|x| x.as_str())
+ .map(String::from)
+ .collect(),
+ _ => vec![],
+ };
+ (k.clone(), handlers)
+ })
+ .collect()
+ })
+ .unwrap_or_default();
+
+ let support = raw
+ .extra_fields
+ .get("support")
+ .and_then(|v| v.as_object())
+ .map(|obj| {
+ let get_str = |key: &str| obj.get(key).and_then(|v| v.as_str()).map(String::from);
+ Support {
+ email: get_str("email"),
+ issues: get_str("issues"),
+ forum: get_str("forum"),
+ wiki: get_str("wiki"),
+ source: get_str("source"),
+ docs: get_str("docs"),
+ irc: get_str("irc"),
+ chat: get_str("chat"),
+ rss: get_str("rss"),
+ security: get_str("security"),
+ }
+ })
+ .unwrap_or_default();
+
+ let funding = raw
+ .extra_fields
+ .get("funding")
+ .and_then(|v| v.as_array())
+ .map(|arr| {
+ arr.iter()
+ .filter_map(|v| v.as_object())
+ .map(|obj| Funding {
+ url: obj.get("url").and_then(|v| v.as_str()).map(String::from),
+ funding_type: obj.get("type").and_then(|v| v.as_str()).map(String::from),
+ })
+ .collect()
+ })
+ .unwrap_or_default();
+
+ let config: BTreeMap<String, serde_json::Value> = raw
+ .extra_fields
+ .get("config")
+ .and_then(|v| v.as_object())
+ .map(|obj| obj.iter().map(|(k, v)| (k.clone(), v.clone())).collect())
+ .unwrap_or_default();
+
+ let prefer_stable = raw
+ .extra_fields
+ .get("prefer-stable")
+ .and_then(|v| v.as_bool())
+ .unwrap_or(false);
+
+ let minimum_stability =
+ Stability::parse(raw.minimum_stability.as_deref().unwrap_or("stable"));
+
+ let package_data = PackageData {
+ name,
+ pretty_name,
+ version,
+ pretty_version,
+ package_type,
+ target_dir: None,
+ source_type: None,
+ source_url: None,
+ source_reference: None,
+ dist_type: None,
+ dist_url: None,
+ dist_reference: None,
+ dist_sha1_checksum: None,
+ release_date: None,
+ extra,
+ binaries: raw.bin,
+ dev: false,
+ stability: Stability::Stable,
+ notification_url: None,
+ requires,
+ conflicts,
+ provides,
+ replaces,
+ dev_requires,
+ suggests: BTreeMap::new(),
+ autoload,
+ dev_autoload: AutoloadRules::default(),
+ is_default_branch: false,
+ };
+
+ let complete_data = CompletePackageData {
+ package: package_data,
+ description: raw.description,
+ homepage: raw.homepage,
+ license,
+ keywords,
+ authors,
+ scripts,
+ support,
+ funding,
+ repositories,
+ abandoned: None,
+ archive_name: None,
+ archive_excludes: Vec::new(),
+ };
+
+ RootPackageData {
+ complete: complete_data,
+ minimum_stability,
+ prefer_stable,
+ stability_flags: BTreeMap::new(),
+ config,
+ references: BTreeMap::new(),
+ aliases: Vec::new(),
+ }
+ }
+}
+
pub fn to_json_pretty(value: &impl Serialize) -> serde_json::Result<String> {
let formatter = serde_json::ser::PrettyFormatter::with_indent(b" ");
let mut buf = Vec::new();