1use indexmap::IndexMap;
4use miette::{Diagnostic, SourceSpan};
5use wac_parser::Document;
6
7mod fs;
8#[cfg(feature = "registry")]
9mod registry;
10mod visitor;
11
12pub use fs::*;
13#[cfg(feature = "registry")]
14pub use registry::*;
15pub use visitor::*;
16use wac_types::BorrowedPackageKey;
17
18#[derive(thiserror::Error, Diagnostic, Debug)]
20#[diagnostic(code("failed to resolve document"))]
21pub enum Error {
22 #[error("failed to create registry client: {0:#}")]
24 RegistryClientFailed(anyhow::Error),
25 #[error("unknown package `{name}`")]
27 UnknownPackage {
28 name: String,
30 #[label(primary, "unknown package `{name}`")]
32 span: SourceSpan,
33 },
34 #[error("invalid package name `{name}`")]
36 InvalidPackageName {
37 name: String,
39 #[label(primary, "invalid package name `{name}`")]
41 span: SourceSpan,
42 },
43 #[cfg(feature = "registry")]
45 #[error("version {version} of package `{name}` does not exist")]
46 UnknownPackageVersion {
47 name: String,
49 version: semver::Version,
51 #[label(primary, "unknown package version `{version}`")]
53 span: SourceSpan,
54 },
55 #[error("cannot instantiate the package being defined")]
57 CannotInstantiateSelf {
58 #[label(primary, "cannot instantiate self")]
60 span: SourceSpan,
61 },
62 #[error("package `{name}` does not exist in the registry")]
64 PackageDoesNotExist {
65 name: String,
67 #[label(primary, "package `{name}` does not exist")]
69 span: SourceSpan,
70 },
71 #[cfg(feature = "registry")]
73 #[error("version {version} of package `{name}` does not exist")]
74 PackageVersionDoesNotExist {
75 name: String,
77 version: semver::Version,
79 #[label(primary, "{version} does not exist")]
81 span: SourceSpan,
82 },
83 #[cfg(feature = "registry")]
85 #[error("package `{name}` has no releases")]
86 PackageNoReleases {
87 name: String,
89 #[label(primary, "package `{name}` has no releases")]
91 span: SourceSpan,
92 },
93 #[cfg(feature = "registry")]
95 #[error("failed to update registry logs")]
96 RegistryUpdateFailure {
97 #[source]
99 source: anyhow::Error,
100 },
101 #[cfg(feature = "registry")]
103 #[error("failed to download content from the registry")]
104 RegistryDownloadFailure {
105 #[source]
107 source: anyhow::Error,
108 },
109 #[cfg(feature = "registry")]
111 #[error("failed to read content path `{path}`", path = .path.display())]
112 RegistryContentFailure {
113 path: std::path::PathBuf,
115 #[source]
117 source: anyhow::Error,
118 },
119 #[error("failed to resolve package `{name}`")]
121 PackageResolutionFailure {
122 name: String,
124 #[label(primary, "package `{name}` failed to resolve")]
126 span: SourceSpan,
127 #[source]
129 source: anyhow::Error,
130 },
131}
132
133pub fn packages<'a>(
136 document: &'a Document<'a>,
137) -> Result<IndexMap<BorrowedPackageKey<'a>, SourceSpan>, Error> {
138 let mut keys = IndexMap::new();
139 let mut visitor = PackageVisitor::new(|name, version, span| {
140 if name == document.directive.package.name {
141 return true;
142 }
143
144 if keys
145 .insert(
146 BorrowedPackageKey::from_name_and_version(name, version),
147 span,
148 )
149 .is_none()
150 {
151 if let Some(version) = version {
152 log::debug!("discovered reference to package `{name}` ({version})");
153 } else {
154 log::debug!("discovered reference to package `{name}`");
155 }
156 }
157
158 true
159 });
160
161 visitor.visit(document)?;
162 Ok(keys)
163}