feat(unstable/npm): deno info --json support for npm specifiers (#16472)

This commit is contained in:
David Sherret 2022-10-31 10:25:46 -04:00 committed by GitHub
parent c962cd4241
commit cb08b4683f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 330 additions and 9 deletions

View file

@ -38,7 +38,9 @@ pub async fn info(flags: Flags, info_flags: InfoFlags) -> Result<(), AnyError> {
let graph = ps.create_graph(vec![(specifier, ModuleKind::Esm)]).await?;
if info_flags.json {
display::write_json_to_stdout(&json!(graph))?;
let mut json_graph = json!(graph);
add_npm_packages_to_json(&mut json_graph, &ps.npm_resolver);
display::write_json_to_stdout(&json_graph)?;
} else {
let mut output = String::new();
GraphDisplayContext::write(&graph, &ps.npm_resolver, &mut output)?;
@ -128,6 +130,98 @@ fn print_cache_info(
}
}
fn add_npm_packages_to_json(
json: &mut serde_json::Value,
npm_resolver: &NpmPackageResolver,
) {
// ideally deno_graph could handle this, but for now we just modify the json here
let snapshot = npm_resolver.snapshot();
let json = json.as_object_mut().unwrap();
let modules = json.get_mut("modules").and_then(|m| m.as_array_mut());
if let Some(modules) = modules {
if modules.len() == 1
&& modules[0].get("kind").and_then(|k| k.as_str()) == Some("external")
{
// If there is only one module and it's "external", then that means
// someone provided an npm specifier as a cli argument. In this case,
// we want to show which npm package the cli argument resolved to.
let module = &mut modules[0];
let maybe_package = module
.get("specifier")
.and_then(|k| k.as_str())
.and_then(|specifier| NpmPackageReference::from_str(specifier).ok())
.and_then(|package_ref| {
snapshot
.resolve_package_from_deno_module(&package_ref.req)
.ok()
});
if let Some(pkg) = maybe_package {
if let Some(module) = module.as_object_mut() {
module.insert("npmPackage".to_string(), format!("{}", pkg.id).into());
// change the "kind" to be "npm"
module.insert("kind".to_string(), "npm".into());
}
}
} else {
// Filter out npm package references from the modules and instead
// have them only listed as dependencies. This is done because various
// npm specifiers modules in the graph are really just unresolved
// references. So there could be listed multiple npm specifiers
// that would resolve to a single npm package.
for i in (0..modules.len()).rev() {
if modules[i].get("kind").and_then(|k| k.as_str()) == Some("external") {
modules.remove(i);
}
}
}
for module in modules.iter_mut() {
let dependencies = module
.get_mut("dependencies")
.and_then(|d| d.as_array_mut());
if let Some(dependencies) = dependencies {
for dep in dependencies.iter_mut() {
if let serde_json::Value::Object(dep) = dep {
let specifier = dep.get("specifier").and_then(|s| s.as_str());
if let Some(specifier) = specifier {
if let Ok(npm_ref) = NpmPackageReference::from_str(specifier) {
if let Ok(pkg) =
snapshot.resolve_package_from_deno_module(&npm_ref.req)
{
dep.insert(
"npmPackage".to_string(),
format!("{}", pkg.id).into(),
);
}
}
}
}
}
}
}
}
let mut sorted_packages = snapshot.all_packages();
sorted_packages.sort_by(|a, b| a.id.cmp(&b.id));
let mut json_packages = serde_json::Map::with_capacity(sorted_packages.len());
for pkg in sorted_packages {
let mut kv = serde_json::Map::new();
kv.insert("name".to_string(), pkg.id.name.to_string().into());
kv.insert("version".to_string(), pkg.id.version.to_string().into());
let mut deps = pkg.dependencies.values().collect::<Vec<_>>();
deps.sort();
let deps = deps
.into_iter()
.map(|id| serde_json::Value::String(format!("{}", id)))
.collect::<Vec<_>>();
kv.insert("dependencies".to_string(), deps.into());
json_packages.insert(format!("{}", &pkg.id), kv.into());
}
json.insert("npmPackages".to_string(), json_packages.into());
}
struct TreeNode {
text: String,
children: Vec<TreeNode>,