summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmmanuel <implicitdef@users.noreply.github.com>2020-07-08 16:50:12 +0200
committerGitHub <noreply@github.com>2020-07-08 10:50:12 -0400
commitcbbd9443592f79f6abf9e5019840de4e01ff8580 (patch)
treebb8c626e95db2ec103de4dcbeb5ec29b65e49aff
parenta2bf61d1ae3ba2ff746a98ad2f0a96b6fc7782d0 (diff)
feat(cli): json option for "deno info" (#6372)
-rw-r--r--cli/flags.rs41
-rw-r--r--cli/main.rs161
-rw-r--r--cli/tests/055_info_file_json.out25
-rw-r--r--cli/tests/info_json.out5
-rw-r--r--cli/tests/integration_tests.rs11
-rw-r--r--core/lib.rs1
-rw-r--r--core/modules.rs60
7 files changed, 212 insertions, 92 deletions
diff --git a/cli/flags.rs b/cli/flags.rs
index eb98c6032..313d8ff1a 100644
--- a/cli/flags.rs
+++ b/cli/flags.rs
@@ -41,6 +41,7 @@ pub enum DenoSubcommand {
},
Help,
Info {
+ json: bool,
file: Option<String>,
},
Install {
@@ -454,10 +455,11 @@ fn eval_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
fn info_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
ca_file_arg_parse(flags, matches);
unstable_arg_parse(flags, matches);
+ let json = matches.is_present("json");
no_check_arg_parse(flags, matches);
-
flags.subcommand = DenoSubcommand::Info {
file: matches.value_of("file").map(|f| f.to_string()),
+ json,
};
}
@@ -824,6 +826,12 @@ TypeScript compiler cache: Subdirectory containing TS compiler output.",
.arg(ca_file_arg())
.arg(no_check_arg())
.arg(unstable_arg())
+ .arg(
+ Arg::with_name("json")
+ .long("json")
+ .help("Outputs the information in JSON format")
+ .takes_value(false),
+ )
}
fn cache_subcommand<'a, 'b>() -> App<'a, 'b> {
@@ -1784,6 +1792,19 @@ mod tests {
r.unwrap(),
Flags {
subcommand: DenoSubcommand::Info {
+ json: false,
+ file: Some("script.ts".to_string()),
+ },
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec_safe(svec!["deno", "info", "--json", "script.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Info {
+ json: true,
file: Some("script.ts".to_string()),
},
..Flags::default()
@@ -1794,7 +1815,22 @@ mod tests {
assert_eq!(
r.unwrap(),
Flags {
- subcommand: DenoSubcommand::Info { file: None },
+ subcommand: DenoSubcommand::Info {
+ json: false,
+ file: None
+ },
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec_safe(svec!["deno", "info", "--json"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Info {
+ json: true,
+ file: None
+ },
..Flags::default()
}
);
@@ -2790,6 +2826,7 @@ mod tests {
r.unwrap(),
Flags {
subcommand: DenoSubcommand::Info {
+ json: false,
file: Some("https://example.com".to_string()),
},
ca_file: Some("example.crt".to_owned()),
diff --git a/cli/main.rs b/cli/main.rs
index 5c54a87ca..5a40a0da2 100644
--- a/cli/main.rs
+++ b/cli/main.rs
@@ -81,6 +81,7 @@ use crate::permissions::Permissions;
use crate::tsc::TargetLib;
use crate::worker::MainWorker;
use deno_core::v8_set_flags;
+use deno_core::Deps;
use deno_core::ErrBox;
use deno_core::EsIsolate;
use deno_core::ModuleSpecifier;
@@ -91,6 +92,7 @@ use futures::Future;
use log::Level;
use log::Metadata;
use log::Record;
+use state::exit_unstable;
use std::env;
use std::io::Read;
use std::io::Write;
@@ -140,22 +142,47 @@ fn write_to_stdout_ignore_sigpipe(bytes: &[u8]) -> Result<(), std::io::Error> {
}
}
-fn print_cache_info(state: &GlobalState) {
- println!(
- "{} {:?}",
- colors::bold("DENO_DIR location:"),
- state.dir.root
- );
- println!(
- "{} {:?}",
- colors::bold("Remote modules cache:"),
- state.file_fetcher.http_cache.location
- );
- println!(
- "{} {:?}",
- colors::bold("TypeScript compiler cache:"),
- state.dir.gen_cache.location
- );
+fn write_json_to_stdout<T>(value: &T) -> Result<(), ErrBox>
+where
+ T: ?Sized + serde::ser::Serialize,
+{
+ let writer = std::io::BufWriter::new(std::io::stdout());
+ serde_json::to_writer_pretty(writer, value).map_err(ErrBox::from)
+}
+
+fn print_cache_info(state: &GlobalState, json: bool) -> Result<(), ErrBox> {
+ let deno_dir = &state.dir.root;
+ let modules_cache = &state.file_fetcher.http_cache.location;
+ let typescript_cache = &state.dir.gen_cache.location;
+ if json {
+ let output = json!({
+ "denoDir": deno_dir,
+ "modulesCache": modules_cache,
+ "typescriptCache": typescript_cache,
+ });
+ write_json_to_stdout(&output)
+ } else {
+ println!("{} {:?}", colors::bold("DENO_DIR location:"), deno_dir);
+ println!(
+ "{} {:?}",
+ colors::bold("Remote modules cache:"),
+ modules_cache
+ );
+ println!(
+ "{} {:?}",
+ colors::bold("TypeScript compiler cache:"),
+ typescript_cache
+ );
+ Ok(())
+ }
+}
+
+struct FileInfoOutput<'a> {
+ local: &'a str,
+ file_type: &'a str,
+ compiled: Option<String>,
+ map: Option<String>,
+ deps: Option<Deps>,
}
// TODO(bartlomieju): this function de facto repeats
@@ -163,6 +190,7 @@ fn print_cache_info(state: &GlobalState) {
async fn print_file_info(
worker: &MainWorker,
module_specifier: ModuleSpecifier,
+ json: bool,
) -> Result<(), ErrBox> {
let global_state = worker.state.borrow().global_state.clone();
@@ -171,17 +199,13 @@ async fn print_file_info(
.fetch_source_file(&module_specifier, None, Permissions::allow_all())
.await?;
- println!(
- "{} {}",
- colors::bold("local:"),
- out.filename.to_str().unwrap()
- );
-
- println!(
- "{} {}",
- colors::bold("type:"),
- msg::enum_name_media_type(out.media_type)
- );
+ let mut output = FileInfoOutput {
+ local: out.filename.to_str().unwrap(),
+ file_type: msg::enum_name_media_type(out.media_type),
+ compiled: None,
+ map: None,
+ deps: None,
+ };
let module_specifier_ = module_specifier.clone();
@@ -208,12 +232,8 @@ async fn print_file_info(
.ts_compiler
.get_compiled_source_file(&out.url)
.unwrap();
-
- println!(
- "{} {}",
- colors::bold("compiled:"),
- compiled_source_file.filename.to_str().unwrap(),
- );
+ output.compiled =
+ compiled_source_file.filename.to_str().map(|s| s.to_owned());
}
if let Ok(source_map) = global_state
@@ -221,31 +241,48 @@ async fn print_file_info(
.ts_compiler
.get_source_map_file(&module_specifier)
{
- println!(
- "{} {}",
- colors::bold("map:"),
- source_map.filename.to_str().unwrap()
- );
+ output.map = source_map.filename.to_str().map(|s| s.to_owned());
}
-
let es_state_rc = EsIsolate::state(&worker.isolate);
let es_state = es_state_rc.borrow();
if let Some(deps) = es_state.modules.deps(&module_specifier) {
- println!("{}{}", colors::bold("deps:\n"), deps.name);
- if let Some(ref depsdeps) = deps.deps {
- for d in depsdeps {
- println!("{}", d);
+ output.deps = Some(deps);
+ }
+
+ if json {
+ let output = json!({
+ "local": output.local,
+ "fileType": output.file_type,
+ "compiled": output.compiled,
+ "map": output.map,
+ "deps": output.deps.map(|x| x.to_json())
+ });
+ write_json_to_stdout(&output)
+ } else {
+ println!("{} {}", colors::bold("local:"), output.local);
+ println!("{} {}", colors::bold("type:"), output.file_type);
+ if let Some(compiled) = output.compiled {
+ println!("{} {}", colors::bold("compiled:"), compiled);
+ }
+ if let Some(map) = output.map {
+ println!("{} {}", colors::bold("map:"), map);
+ }
+ if let Some(deps) = output.deps {
+ println!("{}{}", colors::bold("deps:\n"), deps.name);
+ if let Some(ref depsdeps) = deps.deps {
+ for d in depsdeps {
+ println!("{}", d);
+ }
}
+ } else {
+ println!(
+ "{} cannot retrieve full dependency graph",
+ colors::bold("deps:"),
+ );
}
- } else {
- println!(
- "{} cannot retrieve full dependency graph",
- colors::bold("deps:"),
- );
+ Ok(())
}
-
- Ok(())
}
fn get_types(unstable: bool) -> String {
@@ -270,18 +307,21 @@ fn get_types(unstable: bool) -> String {
async fn info_command(
flags: Flags,
file: Option<String>,
+ json: bool,
) -> Result<(), ErrBox> {
+ if json && !flags.unstable {
+ exit_unstable("--json");
+ }
let global_state = GlobalState::new(flags)?;
// If it was just "deno info" print location of caches and exit
if file.is_none() {
- print_cache_info(&global_state);
- return Ok(());
+ print_cache_info(&global_state, json)
+ } else {
+ let main_module = ModuleSpecifier::resolve_url_or_path(&file.unwrap())?;
+ let mut worker = MainWorker::create(global_state, main_module.clone())?;
+ worker.preload_module(&main_module).await?;
+ print_file_info(&worker, main_module.clone(), json).await
}
-
- let main_module = ModuleSpecifier::resolve_url_or_path(&file.unwrap())?;
- let mut worker = MainWorker::create(global_state, main_module.clone())?;
- worker.preload_module(&main_module).await?;
- print_file_info(&worker, main_module.clone()).await
}
async fn install_command(
@@ -525,8 +565,7 @@ async fn doc_command(
};
if json {
- let writer = std::io::BufWriter::new(std::io::stdout());
- serde_json::to_writer_pretty(writer, &doc_nodes).map_err(ErrBox::from)
+ write_json_to_stdout(&doc_nodes)
} else {
let details = if let Some(filter) = maybe_filter {
let nodes =
@@ -691,7 +730,9 @@ pub fn main() {
DenoSubcommand::Fmt { check, files } => {
fmt::format(files, check).boxed_local()
}
- DenoSubcommand::Info { file } => info_command(flags, file).boxed_local(),
+ DenoSubcommand::Info { file, json } => {
+ info_command(flags, file, json).boxed_local()
+ }
DenoSubcommand::Install {
module_url,
args,
diff --git a/cli/tests/055_info_file_json.out b/cli/tests/055_info_file_json.out
new file mode 100644
index 000000000..20bf94f3f
--- /dev/null
+++ b/cli/tests/055_info_file_json.out
@@ -0,0 +1,25 @@
+{
+ "local": "[WILDCARD]005_more_imports.ts",
+ "fileType": "TypeScript",
+ "compiled": "[WILDCARD]005_more_imports.ts.js",
+ "map": null,
+ "deps": [
+ "file://[WILDCARD]/005_more_imports.ts",
+ [
+ [
+ "file://[WILDCARD]/subdir/mod1.ts",
+ [
+ [
+ "file://[WILDCARD]/subdir/subdir2/mod2.ts",
+ [
+ [
+ "file://[WILDCARD]/subdir/print_hello.ts",
+ []
+ ]
+ ]
+ ]
+ ]
+ ]
+ ]
+ ]
+} \ No newline at end of file
diff --git a/cli/tests/info_json.out b/cli/tests/info_json.out
new file mode 100644
index 000000000..361728a7b
--- /dev/null
+++ b/cli/tests/info_json.out
@@ -0,0 +1,5 @@
+{
+ "denoDir": "[WILDCARD]",
+ "modulesCache": "[WILDCARD]deps",
+ "typescriptCache": "[WILDCARD]gen"
+} \ No newline at end of file
diff --git a/cli/tests/integration_tests.rs b/cli/tests/integration_tests.rs
index 9acb4ed3f..87a6f9d63 100644
--- a/cli/tests/integration_tests.rs
+++ b/cli/tests/integration_tests.rs
@@ -1499,6 +1499,11 @@ itest!(_041_info_flag {
output: "041_info_flag.out",
});
+itest!(info_json {
+ args: "info --json --unstable",
+ output: "info_json.out",
+});
+
itest!(_042_dyn_import_evalcontext {
args: "run --quiet --allow-read --reload 042_dyn_import_evalcontext.ts",
output: "042_dyn_import_evalcontext.ts.out",
@@ -1552,6 +1557,12 @@ itest!(_054_info_local_imports {
exit_code: 0,
});
+itest!(_055_info_file_json {
+ args: "info --quiet --json --unstable 005_more_imports.ts",
+ output: "055_info_file_json.out",
+ exit_code: 0,
+});
+
itest!(_056_make_temp_file_write_perm {
args:
"run --quiet --allow-read --allow-write=./subdir/ 056_make_temp_file_write_perm.ts",
diff --git a/core/lib.rs b/core/lib.rs
index 47ded645e..7358af1c4 100644
--- a/core/lib.rs
+++ b/core/lib.rs
@@ -36,6 +36,7 @@ pub use crate::es_isolate::EsIsolateState;
pub use crate::flags::v8_set_flags;
pub use crate::module_specifier::ModuleResolutionError;
pub use crate::module_specifier::ModuleSpecifier;
+pub use crate::modules::Deps;
pub use crate::modules::ModuleId;
pub use crate::modules::ModuleLoadId;
pub use crate::modules::ModuleLoader;
diff --git a/core/modules.rs b/core/modules.rs
index ca850d0bb..58ad767b9 100644
--- a/core/modules.rs
+++ b/core/modules.rs
@@ -484,20 +484,14 @@ impl Deps {
}
}
- pub fn to_json(&self) -> String {
- let mut children = "[".to_string();
-
- if let Some(ref deps) = self.deps {
- for d in deps {
- children.push_str(&d.to_json());
- if !d.is_last {
- children.push_str(",");
- }
- }
+ pub fn to_json(&self) -> serde_json::Value {
+ let children;
+ if let Some(deps) = &self.deps {
+ children = deps.iter().map(|c| c.to_json()).collect();
+ } else {
+ children = Vec::new()
}
- children.push_str("]");
-
- format!("[\"{}\",{}]", self.name, children)
+ serde_json::json!([&self.name, children])
}
}
@@ -1056,6 +1050,29 @@ mod tests {
assert!(modules.deps(&specifier).is_none());
}
+ #[test]
+ fn deps_to_json() {
+ fn dep(name: &str, deps: Option<Vec<Deps>>) -> Deps {
+ Deps {
+ name: name.to_string(),
+ deps,
+ prefix: "".to_string(),
+ is_last: false,
+ }
+ }
+ let deps = dep(
+ "a",
+ Some(vec![
+ dep("b", Some(vec![dep("b2", None)])),
+ dep("c", Some(vec![])),
+ ]),
+ );
+ assert_eq!(
+ serde_json::json!(["a", [["b", [["b2", []]]], ["c", []]]]),
+ deps.to_json()
+ );
+ }
+
/* TODO(bartlomieju): reenable
#[test]
fn deps() {
@@ -1076,22 +1093,5 @@ mod tests {
assert_eq!(bar_deps.deps, Some(vec![]));
}
- #[test]
- fn test_deps_to_json() {
- let mut modules = Modules::new();
- modules.register(1, "foo");
- modules.register(2, "bar");
- modules.register(3, "baz");
- modules.register(4, "zuh");
- modules.add_child(1, "bar");
- modules.add_child(1, "baz");
- modules.add_child(3, "zuh");
- let maybe_deps = modules.deps("foo");
- assert!(maybe_deps.is_some());
- assert_eq!(
- "[\"foo\",[[\"bar\",[]],[\"baz\",[[\"zuh\",[]]]]]]",
- maybe_deps.unwrap().to_json()
- );
- }
*/
}