diff options
-rw-r--r-- | cli/tests/integration/npm_tests.rs | 37 | ||||
-rw-r--r-- | cli/tests/testdata/info/076_info_json_deps_order.out | 3 | ||||
-rw-r--r-- | cli/tests/testdata/info/json_output/main.out | 3 | ||||
-rw-r--r-- | cli/tests/testdata/npm/cjs_with_deps/main_info.out (renamed from cli/tests/testdata/npm/cjs_with_deps/main.info.out) | 0 | ||||
-rw-r--r-- | cli/tests/testdata/npm/cjs_with_deps/main_info_json.out | 146 | ||||
-rw-r--r-- | cli/tests/testdata/npm/info/chalk.out (renamed from cli/tests/testdata/npm/deno_info_chalk.out) | 0 | ||||
-rw-r--r-- | cli/tests/testdata/npm/info/chalk_json.out | 54 | ||||
-rw-r--r-- | cli/tools/info.rs | 96 |
8 files changed, 330 insertions, 9 deletions
diff --git a/cli/tests/integration/npm_tests.rs b/cli/tests/integration/npm_tests.rs index 0ca1ae910..714fe25d4 100644 --- a/cli/tests/integration/npm_tests.rs +++ b/cli/tests/integration/npm_tests.rs @@ -733,26 +733,51 @@ itest!(compile_errors { http_server: true, }); -itest!(info_chalk { +itest!(info_chalk_display { args: "info --quiet --unstable npm/cjs_with_deps/main.js", - output: "npm/cjs_with_deps/main.info.out", + output: "npm/cjs_with_deps/main_info.out", exit_code: 0, envs: env_vars(), http_server: true, }); -itest!(info_chalk_node_modules_dir { +itest!(info_chalk_display_node_modules_dir { args: "info --quiet --unstable --node-modules-dir $TESTDATA/npm/cjs_with_deps/main.js", - output: "npm/cjs_with_deps/main.info.out", + output: "npm/cjs_with_deps/main_info.out", exit_code: 0, envs: env_vars(), http_server: true, temp_cwd: true, }); -itest!(info_cli_chalk { +itest!(info_chalk_json { + args: "info --quiet --unstable --json npm/cjs_with_deps/main.js", + output: "npm/cjs_with_deps/main_info_json.out", + exit_code: 0, + envs: env_vars(), + http_server: true, +}); + +itest!(info_chalk_json_node_modules_dir { + args: "info --quiet --unstable --node-modules-dir --json $TESTDATA/npm/cjs_with_deps/main.js", + output: "npm/cjs_with_deps/main_info_json.out", + exit_code: 0, + envs: env_vars(), + http_server: true, + temp_cwd: true, +}); + +itest!(info_cli_chalk_display { args: "info --quiet --unstable npm:chalk@4", - output: "npm/deno_info_chalk.out", + output: "npm/info/chalk.out", + exit_code: 0, + envs: env_vars(), + http_server: true, +}); + +itest!(info_cli_chalk_json { + args: "info --quiet --unstable --json npm:chalk@4", + output: "npm/info/chalk_json.out", exit_code: 0, envs: env_vars(), http_server: true, diff --git a/cli/tests/testdata/info/076_info_json_deps_order.out b/cli/tests/testdata/info/076_info_json_deps_order.out index db890ef02..98b5d5d50 100644 --- a/cli/tests/testdata/info/076_info_json_deps_order.out +++ b/cli/tests/testdata/info/076_info_json_deps_order.out @@ -159,5 +159,6 @@ "specifier": "file://[WILDCARD]/recursive_imports/common.ts" } ], - "redirects": {} + "redirects": {}, + "npmPackages": {} } diff --git a/cli/tests/testdata/info/json_output/main.out b/cli/tests/testdata/info/json_output/main.out index 124fc7351..aaef028c0 100644 --- a/cli/tests/testdata/info/json_output/main.out +++ b/cli/tests/testdata/info/json_output/main.out @@ -86,5 +86,6 @@ "specifier": "file://[WILDCARD]/subdir/subdir2/mod2.ts" } ], - "redirects": {} + "redirects": {}, + "npmPackages": {} } diff --git a/cli/tests/testdata/npm/cjs_with_deps/main.info.out b/cli/tests/testdata/npm/cjs_with_deps/main_info.out index 345583a90..345583a90 100644 --- a/cli/tests/testdata/npm/cjs_with_deps/main.info.out +++ b/cli/tests/testdata/npm/cjs_with_deps/main_info.out diff --git a/cli/tests/testdata/npm/cjs_with_deps/main_info_json.out b/cli/tests/testdata/npm/cjs_with_deps/main_info_json.out new file mode 100644 index 000000000..bc7b9e162 --- /dev/null +++ b/cli/tests/testdata/npm/cjs_with_deps/main_info_json.out @@ -0,0 +1,146 @@ +{ + "roots": [ + "file://[WILDCARD]/main.js" + ], + "modules": [ + { + "dependencies": [ + { + "specifier": "npm:chai@4.3", + "code": { + "specifier": "npm:chai@4.3", + "span": { + "start": { + "line": 1, + "character": 23 + }, + "end": { + "line": 1, + "character": 37 + } + } + }, + "npmPackage": "chai@4.3.6" + }, + { + "specifier": "npm:chalk@4", + "code": { + "specifier": "npm:chalk@4", + "span": { + "start": { + "line": 0, + "character": 18 + }, + "end": { + "line": 0, + "character": 31 + } + } + }, + "npmPackage": "chalk@4.1.2" + } + ], + "kind": "esm", + "local": "[WILDCARD]main.js", + "emit": null, + "map": null, + "size": 325, + "mediaType": "JavaScript", + "specifier": "[WILDCARD]/main.js" + } + ], + "redirects": {}, + "npmPackages": { + "ansi-styles@4.3.0": { + "name": "ansi-styles", + "version": "4.3.0", + "dependencies": [ + "color-convert@2.0.1" + ] + }, + "assertion-error@1.1.0": { + "name": "assertion-error", + "version": "1.1.0", + "dependencies": [] + }, + "chai@4.3.6": { + "name": "chai", + "version": "4.3.6", + "dependencies": [ + "assertion-error@1.1.0", + "check-error@1.0.2", + "deep-eql@3.0.1", + "get-func-name@2.0.0", + "loupe@2.3.4", + "pathval@1.1.1", + "type-detect@4.0.8" + ] + }, + "chalk@4.1.2": { + "name": "chalk", + "version": "4.1.2", + "dependencies": [ + "ansi-styles@4.3.0", + "supports-color@7.2.0" + ] + }, + "check-error@1.0.2": { + "name": "check-error", + "version": "1.0.2", + "dependencies": [] + }, + "color-convert@2.0.1": { + "name": "color-convert", + "version": "2.0.1", + "dependencies": [ + "color-name@1.1.4" + ] + }, + "color-name@1.1.4": { + "name": "color-name", + "version": "1.1.4", + "dependencies": [] + }, + "deep-eql@3.0.1": { + "name": "deep-eql", + "version": "3.0.1", + "dependencies": [ + "type-detect@4.0.8" + ] + }, + "get-func-name@2.0.0": { + "name": "get-func-name", + "version": "2.0.0", + "dependencies": [] + }, + "has-flag@4.0.0": { + "name": "has-flag", + "version": "4.0.0", + "dependencies": [] + }, + "loupe@2.3.4": { + "name": "loupe", + "version": "2.3.4", + "dependencies": [ + "get-func-name@2.0.0" + ] + }, + "pathval@1.1.1": { + "name": "pathval", + "version": "1.1.1", + "dependencies": [] + }, + "supports-color@7.2.0": { + "name": "supports-color", + "version": "7.2.0", + "dependencies": [ + "has-flag@4.0.0" + ] + }, + "type-detect@4.0.8": { + "name": "type-detect", + "version": "4.0.8", + "dependencies": [] + } + } +} diff --git a/cli/tests/testdata/npm/deno_info_chalk.out b/cli/tests/testdata/npm/info/chalk.out index 89ea05e71..89ea05e71 100644 --- a/cli/tests/testdata/npm/deno_info_chalk.out +++ b/cli/tests/testdata/npm/info/chalk.out diff --git a/cli/tests/testdata/npm/info/chalk_json.out b/cli/tests/testdata/npm/info/chalk_json.out new file mode 100644 index 000000000..f6673d032 --- /dev/null +++ b/cli/tests/testdata/npm/info/chalk_json.out @@ -0,0 +1,54 @@ +{ + "roots": [ + "npm:chalk@4" + ], + "modules": [ + { + "kind": "npm", + "specifier": "npm:chalk@4", + "npmPackage": "chalk@4.1.2" + } + ], + "redirects": {}, + "npmPackages": { + "ansi-styles@4.3.0": { + "name": "ansi-styles", + "version": "4.3.0", + "dependencies": [ + "color-convert@2.0.1" + ] + }, + "chalk@4.1.2": { + "name": "chalk", + "version": "4.1.2", + "dependencies": [ + "ansi-styles@4.3.0", + "supports-color@7.2.0" + ] + }, + "color-convert@2.0.1": { + "name": "color-convert", + "version": "2.0.1", + "dependencies": [ + "color-name@1.1.4" + ] + }, + "color-name@1.1.4": { + "name": "color-name", + "version": "1.1.4", + "dependencies": [] + }, + "has-flag@4.0.0": { + "name": "has-flag", + "version": "4.0.0", + "dependencies": [] + }, + "supports-color@7.2.0": { + "name": "supports-color", + "version": "7.2.0", + "dependencies": [ + "has-flag@4.0.0" + ] + } + } +} diff --git a/cli/tools/info.rs b/cli/tools/info.rs index e45958b34..12b1ae4c3 100644 --- a/cli/tools/info.rs +++ b/cli/tools/info.rs @@ -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>, |