summaryrefslogtreecommitdiff
path: root/cli/tools
diff options
context:
space:
mode:
Diffstat (limited to 'cli/tools')
-rw-r--r--cli/tools/doc.rs164
-rw-r--r--cli/tools/mod.rs1
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;