summaryrefslogtreecommitdiff
path: root/cli/doc/parser.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/doc/parser.rs')
-rw-r--r--cli/doc/parser.rs505
1 files changed, 0 insertions, 505 deletions
diff --git a/cli/doc/parser.rs b/cli/doc/parser.rs
deleted file mode 100644
index 8950ad74b..000000000
--- a/cli/doc/parser.rs
+++ /dev/null
@@ -1,505 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-use crate::file_fetcher::map_file_extension;
-use crate::op_error::OpError;
-use crate::swc_util::AstParser;
-use swc_common::comments::CommentKind;
-use swc_common::Span;
-use swc_ecmascript::ast::Decl;
-use swc_ecmascript::ast::DefaultDecl;
-use swc_ecmascript::ast::ModuleDecl;
-use swc_ecmascript::ast::Stmt;
-
-use deno_core::ErrBox;
-use deno_core::ModuleSpecifier;
-use futures::Future;
-use regex::Regex;
-use std::collections::HashMap;
-use std::path::PathBuf;
-use std::pin::Pin;
-
-use super::namespace::NamespaceDef;
-use super::node;
-use super::node::ModuleDoc;
-use super::DocNode;
-use super::DocNodeKind;
-use super::ImportDef;
-use super::Location;
-
-pub trait DocFileLoader {
- fn resolve(
- &self,
- specifier: &str,
- referrer: &str,
- ) -> Result<ModuleSpecifier, OpError> {
- ModuleSpecifier::resolve_import(specifier, referrer).map_err(OpError::from)
- }
-
- fn load_source_code(
- &self,
- specifier: &str,
- ) -> Pin<Box<dyn Future<Output = Result<String, OpError>>>>;
-}
-
-pub struct DocParser {
- pub ast_parser: AstParser,
- pub loader: Box<dyn DocFileLoader>,
- pub private: bool,
-}
-
-impl DocParser {
- pub fn new(loader: Box<dyn DocFileLoader>, private: bool) -> Self {
- DocParser {
- loader,
- ast_parser: AstParser::default(),
- private,
- }
- }
-
- fn parse_module(
- &self,
- file_name: &str,
- source_code: &str,
- ) -> Result<ModuleDoc, ErrBox> {
- let media_type = map_file_extension(&PathBuf::from(file_name));
- let parse_result =
- self
- .ast_parser
- .parse_module(file_name, media_type, source_code);
- let module = parse_result?;
- let mut doc_entries =
- self.get_doc_nodes_for_module_body(module.body.clone());
- let import_doc_entries =
- self.get_doc_nodes_for_module_imports(module.body.clone(), file_name)?;
- doc_entries.extend(import_doc_entries);
- let reexports = self.get_reexports_for_module_body(module.body);
- let module_doc = ModuleDoc {
- definitions: doc_entries,
- reexports,
- };
- Ok(module_doc)
- }
-
- pub async fn parse(&self, file_name: &str) -> Result<Vec<DocNode>, ErrBox> {
- let source_code = self.loader.load_source_code(file_name).await?;
-
- self.parse_source(file_name, source_code.as_str())
- }
-
- pub fn parse_source(
- &self,
- file_name: &str,
- source_code: &str,
- ) -> Result<Vec<DocNode>, ErrBox> {
- let module_doc = self.parse_module(file_name, &source_code)?;
- Ok(module_doc.definitions)
- }
-
- async fn flatten_reexports(
- &self,
- reexports: &[node::Reexport],
- referrer: &str,
- ) -> Result<Vec<DocNode>, ErrBox> {
- let mut by_src: HashMap<String, Vec<node::Reexport>> = HashMap::new();
-
- let mut processed_reexports: Vec<DocNode> = vec![];
-
- for reexport in reexports {
- if by_src.get(&reexport.src).is_none() {
- by_src.insert(reexport.src.to_string(), vec![]);
- }
-
- let bucket = by_src.get_mut(&reexport.src).unwrap();
- bucket.push(reexport.clone());
- }
-
- for specifier in by_src.keys() {
- let resolved_specifier = self.loader.resolve(specifier, referrer)?;
- let doc_nodes = self.parse(&resolved_specifier.to_string()).await?;
- let reexports_for_specifier = by_src.get(specifier).unwrap();
-
- for reexport in reexports_for_specifier {
- match &reexport.kind {
- node::ReexportKind::All => {
- processed_reexports.extend(doc_nodes.clone())
- }
- node::ReexportKind::Namespace(ns_name) => {
- let ns_def = NamespaceDef {
- elements: doc_nodes.clone(),
- };
- let ns_doc_node = DocNode {
- kind: DocNodeKind::Namespace,
- name: ns_name.to_string(),
- location: Location {
- filename: specifier.to_string(),
- line: 1,
- col: 0,
- },
- js_doc: None,
- namespace_def: Some(ns_def),
- enum_def: None,
- type_alias_def: None,
- interface_def: None,
- variable_def: None,
- function_def: None,
- class_def: None,
- import_def: None,
- };
- processed_reexports.push(ns_doc_node);
- }
- node::ReexportKind::Named(ident, maybe_alias) => {
- // Try to find reexport.
- // NOTE: the reexport might actually be reexport from another
- // module; for now we're skipping nested reexports.
- let maybe_doc_node =
- doc_nodes.iter().find(|node| &node.name == ident);
-
- if let Some(doc_node) = maybe_doc_node {
- let doc_node = doc_node.clone();
- let doc_node = if let Some(alias) = maybe_alias {
- DocNode {
- name: alias.to_string(),
- ..doc_node
- }
- } else {
- doc_node
- };
-
- processed_reexports.push(doc_node);
- }
- }
- node::ReexportKind::Default => {
- // TODO: handle default export from child module
- }
- }
- }
- }
-
- Ok(processed_reexports)
- }
-
- pub async fn parse_with_reexports(
- &self,
- file_name: &str,
- ) -> Result<Vec<DocNode>, ErrBox> {
- let source_code = self.loader.load_source_code(file_name).await?;
-
- let module_doc = self.parse_module(file_name, &source_code)?;
-
- let flattened_docs = if !module_doc.reexports.is_empty() {
- let mut flattenned_reexports = self
- .flatten_reexports(&module_doc.reexports, file_name)
- .await?;
- flattenned_reexports.extend(module_doc.definitions);
- flattenned_reexports
- } else {
- module_doc.definitions
- };
-
- Ok(flattened_docs)
- }
-
- fn get_doc_nodes_for_module_imports(
- &self,
- module_body: Vec<swc_ecmascript::ast::ModuleItem>,
- referrer: &str,
- ) -> Result<Vec<DocNode>, ErrBox> {
- let mut imports = vec![];
-
- for node in module_body.iter() {
- if let swc_ecmascript::ast::ModuleItem::ModuleDecl(module_decl) = node {
- if let ModuleDecl::Import(import_decl) = module_decl {
- let (js_doc, location) = self.details_for_span(import_decl.span);
- for specifier in &import_decl.specifiers {
- use swc_ecmascript::ast::ImportSpecifier::*;
-
- let (name, maybe_imported_name, src) = match specifier {
- Named(named_specifier) => (
- named_specifier.local.sym.to_string(),
- named_specifier
- .imported
- .as_ref()
- .map(|ident| ident.sym.to_string())
- .or_else(|| Some(named_specifier.local.sym.to_string())),
- import_decl.src.value.to_string(),
- ),
- Default(default_specifier) => (
- default_specifier.local.sym.to_string(),
- Some("default".to_string()),
- import_decl.src.value.to_string(),
- ),
- Namespace(namespace_specifier) => (
- namespace_specifier.local.sym.to_string(),
- None,
- import_decl.src.value.to_string(),
- ),
- };
-
- let resolved_specifier = self.loader.resolve(&src, referrer)?;
- let import_def = ImportDef {
- src: resolved_specifier.to_string(),
- imported: maybe_imported_name,
- };
-
- let doc_node = DocNode::import(
- name,
- location.clone(),
- js_doc.clone(),
- import_def,
- );
-
- imports.push(doc_node);
- }
- }
- }
- }
-
- Ok(imports)
- }
-
- pub fn get_doc_nodes_for_module_exports(
- &self,
- module_decl: &ModuleDecl,
- ) -> Vec<DocNode> {
- match module_decl {
- ModuleDecl::ExportDecl(export_decl) => {
- vec![super::module::get_doc_node_for_export_decl(
- self,
- export_decl,
- )]
- }
- ModuleDecl::ExportDefaultDecl(export_default_decl) => {
- let (js_doc, location) =
- self.details_for_span(export_default_decl.span);
- let name = "default".to_string();
-
- let doc_node = match &export_default_decl.decl {
- DefaultDecl::Class(class_expr) => {
- let class_def =
- crate::doc::class::class_to_class_def(self, &class_expr.class);
- DocNode::class(name, location, js_doc, class_def)
- }
- DefaultDecl::Fn(fn_expr) => {
- let function_def = crate::doc::function::function_to_function_def(
- self,
- &fn_expr.function,
- );
- DocNode::function(name, location, js_doc, function_def)
- }
- DefaultDecl::TsInterfaceDecl(interface_decl) => {
- let (_, interface_def) =
- crate::doc::interface::get_doc_for_ts_interface_decl(
- self,
- interface_decl,
- );
- DocNode::interface(name, location, js_doc, interface_def)
- }
- };
-
- vec![doc_node]
- }
- ModuleDecl::ExportDefaultExpr(_export_default_expr) => vec![],
- _ => vec![],
- }
- }
-
- pub fn get_doc_node_for_stmt(&self, stmt: &Stmt) -> Option<DocNode> {
- match stmt {
- Stmt::Decl(decl) => self.get_doc_node_for_decl(decl),
- _ => None,
- }
- }
-
- fn details_for_span(&self, span: Span) -> (Option<String>, Location) {
- let js_doc = self.js_doc_for_span(span);
- let location = self.ast_parser.get_span_location(span).into();
- (js_doc, location)
- }
-
- pub fn get_doc_node_for_decl(&self, decl: &Decl) -> Option<DocNode> {
- match decl {
- Decl::Class(class_decl) => {
- if !self.private && !class_decl.declare {
- return None;
- }
- let (name, class_def) =
- super::class::get_doc_for_class_decl(self, class_decl);
- let (js_doc, location) = self.details_for_span(class_decl.class.span);
- Some(DocNode::class(name, location, js_doc, class_def))
- }
- Decl::Fn(fn_decl) => {
- if !self.private && !fn_decl.declare {
- return None;
- }
- let (name, function_def) =
- super::function::get_doc_for_fn_decl(self, fn_decl);
- let (js_doc, location) = self.details_for_span(fn_decl.function.span);
- Some(DocNode::function(name, location, js_doc, function_def))
- }
- Decl::Var(var_decl) => {
- if !self.private && !var_decl.declare {
- return None;
- }
- let (name, var_def) = super::variable::get_doc_for_var_decl(var_decl);
- let (js_doc, location) = self.details_for_span(var_decl.span);
- Some(DocNode::variable(name, location, js_doc, var_def))
- }
- Decl::TsInterface(ts_interface_decl) => {
- if !self.private && !ts_interface_decl.declare {
- return None;
- }
- let (name, interface_def) =
- super::interface::get_doc_for_ts_interface_decl(
- self,
- ts_interface_decl,
- );
- let (js_doc, location) = self.details_for_span(ts_interface_decl.span);
- Some(DocNode::interface(name, location, js_doc, interface_def))
- }
- Decl::TsTypeAlias(ts_type_alias) => {
- if !self.private && !ts_type_alias.declare {
- return None;
- }
- let (name, type_alias_def) =
- super::type_alias::get_doc_for_ts_type_alias_decl(
- self,
- ts_type_alias,
- );
- let (js_doc, location) = self.details_for_span(ts_type_alias.span);
- Some(DocNode::type_alias(name, location, js_doc, type_alias_def))
- }
- Decl::TsEnum(ts_enum) => {
- if !self.private && !ts_enum.declare {
- return None;
- }
- let (name, enum_def) =
- super::r#enum::get_doc_for_ts_enum_decl(self, ts_enum);
- let (js_doc, location) = self.details_for_span(ts_enum.span);
- Some(DocNode::r#enum(name, location, js_doc, enum_def))
- }
- Decl::TsModule(ts_module) => {
- if !self.private && !ts_module.declare {
- return None;
- }
- let (name, namespace_def) =
- super::namespace::get_doc_for_ts_module(self, ts_module);
- let (js_doc, location) = self.details_for_span(ts_module.span);
- Some(DocNode::namespace(name, location, js_doc, namespace_def))
- }
- }
- }
-
- pub fn get_reexports_for_module_body(
- &self,
- module_body: Vec<swc_ecmascript::ast::ModuleItem>,
- ) -> Vec<node::Reexport> {
- use swc_ecmascript::ast::ExportSpecifier::*;
-
- let mut reexports: Vec<node::Reexport> = vec![];
-
- for node in module_body.iter() {
- if let swc_ecmascript::ast::ModuleItem::ModuleDecl(module_decl) = node {
- let r = match module_decl {
- ModuleDecl::ExportNamed(named_export) => {
- if let Some(src) = &named_export.src {
- let src_str = src.value.to_string();
- named_export
- .specifiers
- .iter()
- .map(|export_specifier| match export_specifier {
- Namespace(ns_export) => node::Reexport {
- kind: node::ReexportKind::Namespace(
- ns_export.name.sym.to_string(),
- ),
- src: src_str.to_string(),
- },
- Default(_) => node::Reexport {
- kind: node::ReexportKind::Default,
- src: src_str.to_string(),
- },
- Named(named_export) => {
- let ident = named_export.orig.sym.to_string();
- let maybe_alias =
- named_export.exported.as_ref().map(|e| e.sym.to_string());
- let kind = node::ReexportKind::Named(ident, maybe_alias);
- node::Reexport {
- kind,
- src: src_str.to_string(),
- }
- }
- })
- .collect::<Vec<node::Reexport>>()
- } else {
- vec![]
- }
- }
- ModuleDecl::ExportAll(export_all) => {
- let reexport = node::Reexport {
- kind: node::ReexportKind::All,
- src: export_all.src.value.to_string(),
- };
- vec![reexport]
- }
- _ => vec![],
- };
-
- reexports.extend(r);
- }
- }
-
- reexports
- }
-
- pub fn get_doc_nodes_for_module_body(
- &self,
- module_body: Vec<swc_ecmascript::ast::ModuleItem>,
- ) -> Vec<DocNode> {
- let mut doc_entries: Vec<DocNode> = vec![];
- for node in module_body.iter() {
- match node {
- swc_ecmascript::ast::ModuleItem::ModuleDecl(module_decl) => {
- doc_entries
- .extend(self.get_doc_nodes_for_module_exports(module_decl));
- }
- swc_ecmascript::ast::ModuleItem::Stmt(stmt) => {
- if let Some(doc_node) = self.get_doc_node_for_stmt(stmt) {
- doc_entries.push(doc_node);
- }
- }
- }
- }
- doc_entries
- }
-
- pub fn js_doc_for_span(&self, span: Span) -> Option<String> {
- let comments = self.ast_parser.get_span_comments(span);
- let js_doc_comment = comments.iter().rev().find(|comment| {
- comment.kind == CommentKind::Block && comment.text.starts_with('*')
- })?;
-
- let mut margin_pat = String::from("");
- if let Some(margin) = self.ast_parser.source_map.span_to_margin(span) {
- for _ in 0..margin {
- margin_pat.push(' ');
- }
- }
-
- let js_doc_re = Regex::new(r#" ?\* ?"#).unwrap();
- let txt = js_doc_comment
- .text
- .split('\n')
- .map(|line| js_doc_re.replace(line, "").to_string())
- .map(|line| {
- if line.starts_with(&margin_pat) {
- line[margin_pat.len()..].to_string()
- } else {
- line
- }
- })
- .collect::<Vec<String>>()
- .join("\n");
-
- let txt = txt.trim_start().trim_end().to_string();
-
- Some(txt)
- }
-}