diff options
author | Liam Murphy <43807659+Liamolucko@users.noreply.github.com> | 2021-02-26 02:24:05 +1100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-25 16:24:05 +0100 |
commit | cdae4423c27443e0085d59f45eda1c978f186a1c (patch) | |
tree | 74107cebfe5a49a8021ef3fc02c60b30548163be /cli/tools | |
parent | 687ff2ab14d6a735aa5bf0ec57ef00cfe0c04e4b (diff) |
feat(cli/doc): use type definitions "deno doc" if available (#8459)
This commit adds support for type definitions in "deno doc";
with this change "deno doc" is able to leverage the same directives
as TS compiler.
Co-authored-by: Bartek IwaĆczuk <biwanczuk@gmail.com>
Diffstat (limited to 'cli/tools')
-rw-r--r-- | cli/tools/doc.rs | 164 | ||||
-rw-r--r-- | cli/tools/mod.rs | 1 |
2 files changed, 165 insertions, 0 deletions
diff --git a/cli/tools/doc.rs b/cli/tools/doc.rs new file mode 100644 index 000000000..9725076d6 --- /dev/null +++ b/cli/tools/doc.rs @@ -0,0 +1,164 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +use crate::ast; +use crate::colors; +use crate::file_fetcher::File; +use crate::flags::Flags; +use crate::get_types; +use crate::media_type::MediaType; +use crate::module_graph; +use crate::program_state::ProgramState; +use crate::specifier_handler::FetchHandler; +use crate::write_json_to_stdout; +use crate::write_to_stdout_ignore_sigpipe; +use deno_core::error::AnyError; +use deno_core::futures::future::FutureExt; +use deno_core::futures::Future; +use deno_core::resolve_url_or_path; +use deno_doc as doc; +use deno_doc::parser::DocFileLoader; +use deno_runtime::permissions::Permissions; +use std::path::PathBuf; +use std::pin::Pin; +use std::sync::Arc; +use std::sync::Mutex; + +/// When parsing lib.deno.d.ts, only `DocParser::parse_source` is used, +/// which never even references the loader, so this is just a stub for that scenario. +/// +/// TODO(Liamolucko): Refactor `deno_doc` so this isn't necessary. +struct StubDocLoader; + +impl DocFileLoader for StubDocLoader { + fn resolve( + &self, + _specifier: &str, + _referrer: &str, + ) -> Result<String, doc::DocError> { + unreachable!() + } + + fn load_source_code( + &self, + _specifier: &str, + ) -> Pin<Box<dyn Future<Output = Result<String, doc::DocError>>>> { + unreachable!() + } +} + +impl DocFileLoader for module_graph::Graph { + fn resolve( + &self, + specifier: &str, + referrer: &str, + ) -> Result<String, doc::DocError> { + let referrer = + resolve_url_or_path(referrer).expect("Expected valid specifier"); + match self.resolve(specifier, &referrer, true) { + Ok(specifier) => Ok(specifier.to_string()), + Err(e) => Err(doc::DocError::Resolve(e.to_string())), + } + } + + fn load_source_code( + &self, + specifier: &str, + ) -> Pin<Box<dyn Future<Output = Result<String, doc::DocError>>>> { + let specifier = + resolve_url_or_path(specifier).expect("Expected valid specifier"); + let source = self.get_source(&specifier).expect("Unknown dependency"); + async move { Ok(source) }.boxed_local() + } +} + +pub async fn print_docs( + flags: Flags, + source_file: Option<String>, + json: bool, + maybe_filter: Option<String>, + private: bool, +) -> Result<(), AnyError> { + let program_state = ProgramState::build(flags.clone()).await?; + let source_file = source_file.unwrap_or_else(|| "--builtin".to_string()); + + let parse_result = if source_file == "--builtin" { + let loader = Box::new(StubDocLoader); + let doc_parser = doc::DocParser::new(loader, private); + + let syntax = ast::get_syntax(&MediaType::Dts); + doc_parser.parse_source( + "lib.deno.d.ts", + syntax, + get_types(flags.unstable).as_str(), + ) + } else { + let module_specifier = resolve_url_or_path(&source_file).unwrap(); + + // If the root module has external types, the module graph won't redirect it, + // so instead create a dummy file which exports everything from the actual file being documented. + let root_specifier = resolve_url_or_path("./$deno$doc.ts").unwrap(); + let root = File { + local: PathBuf::from("./$deno$doc.ts"), + maybe_types: None, + media_type: MediaType::TypeScript, + source: format!("export * from \"{}\";", module_specifier), + specifier: root_specifier.clone(), + }; + + // Save our fake file into file fetcher cache. + program_state.file_fetcher.insert_cached(root); + + let handler = Arc::new(Mutex::new(FetchHandler::new( + &program_state, + Permissions::allow_all(), + )?)); + let mut builder = module_graph::GraphBuilder::new( + handler, + program_state.maybe_import_map.clone(), + program_state.lockfile.clone(), + ); + builder.add(&root_specifier, false).await?; + let graph = builder.get_graph(); + + let doc_parser = doc::DocParser::new(Box::new(graph), private); + doc_parser + .parse_with_reexports( + root_specifier.as_str(), + ast::get_syntax(&MediaType::TypeScript), + ) + .await + }; + + let mut doc_nodes = match parse_result { + Ok(nodes) => nodes, + Err(e) => { + eprintln!("{}", e); + std::process::exit(1); + } + }; + + if 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) = maybe_filter { + let nodes = + doc::find_nodes_by_name_recursively(doc_nodes, filter.clone()); + if nodes.is_empty() { + eprintln!("Node {} was not found!", filter); + std::process::exit(1); + } + format!( + "{}", + doc::DocPrinter::new(&nodes, colors::use_color(), private) + ) + } else { + format!( + "{}", + doc::DocPrinter::new(&doc_nodes, colors::use_color(), private) + ) + }; + + write_to_stdout_ignore_sigpipe(details.as_bytes()).map_err(AnyError::from) + } +} diff --git a/cli/tools/mod.rs b/cli/tools/mod.rs index 089232b99..cd00f6a86 100644 --- a/cli/tools/mod.rs +++ b/cli/tools/mod.rs @@ -1,6 +1,7 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. pub mod coverage; +pub mod doc; pub mod fmt; pub mod installer; pub mod lint; |