diff --git a/cli/doc/mod.rs b/cli/doc/mod.rs index 49f8d7453edb3fa48ba7426dc45961904fd2ef22..d015d9e4c06909a2647c6dcd99a1730a498fa254 100644 --- a/cli/doc/mod.rs +++ b/cli/doc/mod.rs @@ -17,6 +17,7 @@ pub mod variable; pub use node::DocNode; pub use node::DocNodeKind; +pub use node::ImportDef; pub use node::Location; pub use params::ParamDef; pub use parser::DocParser; diff --git a/cli/doc/module.rs b/cli/doc/module.rs index 74d5361eb1ad9001a7fdf470e714c59fbdc7d014..cd0fdbd45a66a785dbb12b9392f834ea0d600ee6 100644 --- a/cli/doc/module.rs +++ b/cli/doc/module.rs @@ -31,6 +31,7 @@ pub fn get_doc_node_for_export_decl( type_alias_def: None, namespace_def: None, interface_def: None, + import_def: None, } } Decl::Fn(fn_decl) => { @@ -48,6 +49,7 @@ pub fn get_doc_node_for_export_decl( type_alias_def: None, namespace_def: None, interface_def: None, + import_def: None, } } Decl::Var(var_decl) => { @@ -64,6 +66,7 @@ pub fn get_doc_node_for_export_decl( type_alias_def: None, namespace_def: None, interface_def: None, + import_def: None, } } Decl::TsInterface(ts_interface_decl) => { @@ -84,6 +87,7 @@ pub fn get_doc_node_for_export_decl( enum_def: None, type_alias_def: None, namespace_def: None, + import_def: None, } } Decl::TsTypeAlias(ts_type_alias) => { @@ -104,6 +108,7 @@ pub fn get_doc_node_for_export_decl( class_def: None, enum_def: None, namespace_def: None, + import_def: None, } } Decl::TsEnum(ts_enum) => { @@ -121,6 +126,7 @@ pub fn get_doc_node_for_export_decl( function_def: None, class_def: None, namespace_def: None, + import_def: None, } } Decl::TsModule(ts_module) => { @@ -138,6 +144,7 @@ pub fn get_doc_node_for_export_decl( variable_def: None, function_def: None, class_def: None, + import_def: None, } } } diff --git a/cli/doc/namespace.rs b/cli/doc/namespace.rs index 35f9233fdf52bcbffe272e6de2ad09d603765310..17e1d2eb78e05cf25eb859263c3cf9c9f4c51629 100644 --- a/cli/doc/namespace.rs +++ b/cli/doc/namespace.rs @@ -46,6 +46,7 @@ pub fn get_doc_for_ts_namespace_decl( class_def: None, type_alias_def: None, interface_def: None, + import_def: None, } } diff --git a/cli/doc/node.rs b/cli/doc/node.rs index 4946924c622df48bf32dc0b189db46a2993cf012..980a5d8b9f2410a04d6ace4d944c175c2174b34f 100644 --- a/cli/doc/node.rs +++ b/cli/doc/node.rs @@ -11,6 +11,7 @@ pub enum DocNodeKind { Interface, TypeAlias, Namespace, + Import, } #[derive(Debug, Serialize, Clone, PartialEq)] @@ -67,6 +68,13 @@ pub struct ModuleDoc { pub reexports: Vec, } +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ImportDef { + pub src: String, + pub imported: Option, +} + #[derive(Debug, Serialize, Clone)] #[serde(rename_all = "camelCase")] pub struct DocNode { @@ -95,4 +103,7 @@ pub struct DocNode { #[serde(skip_serializing_if = "Option::is_none")] pub interface_def: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub import_def: Option, } diff --git a/cli/doc/parser.rs b/cli/doc/parser.rs index e185e5bffb1952ec01bb44094da3005cd39887ee..2247c68778a53bd400e1855e2466e4c1c0ad9be6 100644 --- a/cli/doc/parser.rs +++ b/cli/doc/parser.rs @@ -2,7 +2,6 @@ use crate::file_fetcher::map_file_extension; use crate::op_error::OpError; use crate::swc_util::AstParser; -use crate::swc_util::SwcDiagnosticBuffer; use swc_common::comments::CommentKind; use swc_common::Span; use swc_ecmascript::ast::Decl; @@ -23,6 +22,7 @@ use super::node; use super::node::ModuleDoc; use super::DocNode; use super::DocNodeKind; +use super::ImportDef; use super::Location; pub trait DocFileLoader { @@ -59,14 +59,18 @@ impl DocParser { &self, file_name: &str, source_code: &str, - ) -> Result { + ) -> Result { 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 doc_entries = self.get_doc_nodes_for_module_body(module.body.clone()); + 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, @@ -138,6 +142,7 @@ impl DocParser { variable_def: None, function_def: None, class_def: None, + import_def: None, }; processed_reexports.push(ns_doc_node); } @@ -193,6 +198,72 @@ impl DocParser { Ok(flattened_docs) } + fn get_doc_nodes_for_module_imports( + &self, + module_body: Vec, + referrer: &str, + ) -> Result, 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 { + kind: DocNodeKind::Import, + name, + location: location.clone(), + js_doc: js_doc.clone(), + import_def: Some(import_def), + class_def: None, + function_def: None, + variable_def: None, + enum_def: None, + type_alias_def: None, + namespace_def: None, + interface_def: None, + }; + + imports.push(doc_node); + } + } + } + } + + Ok(imports) + } + pub fn get_doc_nodes_for_module_exports( &self, module_decl: &ModuleDecl, @@ -225,6 +296,7 @@ impl DocParser { type_alias_def: None, namespace_def: None, interface_def: None, + import_def: None, } } DefaultDecl::Fn(fn_expr) => { @@ -244,6 +316,7 @@ impl DocParser { type_alias_def: None, namespace_def: None, interface_def: None, + import_def: None, } } DefaultDecl::TsInterfaceDecl(interface_decl) => { @@ -264,6 +337,7 @@ impl DocParser { type_alias_def: None, namespace_def: None, interface_def: Some(interface_def), + import_def: None, } } }; @@ -309,6 +383,7 @@ impl DocParser { type_alias_def: None, namespace_def: None, interface_def: None, + import_def: None, }) } Decl::Fn(fn_decl) => { @@ -330,6 +405,7 @@ impl DocParser { type_alias_def: None, namespace_def: None, interface_def: None, + import_def: None, }) } Decl::Var(var_decl) => { @@ -350,6 +426,7 @@ impl DocParser { type_alias_def: None, namespace_def: None, interface_def: None, + import_def: None, }) } Decl::TsInterface(ts_interface_decl) => { @@ -374,6 +451,7 @@ impl DocParser { enum_def: None, type_alias_def: None, namespace_def: None, + import_def: None, }) } Decl::TsTypeAlias(ts_type_alias) => { @@ -398,6 +476,7 @@ impl DocParser { class_def: None, enum_def: None, namespace_def: None, + import_def: None, }) } Decl::TsEnum(ts_enum) => { @@ -419,6 +498,7 @@ impl DocParser { function_def: None, class_def: None, namespace_def: None, + import_def: None, }) } Decl::TsModule(ts_module) => { @@ -440,6 +520,7 @@ impl DocParser { variable_def: None, function_def: None, class_def: None, + import_def: None, }) } } diff --git a/cli/doc/printer.rs b/cli/doc/printer.rs index a3ecd2718e3600073fa5bbf638a32d0b5df02e35..5ba5154c5a1d45ce7bf49d5f1af2f8f6d3d297a7 100644 --- a/cli/doc/printer.rs +++ b/cli/doc/printer.rs @@ -129,6 +129,7 @@ impl<'a> DocPrinter<'a> { DocNodeKind::Interface => 4, DocNodeKind::TypeAlias => 5, DocNodeKind::Namespace => 6, + DocNodeKind::Import => 7, } } @@ -152,6 +153,7 @@ impl<'a> DocPrinter<'a> { DocNodeKind::Namespace => { self.format_namespace_signature(w, node, indent) } + DocNodeKind::Import => Ok(()), } } diff --git a/cli/doc/tests.rs b/cli/doc/tests.rs index e46fff62105571d8f586d5ea01aa1a76c641f351..94d087ea3b7ca20b4e91f828fabbe873377bdc0f 100644 --- a/cli/doc/tests.rs +++ b/cli/doc/tests.rs @@ -153,9 +153,12 @@ import { bar } from "./nested_reexport.ts"; * JSDoc for const */ export const foo = "foo"; + +export const fizz = "fizz"; "#; let test_source_code = r#" export { default, foo as fooConst } from "./reexport.ts"; +import { fizz as buzz } from "./reexport.ts"; /** JSDoc for function */ export function fooFn(a: number) { @@ -177,7 +180,7 @@ export function fooFn(a: number) { .parse_with_reexports("file:///test.ts") .await .unwrap(); - assert_eq!(entries.len(), 2); + assert_eq!(entries.len(), 3); let expected_json = json!([ { @@ -199,7 +202,7 @@ export function fooFn(a: number) { "name": "fooFn", "location": { "filename": "file:///test.ts", - "line": 5, + "line": 6, "col": 0 }, "jsDoc": "JSDoc for function", @@ -220,6 +223,20 @@ export function fooFn(a: number) { "returnType": null, "isAsync": false, "isGenerator": false + }, + }, + { + "kind": "import", + "name": "buzz", + "location": { + "filename": "file:///test.ts", + "line": 3, + "col": 0 + }, + "jsDoc": null, + "importDef": { + "src": "file:///reexport.ts", + "imported": "fizz", } } ]); diff --git a/cli/main.rs b/cli/main.rs index 0c84e7b3e48f4109bd4a65b96cf2ceae67d05f45..799d47e32c15f8d55c714ac5114e8699fd4f8718 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -532,7 +532,7 @@ async fn doc_command( .await }; - let doc_nodes = match parse_result { + let mut doc_nodes = match parse_result { Ok(nodes) => nodes, Err(e) => { eprintln!("{}", e); @@ -543,6 +543,7 @@ async fn doc_command( 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());