1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-09 15:48:16 -05:00

feat(doc): handle imports (#6987)

This commit adds additional objects to JSON output
of "deno doc" command to facilitate linking between 
types in different modules.
This commit is contained in:
Bartek Iwańczuk 2020-08-10 17:41:19 +02:00 committed by GitHub
parent fdb2dab7cd
commit 6fcf06306e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 127 additions and 6 deletions

View file

@ -17,6 +17,7 @@ pub mod variable;
pub use node::DocNode; pub use node::DocNode;
pub use node::DocNodeKind; pub use node::DocNodeKind;
pub use node::ImportDef;
pub use node::Location; pub use node::Location;
pub use params::ParamDef; pub use params::ParamDef;
pub use parser::DocParser; pub use parser::DocParser;

View file

@ -31,6 +31,7 @@ pub fn get_doc_node_for_export_decl(
type_alias_def: None, type_alias_def: None,
namespace_def: None, namespace_def: None,
interface_def: None, interface_def: None,
import_def: None,
} }
} }
Decl::Fn(fn_decl) => { Decl::Fn(fn_decl) => {
@ -48,6 +49,7 @@ pub fn get_doc_node_for_export_decl(
type_alias_def: None, type_alias_def: None,
namespace_def: None, namespace_def: None,
interface_def: None, interface_def: None,
import_def: None,
} }
} }
Decl::Var(var_decl) => { Decl::Var(var_decl) => {
@ -64,6 +66,7 @@ pub fn get_doc_node_for_export_decl(
type_alias_def: None, type_alias_def: None,
namespace_def: None, namespace_def: None,
interface_def: None, interface_def: None,
import_def: None,
} }
} }
Decl::TsInterface(ts_interface_decl) => { Decl::TsInterface(ts_interface_decl) => {
@ -84,6 +87,7 @@ pub fn get_doc_node_for_export_decl(
enum_def: None, enum_def: None,
type_alias_def: None, type_alias_def: None,
namespace_def: None, namespace_def: None,
import_def: None,
} }
} }
Decl::TsTypeAlias(ts_type_alias) => { Decl::TsTypeAlias(ts_type_alias) => {
@ -104,6 +108,7 @@ pub fn get_doc_node_for_export_decl(
class_def: None, class_def: None,
enum_def: None, enum_def: None,
namespace_def: None, namespace_def: None,
import_def: None,
} }
} }
Decl::TsEnum(ts_enum) => { Decl::TsEnum(ts_enum) => {
@ -121,6 +126,7 @@ pub fn get_doc_node_for_export_decl(
function_def: None, function_def: None,
class_def: None, class_def: None,
namespace_def: None, namespace_def: None,
import_def: None,
} }
} }
Decl::TsModule(ts_module) => { Decl::TsModule(ts_module) => {
@ -138,6 +144,7 @@ pub fn get_doc_node_for_export_decl(
variable_def: None, variable_def: None,
function_def: None, function_def: None,
class_def: None, class_def: None,
import_def: None,
} }
} }
} }

View file

@ -46,6 +46,7 @@ pub fn get_doc_for_ts_namespace_decl(
class_def: None, class_def: None,
type_alias_def: None, type_alias_def: None,
interface_def: None, interface_def: None,
import_def: None,
} }
} }

View file

@ -11,6 +11,7 @@ pub enum DocNodeKind {
Interface, Interface,
TypeAlias, TypeAlias,
Namespace, Namespace,
Import,
} }
#[derive(Debug, Serialize, Clone, PartialEq)] #[derive(Debug, Serialize, Clone, PartialEq)]
@ -67,6 +68,13 @@ pub struct ModuleDoc {
pub reexports: Vec<Reexport>, pub reexports: Vec<Reexport>,
} }
#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ImportDef {
pub src: String,
pub imported: Option<String>,
}
#[derive(Debug, Serialize, Clone)] #[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct DocNode { pub struct DocNode {
@ -95,4 +103,7 @@ pub struct DocNode {
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub interface_def: Option<super::interface::InterfaceDef>, pub interface_def: Option<super::interface::InterfaceDef>,
#[serde(skip_serializing_if = "Option::is_none")]
pub import_def: Option<ImportDef>,
} }

