mirror of
https://github.com/denoland/deno.git
synced 2025-07-12 15:55:05 +00:00
feat: deno doc handles default exports (#4873)
This commit is contained in:
parent
e513751ee9
commit
e18aaf49cf
4 changed files with 322 additions and 15 deletions
|
@ -85,15 +85,15 @@ fn prop_name_to_string(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_doc_for_class_decl(
|
pub fn class_to_class_def(
|
||||||
doc_parser: &DocParser,
|
doc_parser: &DocParser,
|
||||||
class_decl: &swc_ecma_ast::ClassDecl,
|
class: &swc_ecma_ast::Class,
|
||||||
) -> (String, ClassDef) {
|
) -> ClassDef {
|
||||||
let mut constructors = vec![];
|
let mut constructors = vec![];
|
||||||
let mut methods = vec![];
|
let mut methods = vec![];
|
||||||
let mut properties = vec![];
|
let mut properties = vec![];
|
||||||
|
|
||||||
let extends: Option<String> = match &class_decl.class.super_class {
|
let extends: Option<String> = match &class.super_class {
|
||||||
Some(boxed) => {
|
Some(boxed) => {
|
||||||
use crate::swc_ecma_ast::Expr;
|
use crate::swc_ecma_ast::Expr;
|
||||||
let expr: &Expr = &**boxed;
|
let expr: &Expr = &**boxed;
|
||||||
|
@ -105,14 +105,13 @@ pub fn get_doc_for_class_decl(
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let implements: Vec<String> = class_decl
|
let implements: Vec<String> = class
|
||||||
.class
|
|
||||||
.implements
|
.implements
|
||||||
.iter()
|
.iter()
|
||||||
.map(|expr| ts_entity_name_to_name(&expr.expr))
|
.map(|expr| ts_entity_name_to_name(&expr.expr))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
for member in &class_decl.class.body {
|
for member in &class.body {
|
||||||
use crate::swc_ecma_ast::ClassMember::*;
|
use crate::swc_ecma_ast::ClassMember::*;
|
||||||
|
|
||||||
match member {
|
match member {
|
||||||
|
@ -207,19 +206,26 @@ pub fn get_doc_for_class_decl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let type_params = maybe_type_param_decl_to_type_param_defs(
|
let type_params =
|
||||||
class_decl.class.type_params.as_ref(),
|
maybe_type_param_decl_to_type_param_defs(class.type_params.as_ref());
|
||||||
);
|
|
||||||
let class_name = class_decl.ident.sym.to_string();
|
ClassDef {
|
||||||
let class_def = ClassDef {
|
is_abstract: class.is_abstract,
|
||||||
is_abstract: class_decl.class.is_abstract,
|
|
||||||
extends,
|
extends,
|
||||||
implements,
|
implements,
|
||||||
constructors,
|
constructors,
|
||||||
properties,
|
properties,
|
||||||
methods,
|
methods,
|
||||||
type_params,
|
type_params,
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_doc_for_class_decl(
|
||||||
|
doc_parser: &DocParser,
|
||||||
|
class_decl: &swc_ecma_ast::ClassDecl,
|
||||||
|
) -> (String, ClassDef) {
|
||||||
|
let class_name = class_decl.ident.sym.to_string();
|
||||||
|
let class_def = class_to_class_def(doc_parser, &class_decl.class);
|
||||||
|
|
||||||
(class_name, class_def)
|
(class_name, class_def)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ pub fn get_doc_node_for_export_decl(
|
||||||
let js_doc = doc_parser.js_doc_for_span(export_span);
|
let js_doc = doc_parser.js_doc_for_span(export_span);
|
||||||
let location = doc_parser.ast_parser.get_span_location(export_span).into();
|
let location = doc_parser.ast_parser.get_span_location(export_span).into();
|
||||||
|
|
||||||
|
eprintln!("decl {:#?}", export_decl);
|
||||||
match &export_decl.decl {
|
match &export_decl.decl {
|
||||||
Decl::Class(class_decl) => {
|
Decl::Class(class_decl) => {
|
||||||
let (name, class_def) =
|
let (name, class_def) =
|
||||||
|
|
|
@ -4,6 +4,7 @@ use crate::swc_common::comments::CommentKind;
|
||||||
use crate::swc_common::Span;
|
use crate::swc_common::Span;
|
||||||
use crate::swc_ecma_ast;
|
use crate::swc_ecma_ast;
|
||||||
use crate::swc_ecma_ast::Decl;
|
use crate::swc_ecma_ast::Decl;
|
||||||
|
use crate::swc_ecma_ast::DefaultDecl;
|
||||||
use crate::swc_ecma_ast::ModuleDecl;
|
use crate::swc_ecma_ast::ModuleDecl;
|
||||||
use crate::swc_ecma_ast::Stmt;
|
use crate::swc_ecma_ast::Stmt;
|
||||||
use crate::swc_util::AstParser;
|
use crate::swc_util::AstParser;
|
||||||
|
@ -200,6 +201,74 @@ impl DocParser {
|
||||||
export_decl,
|
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 {
|
||||||
|
kind: DocNodeKind::Class,
|
||||||
|
name,
|
||||||
|
location,
|
||||||
|
js_doc,
|
||||||
|
class_def: Some(class_def),
|
||||||
|
function_def: None,
|
||||||
|
variable_def: None,
|
||||||
|
enum_def: None,
|
||||||
|
type_alias_def: None,
|
||||||
|
namespace_def: None,
|
||||||
|
interface_def: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DefaultDecl::Fn(fn_expr) => {
|
||||||
|
let function_def =
|
||||||
|
crate::doc::function::function_to_function_def(&fn_expr.function);
|
||||||
|
DocNode {
|
||||||
|
kind: DocNodeKind::Function,
|
||||||
|
name,
|
||||||
|
location,
|
||||||
|
js_doc,
|
||||||
|
class_def: None,
|
||||||
|
function_def: Some(function_def),
|
||||||
|
variable_def: None,
|
||||||
|
enum_def: None,
|
||||||
|
type_alias_def: None,
|
||||||
|
namespace_def: None,
|
||||||
|
interface_def: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DefaultDecl::TsInterfaceDecl(interface_decl) => {
|
||||||
|
let (_, interface_def) =
|
||||||
|
crate::doc::interface::get_doc_for_ts_interface_decl(
|
||||||
|
self,
|
||||||
|
interface_decl,
|
||||||
|
);
|
||||||
|
DocNode {
|
||||||
|
kind: DocNodeKind::Interface,
|
||||||
|
name,
|
||||||
|
location,
|
||||||
|
js_doc,
|
||||||
|
class_def: None,
|
||||||
|
function_def: None,
|
||||||
|
variable_def: None,
|
||||||
|
enum_def: None,
|
||||||
|
type_alias_def: None,
|
||||||
|
namespace_def: None,
|
||||||
|
interface_def: Some(interface_def),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
vec![doc_node]
|
||||||
|
}
|
||||||
|
ModuleDecl::ExportDefaultExpr(export_default_expr) => {
|
||||||
|
eprintln!("export default expr {:#?}", export_default_expr);
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -386,6 +455,7 @@ impl DocParser {
|
||||||
if let swc_ecma_ast::ModuleItem::ModuleDecl(module_decl) = node {
|
if let swc_ecma_ast::ModuleItem::ModuleDecl(module_decl) = node {
|
||||||
let r = match module_decl {
|
let r = match module_decl {
|
||||||
ModuleDecl::ExportNamed(named_export) => {
|
ModuleDecl::ExportNamed(named_export) => {
|
||||||
|
eprintln!("export named {:#?}", named_export);
|
||||||
if let Some(src) = &named_export.src {
|
if let Some(src) = &named_export.src {
|
||||||
let src_str = src.value.to_string();
|
let src_str = src.value.to_string();
|
||||||
named_export
|
named_export
|
||||||
|
|
232
cli/doc/tests.rs
232
cli/doc/tests.rs
|
@ -1064,6 +1064,234 @@ declare namespace RootNs {
|
||||||
.contains("namespace RootNs")
|
.contains("namespace RootNs")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn export_default_fn() {
|
||||||
|
let source_code = r#"
|
||||||
|
export default function foo(a: number) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let loader =
|
||||||
|
TestLoader::new(vec![("test.ts".to_string(), source_code.to_string())]);
|
||||||
|
let entries = DocParser::new(loader).parse("test.ts").await.unwrap();
|
||||||
|
assert_eq!(entries.len(), 1);
|
||||||
|
let entry = &entries[0];
|
||||||
|
let expected_json = json!({
|
||||||
|
"kind": "function",
|
||||||
|
"name": "default",
|
||||||
|
"location": {
|
||||||
|
"filename": "test.ts",
|
||||||
|
"line": 2,
|
||||||
|
"col": 15
|
||||||
|
},
|
||||||
|
"jsDoc": null,
|
||||||
|
"functionDef": {
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"name": "a",
|
||||||
|
"kind": "identifier",
|
||||||
|
"optional": false,
|
||||||
|
"tsType": {
|
||||||
|
"keyword": "number",
|
||||||
|
"kind": "keyword",
|
||||||
|
"repr": "number",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"typeParams": [],
|
||||||
|
"returnType": null,
|
||||||
|
"isAsync": false,
|
||||||
|
"isGenerator": false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let actual = serde_json::to_value(entry).unwrap();
|
||||||
|
assert_eq!(actual, expected_json);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
colors::strip_ansi_codes(super::printer::format(entries).as_str())
|
||||||
|
.contains("function default(a: number)")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn export_default_class() {
|
||||||
|
let source_code = r#"
|
||||||
|
/** Class doc */
|
||||||
|
export default class Foobar {
|
||||||
|
/** Constructor js doc */
|
||||||
|
constructor(name: string, private private2: number, protected protected2: number) {}
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let loader =
|
||||||
|
TestLoader::new(vec![("test.ts".to_string(), source_code.to_string())]);
|
||||||
|
let entries = DocParser::new(loader).parse("test.ts").await.unwrap();
|
||||||
|
assert_eq!(entries.len(), 1);
|
||||||
|
let expected_json = json!({
|
||||||
|
"kind": "class",
|
||||||
|
"name": "default",
|
||||||
|
"location": {
|
||||||
|
"filename": "test.ts",
|
||||||
|
"line": 3,
|
||||||
|
"col": 0
|
||||||
|
},
|
||||||
|
"jsDoc": "Class doc",
|
||||||
|
"classDef": {
|
||||||
|
"isAbstract": false,
|
||||||
|
"extends": null,
|
||||||
|
"implements": [],
|
||||||
|
"typeParams": [],
|
||||||
|
"constructors": [
|
||||||
|
{
|
||||||
|
"jsDoc": "Constructor js doc",
|
||||||
|
"accessibility": null,
|
||||||
|
"name": "constructor",
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"kind": "identifier",
|
||||||
|
"optional": false,
|
||||||
|
"tsType": {
|
||||||
|
"repr": "string",
|
||||||
|
"kind": "keyword",
|
||||||
|
"keyword": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "private2",
|
||||||
|
"kind": "identifier",
|
||||||
|
"optional": false,
|
||||||
|
"tsType": {
|
||||||
|
"repr": "number",
|
||||||
|
"kind": "keyword",
|
||||||
|
"keyword": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "protected2",
|
||||||
|
"kind": "identifier",
|
||||||
|
"optional": false,
|
||||||
|
"tsType": {
|
||||||
|
"repr": "number",
|
||||||
|
"kind": "keyword",
|
||||||
|
"keyword": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"location": {
|
||||||
|
"filename": "test.ts",
|
||||||
|
"line": 5,
|
||||||
|
"col": 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties": [],
|
||||||
|
"methods": []
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let entry = &entries[0];
|
||||||
|
let actual = serde_json::to_value(entry).unwrap();
|
||||||
|
assert_eq!(actual, expected_json);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
colors::strip_ansi_codes(super::printer::format(entries).as_str())
|
||||||
|
.contains("class default")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn export_default_interface() {
|
||||||
|
let source_code = r#"
|
||||||
|
/**
|
||||||
|
* Interface js doc
|
||||||
|
*/
|
||||||
|
export default interface Reader {
|
||||||
|
/** Read n bytes */
|
||||||
|
read?(buf: Uint8Array, something: unknown): Promise<number>
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let loader =
|
||||||
|
TestLoader::new(vec![("test.ts".to_string(), source_code.to_string())]);
|
||||||
|
let entries = DocParser::new(loader).parse("test.ts").await.unwrap();
|
||||||
|
assert_eq!(entries.len(), 1);
|
||||||
|
let entry = &entries[0];
|
||||||
|
let expected_json = json!({
|
||||||
|
"kind": "interface",
|
||||||
|
"name": "default",
|
||||||
|
"location": {
|
||||||
|
"filename": "test.ts",
|
||||||
|
"line": 5,
|
||||||
|
"col": 0
|
||||||
|
},
|
||||||
|
"jsDoc": "Interface js doc",
|
||||||
|
"interfaceDef": {
|
||||||
|
"extends": [],
|
||||||
|
"methods": [
|
||||||
|
{
|
||||||
|
"name": "read",
|
||||||
|
"location": {
|
||||||
|
"filename": "test.ts",
|
||||||
|
"line": 7,
|
||||||
|
"col": 4
|
||||||
|
},
|
||||||
|
"optional": true,
|
||||||
|
"jsDoc": "Read n bytes",
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"name": "buf",
|
||||||
|
"kind": "identifier",
|
||||||
|
"optional": false,
|
||||||
|
"tsType": {
|
||||||
|
"repr": "Uint8Array",
|
||||||
|
"kind": "typeRef",
|
||||||
|
"typeRef": {
|
||||||
|
"typeParams": null,
|
||||||
|
"typeName": "Uint8Array"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "something",
|
||||||
|
"kind": "identifier",
|
||||||
|
"optional": false,
|
||||||
|
"tsType": {
|
||||||
|
"repr": "unknown",
|
||||||
|
"kind": "keyword",
|
||||||
|
"keyword": "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"typeParams": [],
|
||||||
|
"returnType": {
|
||||||
|
"repr": "Promise",
|
||||||
|
"kind": "typeRef",
|
||||||
|
"typeRef": {
|
||||||
|
"typeParams": [
|
||||||
|
{
|
||||||
|
"repr": "number",
|
||||||
|
"kind": "keyword",
|
||||||
|
"keyword": "number"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"typeName": "Promise"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties": [],
|
||||||
|
"callSignatures": [],
|
||||||
|
"typeParams": [],
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let actual = serde_json::to_value(entry).unwrap();
|
||||||
|
assert_eq!(actual, expected_json);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
colors::strip_ansi_codes(super::printer::format(entries).as_str())
|
||||||
|
.contains("interface default")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn optional_return_type() {
|
async fn optional_return_type() {
|
||||||
let source_code = r#"
|
let source_code = r#"
|
||||||
|
@ -1120,6 +1348,8 @@ async fn reexports() {
|
||||||
* JSDoc for bar
|
* JSDoc for bar
|
||||||
*/
|
*/
|
||||||
export const bar = "bar";
|
export const bar = "bar";
|
||||||
|
|
||||||
|
export default 42;
|
||||||
"#;
|
"#;
|
||||||
let reexport_source_code = r#"
|
let reexport_source_code = r#"
|
||||||
import { bar } from "./nested_reexport.ts";
|
import { bar } from "./nested_reexport.ts";
|
||||||
|
@ -1130,7 +1360,7 @@ import { bar } from "./nested_reexport.ts";
|
||||||
export const foo = "foo";
|
export const foo = "foo";
|
||||||
"#;
|
"#;
|
||||||
let test_source_code = r#"
|
let test_source_code = r#"
|
||||||
export { foo as fooConst } from "./reexport.ts";
|
export { default, foo as fooConst } from "./reexport.ts";
|
||||||
|
|
||||||
/** JSDoc for function */
|
/** JSDoc for function */
|
||||||
export function fooFn(a: number) {
|
export function fooFn(a: number) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue