From a5d51a4ffabbc45b67a754a7367494af1b0fe27c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Mon, 30 Oct 2023 02:28:01 +0100 Subject: [PATCH 01/16] use cargo patch --- Cargo.lock | 3 +-- Cargo.toml | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e322d63d16cc2b..ef87cb6e0ac4a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1264,8 +1264,7 @@ dependencies = [ [[package]] name = "deno_doc" version = "0.70.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd0a46bf024da1e3a1caa7fbb6309bd2abd5395c738b73efe34276a6d9b9838" +source = "git+https://github.com/denoland/deno_doc?branch=main#7807fac29e5ca6dff89d7ae64b64a8a3e889ece4" dependencies = [ "anyhow", "cfg-if 1.0.0", diff --git a/Cargo.toml b/Cargo.toml index 77f229e04d62f0..1d75adf74e557a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -329,3 +329,6 @@ opt-level = 3 opt-level = 3 [profile.release.package.base64-simd] opt-level = 3 + +[patch.crates-io] +deno_doc = { git = "https://github.com/denoland/deno_doc", branch = "main" } From 8e55277450f5a4c813f24c7f10bf607aff5a0f1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Mon, 30 Oct 2023 03:53:20 +0100 Subject: [PATCH 02/16] flags for 'deno doc' test --- cli/args/flags.rs | 113 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/cli/args/flags.rs b/cli/args/flags.rs index 6e8b00cabc2d21..e708d47c8857dd 100644 --- a/cli/args/flags.rs +++ b/cli/args/flags.rs @@ -105,10 +105,17 @@ impl Default for DocSourceFileFlag { } } +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct DocHtmlFlag { + pub name: String, + pub output: String, +} + #[derive(Clone, Debug, Eq, PartialEq)] pub struct DocFlags { pub private: bool, pub json: bool, + pub html: Option, pub source_file: DocSourceFileFlag, pub filter: Option, } @@ -1319,6 +1326,12 @@ Output documentation to standard output: deno doc ./path/to/module.ts +Output documentation in HTML format: + + deno doc --html --name=\"My library\" ./path/to/module.ts + deno doc --html --name=\"My library\" ./main.ts ./dev.ts + deno doc --html --name=\"My library\" --output=./documentation/ ./path/to/module.ts + Output private documentation to standard output: deno doc --private ./path/to/module.ts @@ -1350,6 +1363,28 @@ Show documentation for runtime built-ins: .help("Output documentation in JSON format") .action(ArgAction::SetTrue), ) + .arg( + Arg::new("html") + .long("html") + .help("Output documentation in HTML format") + .action(ArgAction::SetTrue) + .conflicts_with("json") + ) + .arg( + Arg::new("name") + .long("name") + .help("The name that will be displayed in the docs") + .action(ArgAction::Set) + .required_if_eq("html", "true") + .require_equals(true) + ) + .arg( + Arg::new("output") + .long("output") + .help("Directory for HTML documentation output") + .action(ArgAction::Set) + .require_equals(true) + ) .arg( Arg::new("private") .long("private") @@ -3103,9 +3138,29 @@ fn doc_parse(flags: &mut Flags, matches: &mut ArgMatches) { let private = matches.get_flag("private"); let json = matches.get_flag("json"); let filter = matches.remove_one::("filter"); + let html = matches.get_flag("html"); + let name = if html { + matches.remove_one::("name").unwrap() + } else { + "".to_string() + }; + let output = if html { + matches + .remove_one::("output") + .unwrap_or(String::from("./docs/")) + } else { + "".to_string() + }; + let html = if html { + Some(DocHtmlFlag { name, output }) + } else { + None + }; + flags.subcommand = DenoSubcommand::Doc(DocFlags { source_file, json, + html, filter, private, }); @@ -5921,6 +5976,7 @@ mod tests { source_file: DocSourceFileFlag::Path("script.ts".to_owned()), private: false, json: false, + html: None, filter: None, }), import_map_path: Some("import_map.json".to_owned()), @@ -7178,6 +7234,59 @@ mod tests { subcommand: DenoSubcommand::Doc(DocFlags { private: false, json: true, + html: None, + source_file: DocSourceFileFlag::Path("path/to/module.ts".to_string()), + filter: None, + }), + ..Flags::default() + } + ); + + let r = flags_from_vec(svec!["deno", "doc", "--html", "path/to/module.ts"]); + assert!(r.is_err()); + + let r = flags_from_vec(svec![ + "deno", + "doc", + "--html", + "--name=My library", + "path/to/module.ts" + ]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Doc(DocFlags { + private: false, + json: false, + html: Some(DocHtmlFlag { + name: "My library".to_string(), + output: "./docs/".to_string(), + }), + source_file: DocSourceFileFlag::Path("path/to/module.ts".to_string()), + filter: None, + }), + ..Flags::default() + } + ); + + let r = flags_from_vec(svec![ + "deno", + "doc", + "--html", + "--name=My library", + "--output=./foo", + "path/to/module.ts" + ]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Doc(DocFlags { + private: false, + json: false, + html: Some(DocHtmlFlag { + name: "My library".to_string(), + output: "./foo".to_string(), + }), source_file: DocSourceFileFlag::Path("path/to/module.ts".to_string()), filter: None, }), @@ -7197,6 +7306,7 @@ mod tests { subcommand: DenoSubcommand::Doc(DocFlags { private: false, json: false, + html: None, source_file: DocSourceFileFlag::Path("path/to/module.ts".to_string()), filter: Some("SomeClass.someField".to_string()), }), @@ -7211,6 +7321,7 @@ mod tests { subcommand: DenoSubcommand::Doc(DocFlags { private: false, json: false, + html: None, source_file: Default::default(), filter: None, }), @@ -7225,6 +7336,7 @@ mod tests { subcommand: DenoSubcommand::Doc(DocFlags { private: false, json: false, + html: None, source_file: DocSourceFileFlag::Builtin, filter: Some("Deno.Listener".to_string()), }), @@ -7246,6 +7358,7 @@ mod tests { subcommand: DenoSubcommand::Doc(DocFlags { private: true, json: false, + html: None, source_file: DocSourceFileFlag::Path("path/to/module.js".to_string()), filter: None, }), From 1b4289d3a1a0f1f8f4dd6c8f37f53143ff1509e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Mon, 30 Oct 2023 03:59:09 +0100 Subject: [PATCH 03/16] update subcommands --- cli/main.rs | 2 +- cli/tools/doc.rs | 112 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 110 insertions(+), 4 deletions(-) diff --git a/cli/main.rs b/cli/main.rs index 0817c0984ca667..d6aeb22bfc470a 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -95,7 +95,7 @@ async fn run_subcommand(flags: Flags) -> Result { tools::bundle::bundle(flags, bundle_flags).await }), DenoSubcommand::Doc(doc_flags) => { - spawn_subcommand(async { tools::doc::print_docs(flags, doc_flags).await }) + spawn_subcommand(async { tools::doc::doc(flags, doc_flags).await }) } DenoSubcommand::Eval(eval_flags) => spawn_subcommand(async { tools::run::eval_command(flags, eval_flags).await diff --git a/cli/tools/doc.rs b/cli/tools/doc.rs index 1a770b2d3a6871..c57ecfa6321f67 100644 --- a/cli/tools/doc.rs +++ b/cli/tools/doc.rs @@ -1,6 +1,7 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. use crate::args::DocFlags; +use crate::args::DocHtmlFlag; use crate::args::DocSourceFileFlag; use crate::args::Flags; use crate::colors; @@ -19,10 +20,115 @@ use deno_graph::DefaultParsedSourceStore; use deno_graph::GraphKind; use deno_graph::ModuleSpecifier; -pub async fn print_docs( - flags: Flags, - doc_flags: DocFlags, +pub async fn doc(flags: Flags, doc_flags: DocFlags) -> Result<(), AnyError> { + let factory = CliFactory::from_flags(flags).await?; + let cli_options = factory.cli_options(); + let module_info_cache = factory.module_info_cache()?; + let source_parser = deno_graph::DefaultModuleParser::new_for_analysis(); + let store = DefaultParsedSourceStore::default(); + let analyzer = + module_info_cache.as_module_analyzer(Some(&source_parser), &store); + let capturing_parser = + CapturingModuleParser::new(Some(&source_parser), &store); + + let mut doc_nodes = match doc_flags.source_file { + DocSourceFileFlag::Builtin => { + let source_file_specifier = + ModuleSpecifier::parse("internal://lib.deno.d.ts").unwrap(); + let content = get_types_declaration_file_text(cli_options.unstable()); + let mut loader = deno_graph::source::MemoryLoader::new( + vec![( + source_file_specifier.to_string(), + deno_graph::source::Source::Module { + specifier: source_file_specifier.to_string(), + content, + maybe_headers: None, + }, + )], + Vec::new(), + ); + let mut graph = deno_graph::ModuleGraph::new(GraphKind::TypesOnly); + graph + .build( + vec![source_file_specifier.clone()], + &mut loader, + deno_graph::BuildOptions { + module_analyzer: Some(&analyzer), + ..Default::default() + }, + ) + .await; + let doc_parser = + doc::DocParser::new(&graph, doc_flags.private, capturing_parser)?; + doc_parser.parse_module(&source_file_specifier)?.definitions + } + DocSourceFileFlag::Path(source_file) => { + let module_graph_builder = factory.module_graph_builder().await?; + let maybe_lockfile = factory.maybe_lockfile(); + + let module_specifier = + resolve_url_or_path(&source_file, cli_options.initial_cwd())?; + + let mut loader = module_graph_builder.create_graph_loader(); + let graph = module_graph_builder + .create_graph_with_options(CreateGraphOptions { + graph_kind: GraphKind::TypesOnly, + roots: vec![module_specifier.clone()], + loader: &mut loader, + analyzer: &analyzer, + }) + .await?; + + if let Some(lockfile) = maybe_lockfile { + graph_lock_or_exit(&graph, &mut lockfile.lock()); + } + + doc::DocParser::new(&graph, doc_flags.private, capturing_parser)? + .parse_with_reexports(&module_specifier)? + } + }; + + if let Some(html_options) = doc_flags.html { + generate_docs_directory(doc_nodes, html_options) + .boxed_local() + .await + } else if doc_flags.json { + write_json_to_stdout(&doc_nodes) + } else { + doc_nodes.retain(|doc_node| doc_node.kind != doc::DocNodeKind::Import); + let details = if let Some(filter) = doc_flags.filter { + let nodes = + doc::find_nodes_by_name_recursively(doc_nodes, filter.clone()); + if nodes.is_empty() { + bail!("Node {} was not found!", filter); + } + format!( + "{}", + doc::DocPrinter::new(&nodes, colors::use_color(), doc_flags.private) + ) + } else { + format!( + "{}", + doc::DocPrinter::new( + &doc_nodes, + colors::use_color(), + doc_flags.private + ) + ) + }; + + write_to_stdout_ignore_sigpipe(details.as_bytes()).map_err(AnyError::from) + } +} + +async fn generate_docs_directory( + doc_nodes: Vec, + html_options: DocHtmlFlag, ) -> Result<(), AnyError> { + todo!() +} + +async fn print_docs(flags: Flags, doc_flags: DocFlags) -> Result<(), AnyError> { let factory = CliFactory::from_flags(flags).await?; let cli_options = factory.cli_options(); let module_info_cache = factory.module_info_cache()?; From 7ee3df022a041837f5d2a4715b3b84ea255e61da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Mon, 30 Oct 2023 04:18:57 +0100 Subject: [PATCH 04/16] wire up to 'deno doc' command --- Cargo.lock | 340 ++++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 3 - cli/Cargo.toml | 2 +- cli/tools/doc.rs | 212 +++++++++++++---------------- 4 files changed, 424 insertions(+), 133 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ef87cb6e0ac4a1..bcf67349607c65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -577,6 +577,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca8f255e4b8027970e78db75e78831229c9815fdbfa67eb1a1b777a62e24b4a0" dependencies = [ "clap_builder", + "clap_derive", + "once_cell", ] [[package]] @@ -590,6 +592,7 @@ dependencies = [ "bitflags 1.3.2", "clap_lex", "strsim", + "terminal_size", ] [[package]] @@ -611,6 +614,18 @@ dependencies = [ "clap_complete", ] +[[package]] +name = "clap_derive" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" +dependencies = [ + "heck", + "proc-macro2 1.0.67", + "quote 1.0.33", + "syn 2.0.37", +] + [[package]] name = "clap_lex" version = "0.5.1" @@ -643,6 +658,26 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "comrak" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82c995deda3bfdebd07d0e2af79e9da13e4b1be652b21a746f3f5b24bf0a49ef" +dependencies = [ + "clap", + "derive_builder", + "entities", + "memchr", + "once_cell", + "regex", + "shell-words", + "slug", + "syntect", + "typed-arena", + "unicode_categories", + "xdg", +] + [[package]] name = "console_static_text" version = "0.8.1" @@ -917,6 +952,41 @@ dependencies = [ "syn 2.0.37", ] +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2 1.0.67", + "quote 1.0.33", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote 1.0.33", + "syn 1.0.109", +] + [[package]] name = "dashmap" version = "3.11.10" @@ -1002,7 +1072,7 @@ dependencies = [ "encoding_rs", "env_logger", "eszip", - "fancy-regex", + "fancy-regex 0.10.0", "fastwebsockets", "flaky_test", "flate2", @@ -1268,15 +1338,19 @@ source = "git+https://github.com/denoland/deno_doc?branch=main#7807fac29e5ca6dff dependencies = [ "anyhow", "cfg-if 1.0.0", + "comrak", "deno_ast", "deno_graph", "futures", + "html-escape", "import_map", + "indexmap 2.0.2", "lazy_static", "regex", "serde", "serde_json", "termcolor", + "tinytemplate", ] [[package]] @@ -1835,6 +1909,37 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" +[[package]] +name = "derive_builder" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" +dependencies = [ + "darling", + "proc-macro2 1.0.67", + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_macro" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" +dependencies = [ + "derive_builder_core", + "syn 1.0.109", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -1848,6 +1953,21 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "deunicode" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71dbf1bf89c23e9cd1baf5e654f622872655f195b36588dc9dc38f7eda30758c" +dependencies = [ + "deunicode 1.4.1", +] + +[[package]] +name = "deunicode" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a1abaf4d861455be59f64fd2b55606cb151fce304ede7165f410243ce96bde6" + [[package]] name = "diff" version = "0.1.13" @@ -2132,6 +2252,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" +[[package]] +name = "entities" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" + [[package]] name = "enum-as-inner" version = "0.5.1" @@ -2268,6 +2394,16 @@ dependencies = [ "regex", ] +[[package]] +name = "fancy-regex" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2" +dependencies = [ + "bit-set", + "regex", +] + [[package]] name = "fastrand" version = "2.0.1" @@ -2298,7 +2434,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" dependencies = [ "cfg-if 1.0.0", - "rustix", + "rustix 0.38.19", "windows-sys", ] @@ -2730,6 +2866,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "html-escape" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476" +dependencies = [ + "utf8-width", +] + [[package]] name = "http" version = "0.2.9" @@ -2862,6 +3007,12 @@ dependencies = [ "cc", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.2.3" @@ -2974,6 +3125,17 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys", +] + [[package]] name = "ipconfig" version = "0.3.2" @@ -3012,7 +3174,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", - "rustix", + "rustix 0.38.19", "windows-sys", ] @@ -3194,12 +3356,27 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "line-wrap" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" +dependencies = [ + "safemem", +] + [[package]] name = "linked-hash-map" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + [[package]] name = "linux-raw-sys" version = "0.4.10" @@ -3583,6 +3760,28 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "onig" +version = "6.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f" +dependencies = [ + "bitflags 1.3.2", + "libc", + "once_cell", + "onig_sys", +] + +[[package]] +name = "onig_sys" +version = "69.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7" +dependencies = [ + "cc", + "pkg-config", +] + [[package]] name = "opaque-debug" version = "0.3.0" @@ -3922,6 +4121,20 @@ version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8" +[[package]] +name = "plist" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a4a0cfc5fb21a09dc6af4bf834cf10d4a32fccd9e2ea468c4b1751a097487aa" +dependencies = [ + "base64 0.21.4", + "indexmap 1.9.3", + "line-wrap", + "quick-xml 0.30.0", + "serde", + "time", +] + [[package]] name = "pmutil" version = "0.6.1" @@ -4133,12 +4346,21 @@ dependencies = [ "chrono", "indexmap 2.0.2", "nextest-workspace-hack", - "quick-xml", + "quick-xml 0.31.0", "strip-ansi-escapes", "thiserror", "uuid 1.5.0", ] +[[package]] +name = "quick-xml" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" +dependencies = [ + "memchr", +] + [[package]] name = "quick-xml" version = "0.31.0" @@ -4477,6 +4699,20 @@ dependencies = [ "nom", ] +[[package]] +name = "rustix" +version = "0.37.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +dependencies = [ + "bitflags 1.3.2", + "errno 0.3.3", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys", +] + [[package]] name = "rustix" version = "0.38.19" @@ -4486,7 +4722,7 @@ dependencies = [ "bitflags 2.4.0", "errno 0.3.3", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.10", "windows-sys", ] @@ -4584,6 +4820,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4950d85bc52415f8432144c97c4791bd0c4f7954de32a7270ee9cccd3c22b12b" +[[package]] +name = "safemem" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" + [[package]] name = "salsa20" version = "0.10.2" @@ -4865,6 +5107,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -4915,6 +5163,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "slug" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373" +dependencies = [ + "deunicode 0.4.5", +] + [[package]] name = "smallvec" version = "1.11.1" @@ -5604,6 +5861,28 @@ dependencies = [ "unicode-xid 0.2.4", ] +[[package]] +name = "syntect" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e02b4b303bf8d08bfeb0445cba5068a3d306b6baece1d5582171a9bf49188f91" +dependencies = [ + "bincode", + "bitflags 1.3.2", + "fancy-regex 0.11.0", + "flate2", + "fnv", + "once_cell", + "onig", + "plist", + "regex-syntax", + "serde", + "serde_json", + "thiserror", + "walkdir", + "yaml-rust", +] + [[package]] name = "tar" version = "0.4.40" @@ -5624,7 +5903,7 @@ dependencies = [ "cfg-if 1.0.0", "fastrand", "redox_syscall 0.3.5", - "rustix", + "rustix 0.38.19", "windows-sys", ] @@ -5637,6 +5916,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal_size" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" +dependencies = [ + "rustix 0.37.27", + "windows-sys", +] + [[package]] name = "test_ffi" version = "0.1.0" @@ -5768,6 +6057,16 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -6234,6 +6533,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + [[package]] name = "universal-hash" version = "0.5.1" @@ -6281,6 +6586,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf8-width" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1" + [[package]] name = "utf8parse" version = "0.2.1" @@ -6493,7 +6804,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix", + "rustix 0.38.19", ] [[package]] @@ -6684,6 +6995,21 @@ dependencies = [ "libc", ] +[[package]] +name = "xdg" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "yansi" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index 1d75adf74e557a..77f229e04d62f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -329,6 +329,3 @@ opt-level = 3 opt-level = 3 [profile.release.package.base64-simd] opt-level = 3 - -[patch.crates-io] -deno_doc = { git = "https://github.com/denoland/deno_doc", branch = "main" } diff --git a/cli/Cargo.toml b/cli/Cargo.toml index de51163507c5bb..714e0b86bcbd04 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -49,7 +49,7 @@ deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "dep_gra deno_cache_dir = "=0.6.1" deno_config = "=0.4.0" deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] } -deno_doc = "=0.70.0" +deno_doc = { git = "https://github.com/denoland/deno_doc", branch = "main", features = ["html"] } deno_emit = "=0.31.1" deno_graph = "=0.59.1" deno_lint = { version = "=0.52.2", features = ["docs"] } diff --git a/cli/tools/doc.rs b/cli/tools/doc.rs index c57ecfa6321f67..68a284d45fa05b 100644 --- a/cli/tools/doc.rs +++ b/cli/tools/doc.rs @@ -12,13 +12,16 @@ use crate::graph_util::graph_lock_or_exit; use crate::graph_util::CreateGraphOptions; use crate::tsc::get_types_declaration_file_text; use deno_core::anyhow::bail; +use deno_core::anyhow::Context; use deno_core::error::AnyError; +use deno_core::futures::FutureExt; use deno_core::resolve_url_or_path; use deno_doc as doc; use deno_graph::CapturingModuleParser; use deno_graph::DefaultParsedSourceStore; use deno_graph::GraphKind; use deno_graph::ModuleSpecifier; +use indexmap::IndexMap; pub async fn doc(flags: Flags, doc_flags: DocFlags) -> Result<(), AnyError> { let factory = CliFactory::from_flags(flags).await?; @@ -31,7 +34,8 @@ pub async fn doc(flags: Flags, doc_flags: DocFlags) -> Result<(), AnyError> { let capturing_parser = CapturingModuleParser::new(Some(&source_parser), &store); - let mut doc_nodes = match doc_flags.source_file { + // TODO(bartlomieju): update to handle multiple files + let (doc_nodes, specifier) = match doc_flags.source_file { DocSourceFileFlag::Builtin => { let source_file_specifier = ModuleSpecifier::parse("internal://lib.deno.d.ts").unwrap(); @@ -60,9 +64,11 @@ pub async fn doc(flags: Flags, doc_flags: DocFlags) -> Result<(), AnyError> { .await; let doc_parser = doc::DocParser::new(&graph, doc_flags.private, capturing_parser)?; - doc_parser.parse_module(&source_file_specifier)?.definitions + let nodes = doc_parser.parse_module(&source_file_specifier)?.definitions; + + (nodes, source_file_specifier) } - DocSourceFileFlag::Path(source_file) => { + DocSourceFileFlag::Path(ref source_file) => { let module_graph_builder = factory.module_graph_builder().await?; let maybe_lockfile = factory.maybe_lockfile(); @@ -83,144 +89,106 @@ pub async fn doc(flags: Flags, doc_flags: DocFlags) -> Result<(), AnyError> { graph_lock_or_exit(&graph, &mut lockfile.lock()); } - doc::DocParser::new(&graph, doc_flags.private, capturing_parser)? - .parse_with_reexports(&module_specifier)? + let nodes = + doc::DocParser::new(&graph, doc_flags.private, capturing_parser)? + .parse_with_reexports(&module_specifier)?; + + (nodes, module_specifier) } }; if let Some(html_options) = doc_flags.html { - generate_docs_directory(doc_nodes, html_options) + generate_docs_directory(specifier, doc_nodes, html_options) .boxed_local() .await - } else if doc_flags.json { - write_json_to_stdout(&doc_nodes) } else { - doc_nodes.retain(|doc_node| doc_node.kind != doc::DocNodeKind::Import); - let details = if let Some(filter) = doc_flags.filter { - let nodes = - doc::find_nodes_by_name_recursively(doc_nodes, filter.clone()); - if nodes.is_empty() { - bail!("Node {} was not found!", filter); - } - format!( - "{}", - doc::DocPrinter::new(&nodes, colors::use_color(), doc_flags.private) - ) - } else { - format!( - "{}", - doc::DocPrinter::new( - &doc_nodes, - colors::use_color(), - doc_flags.private - ) - ) - }; - - write_to_stdout_ignore_sigpipe(details.as_bytes()).map_err(AnyError::from) + print_docs(doc_flags, doc_nodes) } } async fn generate_docs_directory( + specifier: ModuleSpecifier, doc_nodes: Vec, html_options: DocHtmlFlag, ) -> Result<(), AnyError> { - todo!() -} - -async fn print_docs(flags: Flags, doc_flags: DocFlags) -> Result<(), AnyError> { - let factory = CliFactory::from_flags(flags).await?; - let cli_options = factory.cli_options(); - let module_info_cache = factory.module_info_cache()?; - let source_parser = deno_graph::DefaultModuleParser::new_for_analysis(); - let store = DefaultParsedSourceStore::default(); - let analyzer = - module_info_cache.as_module_analyzer(Some(&source_parser), &store); - let capturing_parser = - CapturingModuleParser::new(Some(&source_parser), &store); - - let mut doc_nodes = match doc_flags.source_file { - DocSourceFileFlag::Builtin => { - let source_file_specifier = - ModuleSpecifier::parse("internal://lib.deno.d.ts").unwrap(); - let content = get_types_declaration_file_text(cli_options.unstable()); - let mut loader = deno_graph::source::MemoryLoader::new( - vec![( - source_file_specifier.to_string(), - deno_graph::source::Source::Module { - specifier: source_file_specifier.to_string(), - content, - maybe_headers: None, - }, - )], - Vec::new(), - ); - let mut graph = deno_graph::ModuleGraph::new(GraphKind::TypesOnly); - graph - .build( - vec![source_file_specifier.clone()], - &mut loader, - deno_graph::BuildOptions { - module_analyzer: Some(&analyzer), - ..Default::default() - }, - ) - .await; - let doc_parser = - doc::DocParser::new(&graph, doc_flags.private, capturing_parser)?; - doc_parser.parse_module(&source_file_specifier)?.definitions - } - DocSourceFileFlag::Path(source_file) => { - let module_graph_builder = factory.module_graph_builder().await?; - let maybe_lockfile = factory.maybe_lockfile(); + let cwd = std::env::current_dir().context("Failed to get CWD")?; + let output_dir_resolved = cwd.join(&html_options.output); + let output_dir_relative = output_dir_resolved.strip_prefix(&cwd).unwrap(); + let mut output_dir_relative_str = + output_dir_relative.to_string_lossy().to_string(); + output_dir_relative_str = output_dir_relative_str + .strip_prefix('/') + .unwrap_or(&output_dir_relative_str) + .to_string(); + output_dir_relative_str = output_dir_relative_str + .strip_suffix('/') + .unwrap_or(&output_dir_relative_str) + .to_string(); + // TODO: make `base_url` configurable? + let base_url = format!("/{}/", output_dir_relative_str); + + let options = deno_doc::html::GenerateOptions { + package_name: html_options.name, + base_url, + }; - let module_specifier = - resolve_url_or_path(&source_file, cli_options.initial_cwd())?; + // TODO(bartlomieju): parse all files here + let doc_nodes_by_url = IndexMap::from([(specifier, doc_nodes)]); + let html = deno_doc::html::generate(options.clone(), &doc_nodes_by_url)?; + + let path = &output_dir_resolved; + let _ = std::fs::remove_dir_all(path); + std::fs::create_dir(path)?; + + std::fs::write( + path.join(deno_doc::html::STYLESHEET_FILENAME), + deno_doc::html::STYLESHEET, + ) + .unwrap(); + std::fs::write( + path.join(deno_doc::html::SEARCH_INDEX_FILENAME), + deno_doc::html::generate_search_index(&doc_nodes_by_url)?, + ) + .unwrap(); + std::fs::write( + path.join(deno_doc::html::SEARCH_FILENAME), + deno_doc::html::SEARCH_JS, + ) + .unwrap(); + for (name, content) in html { + let this_path = path.join(name); + let prefix = this_path.parent().unwrap(); + std::fs::create_dir_all(prefix).unwrap(); + std::fs::write(this_path, content).unwrap(); + } - let mut loader = module_graph_builder.create_graph_loader(); - let graph = module_graph_builder - .create_graph_with_options(CreateGraphOptions { - graph_kind: GraphKind::TypesOnly, - roots: vec![module_specifier.clone()], - loader: &mut loader, - analyzer: &analyzer, - }) - .await?; + Ok(()) +} - if let Some(lockfile) = maybe_lockfile { - graph_lock_or_exit(&graph, &mut lockfile.lock()); - } +fn print_docs( + doc_flags: DocFlags, + mut doc_nodes: Vec, +) -> Result<(), AnyError> { + if doc_flags.json { + return write_json_to_stdout(&doc_nodes); + } - doc::DocParser::new(&graph, doc_flags.private, capturing_parser)? - .parse_with_reexports(&module_specifier)? + doc_nodes.retain(|doc_node| doc_node.kind != doc::DocNodeKind::Import); + let details = if let Some(filter) = doc_flags.filter { + let nodes = doc::find_nodes_by_name_recursively(doc_nodes, filter.clone()); + if nodes.is_empty() { + bail!("Node {} was not found!", filter); } - }; - - if doc_flags.json { - write_json_to_stdout(&doc_nodes) + format!( + "{}", + doc::DocPrinter::new(&nodes, colors::use_color(), doc_flags.private) + ) } else { - doc_nodes.retain(|doc_node| doc_node.kind != doc::DocNodeKind::Import); - let details = if let Some(filter) = doc_flags.filter { - let nodes = - doc::find_nodes_by_name_recursively(doc_nodes, filter.clone()); - if nodes.is_empty() { - bail!("Node {} was not found!", filter); - } - format!( - "{}", - doc::DocPrinter::new(&nodes, colors::use_color(), doc_flags.private) - ) - } else { - format!( - "{}", - doc::DocPrinter::new( - &doc_nodes, - colors::use_color(), - doc_flags.private - ) - ) - }; + format!( + "{}", + doc::DocPrinter::new(&doc_nodes, colors::use_color(), doc_flags.private) + ) + }; - write_to_stdout_ignore_sigpipe(details.as_bytes()).map_err(AnyError::from) - } + write_to_stdout_ignore_sigpipe(details.as_bytes()).map_err(AnyError::from) } From 8ad3133ed1d30418e7e5c64b80fa8587c44e2a8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Mon, 30 Oct 2023 04:25:43 +0100 Subject: [PATCH 05/16] mark --html as unstable --- cli/args/flags.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/args/flags.rs b/cli/args/flags.rs index e708d47c8857dd..a2408eeabb0f05 100644 --- a/cli/args/flags.rs +++ b/cli/args/flags.rs @@ -1366,7 +1366,7 @@ Show documentation for runtime built-ins: .arg( Arg::new("html") .long("html") - .help("Output documentation in HTML format") + .help("UNSTABLE: Output documentation in HTML format") .action(ArgAction::SetTrue) .conflicts_with("json") ) From 903877f1d9a234d68a26a228efea1e0d03bb61bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Tue, 31 Oct 2023 02:34:31 +0100 Subject: [PATCH 06/16] update deno_doc --- Cargo.lock | 8 ++++---- cli/tools/doc.rs | 49 ++++++++++++++++-------------------------------- 2 files changed, 20 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4bbb6874c8f3a3..3ce6831695ed61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1315,8 +1315,8 @@ dependencies = [ [[package]] name = "deno_doc" -version = "0.70.0" -source = "git+https://github.com/denoland/deno_doc?branch=main#7807fac29e5ca6dff89d7ae64b64a8a3e889ece4" +version = "0.71.0" +source = "git+https://github.com/denoland/deno_doc?branch=main#c014267b04f6ba061434f58b87b2cbb8eaa27958" dependencies = [ "anyhow", "cfg-if 1.0.0", @@ -6372,8 +6372,8 @@ version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ - "cfg-if 1.0.0", - "rand 0.8.5", + "cfg-if 0.1.10", + "rand 0.7.3", "static_assertions", ] diff --git a/cli/tools/doc.rs b/cli/tools/doc.rs index e44ea95398e915..83508f32dff5c1 100644 --- a/cli/tools/doc.rs +++ b/cli/tools/doc.rs @@ -62,8 +62,14 @@ pub async fn doc(flags: Flags, doc_flags: DocFlags) -> Result<(), AnyError> { }, ) .await; - let doc_parser = - doc::DocParser::new(&graph, doc_flags.private, capturing_parser)?; + let doc_parser = doc::DocParser::new( + &graph, + capturing_parser, + doc::DocParserOptions { + diagnostics: false, + private: doc_flags.private, + }, + )?; let nodes = doc_parser.parse_module(&source_file_specifier)?.definitions; (nodes, source_file_specifier) @@ -94,8 +100,14 @@ pub async fn doc(flags: Flags, doc_flags: DocFlags) -> Result<(), AnyError> { graph_lock_or_exit(&graph, &mut lockfile.lock()); } - let doc_parser = - doc::DocParser::new(&graph, doc_flags.private, capturing_parser)?; + let doc_parser = doc::DocParser::new( + &graph, + capturing_parser, + doc::DocParserOptions { + diagnostics: false, + private: doc_flags.private, + }, + )?; let mut doc_nodes = vec![]; @@ -124,23 +136,9 @@ async fn generate_docs_directory( ) -> Result<(), AnyError> { let cwd = std::env::current_dir().context("Failed to get CWD")?; let output_dir_resolved = cwd.join(&html_options.output); - let output_dir_relative = output_dir_resolved.strip_prefix(&cwd).unwrap(); - let mut output_dir_relative_str = - output_dir_relative.to_string_lossy().to_string(); - output_dir_relative_str = output_dir_relative_str - .strip_prefix('/') - .unwrap_or(&output_dir_relative_str) - .to_string(); - output_dir_relative_str = output_dir_relative_str - .strip_suffix('/') - .unwrap_or(&output_dir_relative_str) - .to_string(); - // TODO: make `base_url` configurable? - let base_url = format!("/{}/", output_dir_relative_str); let options = deno_doc::html::GenerateOptions { package_name: html_options.name, - base_url, }; // TODO(bartlomieju): parse all files here @@ -151,21 +149,6 @@ async fn generate_docs_directory( let _ = std::fs::remove_dir_all(path); std::fs::create_dir(path)?; - std::fs::write( - path.join(deno_doc::html::STYLESHEET_FILENAME), - deno_doc::html::STYLESHEET, - ) - .unwrap(); - std::fs::write( - path.join(deno_doc::html::SEARCH_INDEX_FILENAME), - deno_doc::html::generate_search_index(&doc_nodes_by_url)?, - ) - .unwrap(); - std::fs::write( - path.join(deno_doc::html::SEARCH_FILENAME), - deno_doc::html::SEARCH_JS, - ) - .unwrap(); for (name, content) in html { let this_path = path.join(name); let prefix = this_path.parent().unwrap(); From 635ed4b619292364ff6df3b8c3527a57a226085f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Tue, 31 Oct 2023 02:41:10 +0100 Subject: [PATCH 07/16] generate by file --- cli/tools/doc.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/cli/tools/doc.rs b/cli/tools/doc.rs index 83508f32dff5c1..f3ca53aa08c3e2 100644 --- a/cli/tools/doc.rs +++ b/cli/tools/doc.rs @@ -34,8 +34,7 @@ pub async fn doc(flags: Flags, doc_flags: DocFlags) -> Result<(), AnyError> { let capturing_parser = CapturingModuleParser::new(Some(&source_parser), &store); - // TODO(bartlomieju): rewrite to return an IndexMap - let (doc_nodes, specifier) = match doc_flags.source_files { + let doc_nodes_by_url = match doc_flags.source_files { DocSourceFileFlag::Builtin => { let source_file_specifier = ModuleSpecifier::parse("internal://lib.deno.d.ts").unwrap(); @@ -72,7 +71,7 @@ pub async fn doc(flags: Flags, doc_flags: DocFlags) -> Result<(), AnyError> { )?; let nodes = doc_parser.parse_module(&source_file_specifier)?.definitions; - (nodes, source_file_specifier) + IndexMap::from([(source_file_specifier, nodes)]) } DocSourceFileFlag::Paths(ref source_files) => { let module_graph_builder = factory.module_graph_builder().await?; @@ -109,29 +108,31 @@ pub async fn doc(flags: Flags, doc_flags: DocFlags) -> Result<(), AnyError> { }, )?; - let mut doc_nodes = vec![]; + let mut doc_nodes_by_url = + IndexMap::with_capacity(module_specifiers.len()); for module_specifier in &module_specifiers { let nodes = doc_parser.parse_with_reexports(&module_specifier)?; - doc_nodes.extend_from_slice(&nodes); + doc_nodes_by_url.insert(module_specifier.clone(), nodes); } - (doc_nodes, module_specifiers[0].clone()) + doc_nodes_by_url } }; if let Some(html_options) = doc_flags.html { - generate_docs_directory(specifier, doc_nodes, html_options) + generate_docs_directory(&doc_nodes_by_url, html_options) .boxed_local() .await } else { + let doc_nodes: Vec = + doc_nodes_by_url.values().cloned().flatten().collect(); print_docs(doc_flags, doc_nodes) } } async fn generate_docs_directory( - specifier: ModuleSpecifier, - doc_nodes: Vec, + doc_nodes_by_url: &IndexMap>, html_options: DocHtmlFlag, ) -> Result<(), AnyError> { let cwd = std::env::current_dir().context("Failed to get CWD")?; @@ -141,8 +142,6 @@ async fn generate_docs_directory( package_name: html_options.name, }; - // TODO(bartlomieju): parse all files here - let doc_nodes_by_url = IndexMap::from([(specifier, doc_nodes)]); let html = deno_doc::html::generate(options.clone(), &doc_nodes_by_url)?; let path = &output_dir_resolved; From 4be9dda8aa315f1f3aa371a022012f124edf2d98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Tue, 31 Oct 2023 02:49:15 +0100 Subject: [PATCH 08/16] factor out a function --- cli/tools/doc.rs | 88 +++++++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 35 deletions(-) diff --git a/cli/tools/doc.rs b/cli/tools/doc.rs index f3ca53aa08c3e2..f3178a0b62f5c6 100644 --- a/cli/tools/doc.rs +++ b/cli/tools/doc.rs @@ -1,5 +1,6 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +use crate::args::CliOptions; use crate::args::DocFlags; use crate::args::DocHtmlFlag; use crate::args::DocSourceFileFlag; @@ -20,8 +21,54 @@ use deno_doc as doc; use deno_graph::CapturingModuleParser; use deno_graph::DefaultParsedSourceStore; use deno_graph::GraphKind; +use deno_graph::ModuleAnalyzer; use deno_graph::ModuleSpecifier; use indexmap::IndexMap; +use std::sync::Arc; + +async fn generate_doc_nodes_for_builtin_types( + doc_flags: DocFlags, + cli_options: &Arc, + capturing_parser: CapturingModuleParser<'_>, + analyzer: &dyn ModuleAnalyzer, +) -> Result>, AnyError> { + let source_file_specifier = + ModuleSpecifier::parse("internal://lib.deno.d.ts").unwrap(); + let content = get_types_declaration_file_text(cli_options.unstable()); + let mut loader = deno_graph::source::MemoryLoader::new( + vec![( + source_file_specifier.to_string(), + deno_graph::source::Source::Module { + specifier: source_file_specifier.to_string(), + content, + maybe_headers: None, + }, + )], + Vec::new(), + ); + let mut graph = deno_graph::ModuleGraph::new(GraphKind::TypesOnly); + graph + .build( + vec![source_file_specifier.clone()], + &mut loader, + deno_graph::BuildOptions { + module_analyzer: Some(analyzer), + ..Default::default() + }, + ) + .await; + let doc_parser = doc::DocParser::new( + &graph, + capturing_parser, + doc::DocParserOptions { + diagnostics: false, + private: doc_flags.private, + }, + )?; + let nodes = doc_parser.parse_module(&source_file_specifier)?.definitions; + + Ok(IndexMap::from([(source_file_specifier, nodes)])) +} pub async fn doc(flags: Flags, doc_flags: DocFlags) -> Result<(), AnyError> { let factory = CliFactory::from_flags(flags).await?; @@ -36,42 +83,13 @@ pub async fn doc(flags: Flags, doc_flags: DocFlags) -> Result<(), AnyError> { let doc_nodes_by_url = match doc_flags.source_files { DocSourceFileFlag::Builtin => { - let source_file_specifier = - ModuleSpecifier::parse("internal://lib.deno.d.ts").unwrap(); - let content = get_types_declaration_file_text(cli_options.unstable()); - let mut loader = deno_graph::source::MemoryLoader::new( - vec![( - source_file_specifier.to_string(), - deno_graph::source::Source::Module { - specifier: source_file_specifier.to_string(), - content, - maybe_headers: None, - }, - )], - Vec::new(), - ); - let mut graph = deno_graph::ModuleGraph::new(GraphKind::TypesOnly); - graph - .build( - vec![source_file_specifier.clone()], - &mut loader, - deno_graph::BuildOptions { - module_analyzer: Some(&analyzer), - ..Default::default() - }, - ) - .await; - let doc_parser = doc::DocParser::new( - &graph, + generate_doc_nodes_for_builtin_types( + doc_flags.clone(), + cli_options, capturing_parser, - doc::DocParserOptions { - diagnostics: false, - private: doc_flags.private, - }, - )?; - let nodes = doc_parser.parse_module(&source_file_specifier)?.definitions; - - IndexMap::from([(source_file_specifier, nodes)]) + &analyzer, + ) + .await? } DocSourceFileFlag::Paths(ref source_files) => { let module_graph_builder = factory.module_graph_builder().await?; From a481f5240bb09a6ddd20454a4d44b470137f5ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Tue, 31 Oct 2023 12:49:36 +0100 Subject: [PATCH 09/16] Leo's review --- cli/args/flags.rs | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/cli/args/flags.rs b/cli/args/flags.rs index 35c7f32b3e3e69..aa06b3de93a61d 100644 --- a/cli/args/flags.rs +++ b/cli/args/flags.rs @@ -108,7 +108,7 @@ impl Default for DocSourceFileFlag { #[derive(Clone, Debug, Eq, PartialEq)] pub struct DocHtmlFlag { pub name: String, - pub output: String, + pub output: PathBuf, } #[derive(Clone, Debug, Eq, PartialEq)] @@ -1386,6 +1386,8 @@ Show documentation for runtime built-ins: .help("Directory for HTML documentation output") .action(ArgAction::Set) .require_equals(true) + .value_hint(ValueHint::DirPath) + .value_parser(value_parser!(PathBuf)) ) .arg( Arg::new("private") @@ -3182,20 +3184,11 @@ fn doc_parse(flags: &mut Flags, matches: &mut ArgMatches) { let private = matches.get_flag("private"); let json = matches.get_flag("json"); let filter = matches.remove_one::("filter"); - let html = matches.get_flag("html"); - let name = if html { - matches.remove_one::("name").unwrap() - } else { - "".to_string() - }; - let output = if html { - matches - .remove_one::("output") - .unwrap_or(String::from("./docs/")) - } else { - "".to_string() - }; - let html = if html { + let html = if matches.get_flag("html") { + let name = matches.remove_one::("name").unwrap(); + let output = matches + .remove_one::("output") + .unwrap_or(PathBuf::from("./docs/")); Some(DocHtmlFlag { name, output }) } else { None @@ -7380,7 +7373,7 @@ mod tests { json: false, html: Some(DocHtmlFlag { name: "My library".to_string(), - output: "./docs/".to_string(), + output: PathBuf::from("./docs/"), }), source_files: DocSourceFileFlag::Paths(svec!["path/to/module.ts"]), filter: None, @@ -7405,7 +7398,7 @@ mod tests { json: false, html: Some(DocHtmlFlag { name: "My library".to_string(), - output: "./foo".to_string(), + output: PathBuf::from("./foo"), }), source_files: DocSourceFileFlag::Paths(svec!["path/to/module.ts"]), filter: None, From afc2ddd5cf4376d8c5db89664ac3f3b77febd79c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Tue, 31 Oct 2023 14:39:54 +0100 Subject: [PATCH 10/16] lint --- cli/tools/doc.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/tools/doc.rs b/cli/tools/doc.rs index 83f96ca182c1ce..a818523d674c6c 100644 --- a/cli/tools/doc.rs +++ b/cli/tools/doc.rs @@ -130,7 +130,7 @@ pub async fn doc(flags: Flags, doc_flags: DocFlags) -> Result<(), AnyError> { IndexMap::with_capacity(module_specifiers.len()); for module_specifier in &module_specifiers { - let nodes = doc_parser.parse_with_reexports(&module_specifier)?; + let nodes = doc_parser.parse_with_reexports(module_specifier)?; doc_nodes_by_url.insert(module_specifier.clone(), nodes); } @@ -144,7 +144,7 @@ pub async fn doc(flags: Flags, doc_flags: DocFlags) -> Result<(), AnyError> { .await } else { let doc_nodes: Vec = - doc_nodes_by_url.values().cloned().flatten().collect(); + doc_nodes_by_url.values().flatten().cloned().collect(); print_docs(doc_flags, doc_nodes) } } @@ -160,7 +160,7 @@ async fn generate_docs_directory( package_name: html_options.name, }; - let html = deno_doc::html::generate(options.clone(), &doc_nodes_by_url)?; + let html = deno_doc::html::generate(options.clone(), doc_nodes_by_url)?; let path = &output_dir_resolved; let _ = std::fs::remove_dir_all(path); From f334469962949b2024669f49294c6e6f44bfa96c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Tue, 31 Oct 2023 23:57:09 +0100 Subject: [PATCH 11/16] add tests --- Cargo.lock | 2 +- cli/tests/integration/doc_tests.rs | 35 ++++++++++++++++++++++++++++++ cli/tools/doc.rs | 26 +++++++++++++++++----- 3 files changed, 56 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 133b724cee36fc..105239bf86f204 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1297,7 +1297,7 @@ dependencies = [ [[package]] name = "deno_doc" version = "0.71.0" -source = "git+https://github.com/denoland/deno_doc?branch=main#c014267b04f6ba061434f58b87b2cbb8eaa27958" +source = "git+https://github.com/denoland/deno_doc?branch=main#ce71bb319d52b345e3483b4a22522155be092538" dependencies = [ "anyhow", "cfg-if 1.0.0", diff --git a/cli/tests/integration/doc_tests.rs b/cli/tests/integration/doc_tests.rs index a16f99dd9a5eec..6f813f2665ae1b 100644 --- a/cli/tests/integration/doc_tests.rs +++ b/cli/tests/integration/doc_tests.rs @@ -64,6 +64,12 @@ itest!(deno_doc_lint_referenced_private_types_fixed { output: "doc/referenced_private_types_fixed.out", }); +itest!(deno_doc_html_lint_referenced_private_types_fixed { + args: "doc --lint --html --name=Library doc/referenced_private_types.ts", + exit_code: 1, + output: "doc/referenced_private_types.out", +}); + itest!(_060_deno_doc_displays_all_overloads_in_details_view { args: "doc --filter NS.test doc/060_deno_doc_displays_all_overloads_in_details_view.ts", @@ -96,3 +102,32 @@ itest!(doc_no_lock { cwd: Some("lockfile/basic"), output: "lockfile/basic/doc.nolock.out", }); + +#[test] +fn deno_doc_html() { + let context = TestContext::default(); + let temp_dir = context.temp_dir(); + let output = context + .new_command() + .env("NO_COLOR", "1") + .args_vec(vec![ + "doc", + "--html", + "--name=MyLib", + &format!("--output={}", temp_dir.path().to_string_lossy().to_string()), + "doc/referenced_private_types_fixed.ts", + ]) + .split_output() + .run(); + + output.assert_exit_code(0); + assert_contains!(output.stdout(), "Written 8 files to"); + assert!(temp_dir.path().join("index.html").exists()); + assert!(temp_dir.path().join("compound_index.html").exists()); + assert!(temp_dir.path().join("fuse.js").exists()); + assert!(temp_dir.path().join("search.js").exists()); + assert!(temp_dir.path().join("search_index.js").exists()); + assert!(temp_dir.path().join("styles.css").exists()); + assert!(temp_dir.path().join("MyInterface.html").exists()); + assert!(temp_dir.path().join("MyClass.html").exists()); +} diff --git a/cli/tools/doc.rs b/cli/tools/doc.rs index 5851a25a2ef076..901f084d1e2f61 100644 --- a/cli/tools/doc.rs +++ b/cli/tools/doc.rs @@ -167,19 +167,33 @@ async fn generate_docs_directory( package_name: html_options.name, }; - let html = deno_doc::html::generate(options.clone(), doc_nodes_by_url)?; + let files = deno_doc::html::generate(options, doc_nodes_by_url) + .context("Failed to generate HTML documentation")?; let path = &output_dir_resolved; let _ = std::fs::remove_dir_all(path); - std::fs::create_dir(path)?; + std::fs::create_dir(path) + .with_context(|| format!("Failed to create directory {:?}", path))?; - for (name, content) in html { + let no_of_files = files.len(); + for (name, content) in files { let this_path = path.join(name); - let prefix = this_path.parent().unwrap(); - std::fs::create_dir_all(prefix).unwrap(); - std::fs::write(this_path, content).unwrap(); + let prefix = this_path.parent().with_context(|| { + format!("Failed to get parent path for {:?}", this_path) + })?; + std::fs::create_dir_all(prefix) + .with_context(|| format!("Failed to create directory {:?}", prefix))?; + std::fs::write(&this_path, content) + .with_context(|| format!("Failed to write file {:?}", this_path))?; } + println!( + "{}", + colors::green(format!( + "Written {} files to {:?}", + no_of_files, html_options.output + )) + ); Ok(()) } From 75ee0d3db11d8abd76a2cf26eb067d0e6e78b7a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Wed, 1 Nov 2023 00:05:49 +0100 Subject: [PATCH 12/16] globs, fix tests --- cli/tests/integration/doc_tests.rs | 2 +- cli/tools/doc.rs | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/cli/tests/integration/doc_tests.rs b/cli/tests/integration/doc_tests.rs index 6f813f2665ae1b..b1852f723f1bbd 100644 --- a/cli/tests/integration/doc_tests.rs +++ b/cli/tests/integration/doc_tests.rs @@ -67,7 +67,7 @@ itest!(deno_doc_lint_referenced_private_types_fixed { itest!(deno_doc_html_lint_referenced_private_types_fixed { args: "doc --lint --html --name=Library doc/referenced_private_types.ts", exit_code: 1, - output: "doc/referenced_private_types.out", + output: "doc/referenced_private_types_lint.out", }); itest!(_060_deno_doc_displays_all_overloads_in_details_view { diff --git a/cli/tools/doc.rs b/cli/tools/doc.rs index 901f084d1e2f61..f723c8fd7eade5 100644 --- a/cli/tools/doc.rs +++ b/cli/tools/doc.rs @@ -12,6 +12,7 @@ use crate::factory::CliFactory; use crate::graph_util::graph_lock_or_exit; use crate::graph_util::CreateGraphOptions; use crate::tsc::get_types_declaration_file_text; +use crate::util::glob::expand_globs; use deno_core::anyhow::bail; use deno_core::anyhow::Context; use deno_core::error::AnyError; @@ -26,6 +27,7 @@ use deno_graph::ModuleSpecifier; use doc::DocDiagnostic; use indexmap::IndexMap; use std::collections::BTreeMap; +use std::path::PathBuf; use std::sync::Arc; async fn generate_doc_nodes_for_builtin_types( @@ -97,11 +99,16 @@ pub async fn doc(flags: Flags, doc_flags: DocFlags) -> Result<(), AnyError> { let module_graph_builder = factory.module_graph_builder().await?; let maybe_lockfile = factory.maybe_lockfile(); + let expanded_globs = + expand_globs(source_files.iter().map(|f| PathBuf::from(f)).collect())?; let module_specifiers: Result, AnyError> = - source_files + expanded_globs .iter() .map(|source_file| { - Ok(resolve_url_or_path(source_file, cli_options.initial_cwd())?) + Ok(resolve_url_or_path( + &source_file.to_string_lossy(), + cli_options.initial_cwd(), + )?) }) .collect(); let module_specifiers = module_specifiers?; From 9e02a78b7507bb2f1376581ce2759bc7a3562971 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Wed, 1 Nov 2023 00:13:09 +0100 Subject: [PATCH 13/16] lint --- cli/tests/integration/doc_tests.rs | 2 +- cli/tools/doc.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/tests/integration/doc_tests.rs b/cli/tests/integration/doc_tests.rs index b1852f723f1bbd..06c16af2ea17b8 100644 --- a/cli/tests/integration/doc_tests.rs +++ b/cli/tests/integration/doc_tests.rs @@ -114,7 +114,7 @@ fn deno_doc_html() { "doc", "--html", "--name=MyLib", - &format!("--output={}", temp_dir.path().to_string_lossy().to_string()), + &format!("--output={}", temp_dir.path().to_string_lossy()), "doc/referenced_private_types_fixed.ts", ]) .split_output() diff --git a/cli/tools/doc.rs b/cli/tools/doc.rs index f723c8fd7eade5..bc3bae776f8346 100644 --- a/cli/tools/doc.rs +++ b/cli/tools/doc.rs @@ -100,7 +100,7 @@ pub async fn doc(flags: Flags, doc_flags: DocFlags) -> Result<(), AnyError> { let maybe_lockfile = factory.maybe_lockfile(); let expanded_globs = - expand_globs(source_files.iter().map(|f| PathBuf::from(f)).collect())?; + expand_globs(source_files.iter().map(PathBuf::from).collect())?; let module_specifiers: Result, AnyError> = expanded_globs .iter() From c379f46a82031e43d04aa5a13faf280a29419747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Wed, 1 Nov 2023 01:10:32 +0100 Subject: [PATCH 14/16] update to new void output --- Cargo.lock | 9 +++++---- cli/Cargo.toml | 2 +- cli/tests/testdata/doc/use_import_map.out | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 105239bf86f204..6163548f51a835 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1296,8 +1296,9 @@ dependencies = [ [[package]] name = "deno_doc" -version = "0.71.0" -source = "git+https://github.com/denoland/deno_doc?branch=main#ce71bb319d52b345e3483b4a22522155be092538" +version = "0.72.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "277051ea4bb6b321efffe2099e331f86659c7daed8a6b877552ac82a595e6969" dependencies = [ "anyhow", "cfg-if 1.0.0", @@ -6440,8 +6441,8 @@ version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ - "cfg-if 0.1.10", - "rand 0.7.3", + "cfg-if 1.0.0", + "rand 0.8.5", "static_assertions", ] diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 714e0b86bcbd04..5e6cad4c972623 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -49,7 +49,7 @@ deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "dep_gra deno_cache_dir = "=0.6.1" deno_config = "=0.4.0" deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] } -deno_doc = { git = "https://github.com/denoland/deno_doc", branch = "main", features = ["html"] } +deno_doc = { version = "=0.72.0", features = ["html"] } deno_emit = "=0.31.1" deno_graph = "=0.59.1" deno_lint = { version = "=0.52.2", features = ["docs"] } diff --git a/cli/tests/testdata/doc/use_import_map.out b/cli/tests/testdata/doc/use_import_map.out index c27a313f4f6962..9509d5bfe19813 100644 --- a/cli/tests/testdata/doc/use_import_map.out +++ b/cli/tests/testdata/doc/use_import_map.out @@ -1,5 +1,5 @@ Defined in [WILDCARD]/doc/module/fun.js:2:1 -function fun(_a, _b) +function fun(_a, _b): void This is some documentation From 74d1b0a35fc1d71e3f2246fcc52294b9c209555b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Wed, 1 Nov 2023 13:55:44 +0100 Subject: [PATCH 15/16] remove unstable, use log::info! --- cli/args/flags.rs | 2 +- cli/tools/doc.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/args/flags.rs b/cli/args/flags.rs index a825d6b0c080d6..e2c03e5645a8fc 100644 --- a/cli/args/flags.rs +++ b/cli/args/flags.rs @@ -1373,7 +1373,7 @@ Show documentation for runtime built-ins: .arg( Arg::new("html") .long("html") - .help("UNSTABLE: Output documentation in HTML format") + .help("Output documentation in HTML format") .action(ArgAction::SetTrue) .conflicts_with("json") ) diff --git a/cli/tools/doc.rs b/cli/tools/doc.rs index bc3bae776f8346..9c88c8e84521f1 100644 --- a/cli/tools/doc.rs +++ b/cli/tools/doc.rs @@ -194,7 +194,7 @@ async fn generate_docs_directory( .with_context(|| format!("Failed to write file {:?}", this_path))?; } - println!( + log::info!( "{}", colors::green(format!( "Written {} files to {:?}", From 916d4ae27aa2becd3c729ddc3e6cf4bf480302f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Wed, 1 Nov 2023 14:27:13 +0100 Subject: [PATCH 16/16] update test --- cli/tests/integration/doc_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/tests/integration/doc_tests.rs b/cli/tests/integration/doc_tests.rs index 06c16af2ea17b8..f5ac44a02a86fc 100644 --- a/cli/tests/integration/doc_tests.rs +++ b/cli/tests/integration/doc_tests.rs @@ -121,7 +121,7 @@ fn deno_doc_html() { .run(); output.assert_exit_code(0); - assert_contains!(output.stdout(), "Written 8 files to"); + assert_contains!(output.stderr(), "Written 8 files to"); assert!(temp_dir.path().join("index.html").exists()); assert!(temp_dir.path().join("compound_index.html").exists()); assert!(temp_dir.path().join("fuse.js").exists());