View file

@ -2,7 +2,6 @@
use crate::file_fetcher::map_file_extension; use crate::file_fetcher::map_file_extension;
use crate::op_error::OpError; use crate::op_error::OpError;
use crate::swc_util::AstParser; use crate::swc_util::AstParser;
use crate::swc_util::SwcDiagnosticBuffer;
use swc_common::comments::CommentKind; use swc_common::comments::CommentKind;
use swc_common::Span; use swc_common::Span;
use swc_ecmascript::ast::Decl; use swc_ecmascript::ast::Decl;
@ -23,6 +22,7 @@ use super::node;
use super::node::ModuleDoc; use super::node::ModuleDoc;
use super::DocNode; use super::DocNode;
use super::DocNodeKind; use super::DocNodeKind;
use super::ImportDef;
use super::Location; use super::Location;
pub trait DocFileLoader { pub trait DocFileLoader {
@ -59,14 +59,18 @@ impl DocParser {
&self, &self,
file_name: &str, file_name: &str,
source_code: &str, source_code: &str,
) -> Result<ModuleDoc, SwcDiagnosticBuffer> { ) -> Result<ModuleDoc, ErrBox> {
let media_type = map_file_extension(&PathBuf::from(file_name)); let media_type = map_file_extension(&PathBuf::from(file_name));
let parse_result = let parse_result =
self self
.ast_parser .ast_parser
.parse_module(file_name, media_type, source_code); .parse_module(file_name, media_type, source_code);
let module = parse_result?; 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 reexports = self.get_reexports_for_module_body(module.body);
let module_doc = ModuleDoc { let module_doc = ModuleDoc {
definitions: doc_entries, definitions: doc_entries,
@ -138,6 +142,7 @@ impl DocParser {
variable_def: None, variable_def: None,
function_def: None, function_def: None,
class_def: None, class_def: None,
import_def: None,
}; };
processed_reexports.push(ns_doc_node); processed_reexports.push(ns_doc_node);
} }
@ -193,6 +198,72 @@ impl DocParser {
Ok(flattened_docs) 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 {
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( pub fn get_doc_nodes_for_module_exports(
&self, &self,
module_decl: &ModuleDecl, module_decl: &ModuleDecl,
@ -225,6 +296,7 @@ impl DocParser {
type_alias_def: None, type_alias_def: None,
namespace_def: None, namespace_def: None,
interface_def: None, interface_def: None,
import_def: None,
} }
} }
DefaultDecl::Fn(fn_expr) => { DefaultDecl::Fn(fn_expr) => {
@ -244,6 +316,7 @@ impl DocParser {
type_alias_def: None, type_alias_def: None,
namespace_def: None, namespace_def: None,
interface_def: None, interface_def: None,
import_def: None,
} }
} }
DefaultDecl::TsInterfaceDecl(interface_decl) => { DefaultDecl::TsInterfaceDecl(interface_decl) => {
@ -264,6 +337,7 @@ impl DocParser {
type_alias_def: None, type_alias_def: None,
namespace_def: None, namespace_def: None,
interface_def: Some(interface_def), interface_def: Some(interface_def),
import_def: None,
} }
} }
}; };
@ -309,6 +383,7 @@ impl DocParser {
type_alias_def: None, type_alias_def: None,
namespace_def: None, namespace_def: None,
interface_def: None, interface_def: None,
import_def: None,
}) })
} }
Decl::Fn(fn_decl) => { Decl::Fn(fn_decl) => {
@ -330,6 +405,7 @@ impl DocParser {
type_alias_def: None, type_alias_def: None,
namespace_def: None, namespace_def: None,
interface_def: None, interface_def: None,
import_def: None,
}) })
} }
Decl::Var(var_decl) => { Decl::Var(var_decl) => {
@ -350,6 +426,7 @@ impl DocParser {
type_alias_def: None, type_alias_def: None,
namespace_def: None, namespace_def: None,
interface_def: None, interface_def: None,
import_def: None,
}) })
} }
Decl::TsInterface(ts_interface_decl) => { Decl::TsInterface(ts_interface_decl) => {
@ -374,6 +451,7 @@ impl DocParser {
enum_def: None, enum_def: None,
type_alias_def: None, type_alias_def: None,
namespace_def: None, namespace_def: None,
import_def: None,
}) })
} }
Decl::TsTypeAlias(ts_type_alias) => { Decl::TsTypeAlias(ts_type_alias) => {
@ -398,6 +476,7 @@ impl DocParser {
class_def: None, class_def: None,
enum_def: None, enum_def: None,
namespace_def: None, namespace_def: None,
import_def: None,
}) })
} }
Decl::TsEnum(ts_enum) => { Decl::TsEnum(ts_enum) => {
@ -419,6 +498,7 @@ impl DocParser {
function_def: None, function_def: None,
class_def: None, class_def: None,
namespace_def: None, namespace_def: None,
import_def: None,
}) })
} }
Decl::TsModule(ts_module) => { Decl::TsModule(ts_module) => {
@ -440,6 +520,7 @@ impl DocParser {
variable_def: None, variable_def: None,
function_def: None, function_def: None,
class_def: None, class_def: None,
import_def: None,
}) })
} }
} }

View file

@ -129,6 +129,7 @@ impl<'a> DocPrinter<'a> {
DocNodeKind::Interface => 4, DocNodeKind::Interface => 4,
DocNodeKind::TypeAlias => 5, DocNodeKind::TypeAlias => 5,
DocNodeKind::Namespace => 6, DocNodeKind::Namespace => 6,
DocNodeKind::Import => 7,
} }
} }
@ -152,6 +153,7 @@ impl<'a> DocPrinter<'a> {
DocNodeKind::Namespace => { DocNodeKind::Namespace => {
self.format_namespace_signature(w, node, indent) self.format_namespace_signature(w, node, indent)
} }
DocNodeKind::Import => Ok(()),
} }
} }

View file

@ -153,9 +153,12 @@ import { bar } from "./nested_reexport.ts";
* JSDoc for const * JSDoc for const
*/ */
export const foo = "foo"; export const foo = "foo";
export const fizz = "fizz";
"#; "#;
let test_source_code = r#" let test_source_code = r#"
export { default, foo as fooConst } from "./reexport.ts"; export { default, foo as fooConst } from "./reexport.ts";
import { fizz as buzz } from "./reexport.ts";
/** JSDoc for function */ /** JSDoc for function */
export function fooFn(a: number) { export function fooFn(a: number) {
@ -177,7 +180,7 @@ export function fooFn(a: number) {
.parse_with_reexports("file:///test.ts") .parse_with_reexports("file:///test.ts")
.await .await
.unwrap(); .unwrap();
assert_eq!(entries.len(), 2); assert_eq!(entries.len(), 3);
let expected_json = json!([ let expected_json = json!([
{ {
@ -199,7 +202,7 @@ export function fooFn(a: number) {
"name": "fooFn", "name": "fooFn",
"location": { "location": {
"filename": "file:///test.ts", "filename": "file:///test.ts",
"line": 5, "line": 6,
"col": 0 "col": 0
}, },
"jsDoc": "JSDoc for function", "jsDoc": "JSDoc for function",
@ -220,6 +223,20 @@ export function fooFn(a: number) {
"returnType": null, "returnType": null,
"isAsync": false, "isAsync": false,
"isGenerator": 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",
} }
} }
]); ]);

View file

@ -532,7 +532,7 @@ async fn doc_command(
.await .await
}; };
let doc_nodes = match parse_result { let mut doc_nodes = match parse_result {
Ok(nodes) => nodes, Ok(nodes) => nodes,
Err(e) => { Err(e) => {
eprintln!("{}", e); eprintln!("{}", e);
@ -543,6 +543,7 @@ async fn doc_command(
if json { if json {
write_json_to_stdout(&doc_nodes) write_json_to_stdout(&doc_nodes)
} else { } else {
doc_nodes.retain(|doc_node| doc_node.kind != doc::DocNodeKind::Import);
let details = if let Some(filter) = maybe_filter { let details = if let Some(filter) = maybe_filter {
let nodes = let nodes =
doc::find_nodes_by_name_recursively(doc_nodes, filter.clone()); doc::find_nodes_by_name_recursively(doc_nodes, filter.clone());