mirror of
https://github.com/denoland/deno.git
synced 2024-11-22 15:06:54 -05:00
feat(doc): Improve terminal printer (#6594)
- Add more support for generics - Add the --private flag - displays documentation for not exported and private nodes - Display more attributes like abstract, static and readonly - Display type aliases - Refactor module to use the Display trait - Use a bit more color
This commit is contained in:
parent
871f9255e3
commit
3374c73fba
16 changed files with 2888 additions and 1743 deletions
|
@ -3,7 +3,7 @@ use regex::Regex;
|
|||
use std::env;
|
||||
use std::fmt;
|
||||
use std::io::Write;
|
||||
use termcolor::Color::{Ansi256, Black, Magenta, Red, White};
|
||||
use termcolor::Color::{Ansi256, Black, Blue, Green, Magenta, Red, White};
|
||||
use termcolor::{Ansi, ColorSpec, WriteColor};
|
||||
|
||||
#[cfg(windows)]
|
||||
|
@ -54,7 +54,10 @@ pub fn red_bold(s: &str) -> impl fmt::Display {
|
|||
|
||||
pub fn green_bold(s: &str) -> impl fmt::Display {
|
||||
let mut style_spec = ColorSpec::new();
|
||||
style_spec.set_fg(Some(Ansi256(10))).set_bold(true);
|
||||
style_spec
|
||||
.set_fg(Some(Green))
|
||||
.set_bold(true)
|
||||
.set_intense(true);
|
||||
style(&s, style_spec)
|
||||
}
|
||||
|
||||
|
@ -102,7 +105,7 @@ pub fn red(s: &str) -> impl fmt::Display {
|
|||
|
||||
pub fn green(s: &str) -> impl fmt::Display {
|
||||
let mut style_spec = ColorSpec::new();
|
||||
style_spec.set_fg(Some(Ansi256(10)));
|
||||
style_spec.set_fg(Some(Green)).set_intense(true);
|
||||
style(&s, style_spec)
|
||||
}
|
||||
|
||||
|
@ -124,6 +127,12 @@ pub fn gray(s: &str) -> impl fmt::Display {
|
|||
style(&s, style_spec)
|
||||
}
|
||||
|
||||
pub fn italic_gray(s: &str) -> impl fmt::Display {
|
||||
let mut style_spec = ColorSpec::new();
|
||||
style_spec.set_fg(Some(Ansi256(8))).set_italic(true);
|
||||
style(&s, style_spec)
|
||||
}
|
||||
|
||||
pub fn italic_bold_gray(s: &str) -> impl fmt::Display {
|
||||
let mut style_spec = ColorSpec::new();
|
||||
style_spec
|
||||
|
@ -132,3 +141,9 @@ pub fn italic_bold_gray(s: &str) -> impl fmt::Display {
|
|||
.set_italic(true);
|
||||
style(&s, style_spec)
|
||||
}
|
||||
|
||||
pub fn intense_blue(s: &str) -> impl fmt::Display {
|
||||
let mut style_spec = ColorSpec::new();
|
||||
style_spec.set_fg(Some(Blue)).set_intense(true);
|
||||
style(&s, style_spec)
|
||||
}
|
||||
|
|
178
cli/doc/class.rs
178
cli/doc/class.rs
|
@ -1,5 +1,10 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
use crate::swc_common::SourceMap;
|
||||
use crate::colors;
|
||||
use crate::doc::display::{
|
||||
display_abstract, display_accessibility, display_async, display_generator,
|
||||
display_method, display_optional, display_readonly, display_static,
|
||||
SliceDisplayer,
|
||||
};
|
||||
use crate::swc_common::Spanned;
|
||||
use crate::swc_ecma_ast;
|
||||
use serde::Serialize;
|
||||
|
@ -7,18 +12,21 @@ use serde::Serialize;
|
|||
use super::function::function_to_function_def;
|
||||
use super::function::FunctionDef;
|
||||
use super::interface::expr_to_name;
|
||||
use super::params::assign_pat_to_param_def;
|
||||
use super::params::ident_to_param_def;
|
||||
use super::params::pat_to_param_def;
|
||||
use super::params::{
|
||||
assign_pat_to_param_def, ident_to_param_def, pat_to_param_def,
|
||||
prop_name_to_string, ts_fn_param_to_param_def,
|
||||
};
|
||||
use super::parser::DocParser;
|
||||
use super::ts_type::ts_entity_name_to_name;
|
||||
use super::ts_type::ts_type_ann_to_def;
|
||||
use super::ts_type::TsTypeDef;
|
||||
use super::ts_type::{
|
||||
maybe_type_param_instantiation_to_type_defs, ts_type_ann_to_def, TsTypeDef,
|
||||
};
|
||||
use super::ts_type_param::maybe_type_param_decl_to_type_param_defs;
|
||||
use super::ts_type_param::TsTypeParamDef;
|
||||
use super::Location;
|
||||
use super::ParamDef;
|
||||
|
||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ClassConstructorDef {
|
||||
|
@ -29,6 +37,18 @@ pub struct ClassConstructorDef {
|
|||
pub location: Location,
|
||||
}
|
||||
|
||||
impl Display for ClassConstructorDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(
|
||||
f,
|
||||
"{}{}({})",
|
||||
display_accessibility(self.accessibility),
|
||||
colors::magenta("constructor"),
|
||||
SliceDisplayer::new(&self.params, ", ", false),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ClassPropertyDef {
|
||||
|
@ -43,6 +63,48 @@ pub struct ClassPropertyDef {
|
|||
pub location: Location,
|
||||
}
|
||||
|
||||
impl Display for ClassPropertyDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(
|
||||
f,
|
||||
"{}{}{}{}{}{}",
|
||||
display_abstract(self.is_abstract),
|
||||
display_accessibility(self.accessibility),
|
||||
display_static(self.is_static),
|
||||
display_readonly(self.readonly),
|
||||
colors::bold(&self.name),
|
||||
display_optional(self.optional),
|
||||
)?;
|
||||
if let Some(ts_type) = &self.ts_type {
|
||||
write!(f, ": {}", ts_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ClassIndexSignatureDef {
|
||||
pub readonly: bool,
|
||||
pub params: Vec<ParamDef>,
|
||||
pub ts_type: Option<TsTypeDef>,
|
||||
}
|
||||
|
||||
impl Display for ClassIndexSignatureDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(
|
||||
f,
|
||||
"{}[{}]",
|
||||
display_readonly(self.readonly),
|
||||
SliceDisplayer::new(&self.params, ", ", false)
|
||||
)?;
|
||||
if let Some(ts_type) = &self.ts_type {
|
||||
write!(f, ": {}", ts_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ClassMethodDef {
|
||||
|
@ -57,32 +119,41 @@ pub struct ClassMethodDef {
|
|||
pub location: Location,
|
||||
}
|
||||
|
||||
impl Display for ClassMethodDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(
|
||||
f,
|
||||
"{}{}{}{}{}{}{}{}({})",
|
||||
display_abstract(self.is_abstract),
|
||||
display_accessibility(self.accessibility),
|
||||
display_static(self.is_static),
|
||||
display_async(self.function_def.is_async),
|
||||
display_method(self.kind),
|
||||
display_generator(self.function_def.is_generator),
|
||||
colors::bold(&self.name),
|
||||
display_optional(self.optional),
|
||||
SliceDisplayer::new(&self.function_def.params, ", ", false),
|
||||
)?;
|
||||
if let Some(return_type) = &self.function_def.return_type {
|
||||
write!(f, ": {}", return_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ClassDef {
|
||||
// TODO(bartlomieju): decorators, super_type_params
|
||||
// TODO(bartlomieju): decorators
|
||||
pub is_abstract: bool,
|
||||
pub constructors: Vec<ClassConstructorDef>,
|
||||
pub properties: Vec<ClassPropertyDef>,
|
||||
pub index_signatures: Vec<ClassIndexSignatureDef>,
|
||||
pub methods: Vec<ClassMethodDef>,
|
||||
pub extends: Option<String>,
|
||||
pub implements: Vec<String>,
|
||||
pub implements: Vec<TsTypeDef>,
|
||||
pub type_params: Vec<TsTypeParamDef>,
|
||||
}
|
||||
|
||||
fn prop_name_to_string(
|
||||
source_map: &SourceMap,
|
||||
prop_name: &swc_ecma_ast::PropName,
|
||||
) -> String {
|
||||
use crate::swc_ecma_ast::PropName;
|
||||
match prop_name {
|
||||
PropName::Ident(ident) => ident.sym.to_string(),
|
||||
PropName::Str(str_) => str_.value.to_string(),
|
||||
PropName::Num(num) => num.value.to_string(),
|
||||
PropName::Computed(comp_prop_name) => {
|
||||
source_map.span_to_snippet(comp_prop_name.span).unwrap()
|
||||
}
|
||||
}
|
||||
pub super_type_params: Vec<TsTypeDef>,
|
||||
}
|
||||
|
||||
pub fn class_to_class_def(
|
||||
|
@ -92,6 +163,7 @@ pub fn class_to_class_def(
|
|||
let mut constructors = vec![];
|
||||
let mut methods = vec![];
|
||||
let mut properties = vec![];
|
||||
let mut index_signatures = vec![];
|
||||
|
||||
let extends: Option<String> = match &class.super_class {
|
||||
Some(boxed) => {
|
||||
|
@ -105,11 +177,11 @@ pub fn class_to_class_def(
|
|||
None => None,
|
||||
};
|
||||
|
||||
let implements: Vec<String> = class
|
||||
let implements = class
|
||||
.implements
|
||||
.iter()
|
||||
.map(|expr| ts_entity_name_to_name(&expr.expr))
|
||||
.collect();
|
||||
.map(|expr| expr.into())
|
||||
.collect::<Vec<TsTypeDef>>();
|
||||
|
||||
for member in &class.body {
|
||||
use crate::swc_ecma_ast::ClassMember::*;
|
||||
|
@ -117,8 +189,10 @@ pub fn class_to_class_def(
|
|||
match member {
|
||||
Constructor(ctor) => {
|
||||
let ctor_js_doc = doc_parser.js_doc_for_span(ctor.span());
|
||||
let constructor_name =
|
||||
prop_name_to_string(&doc_parser.ast_parser.source_map, &ctor.key);
|
||||
let constructor_name = prop_name_to_string(
|
||||
&ctor.key,
|
||||
Some(&doc_parser.ast_parser.source_map),
|
||||
);
|
||||
|
||||
let mut params = vec![];
|
||||
|
||||
|
@ -126,14 +200,23 @@ pub fn class_to_class_def(
|
|||
use crate::swc_ecma_ast::ParamOrTsParamProp::*;
|
||||
|
||||
let param_def = match param {
|
||||
Param(param) => pat_to_param_def(¶m.pat),
|
||||
Param(param) => pat_to_param_def(
|
||||
¶m.pat,
|
||||
Some(&doc_parser.ast_parser.source_map),
|
||||
),
|
||||
TsParamProp(ts_param_prop) => {
|
||||
use swc_ecma_ast::TsParamPropParam;
|
||||
|
||||
match &ts_param_prop.param {
|
||||
TsParamPropParam::Ident(ident) => ident_to_param_def(ident),
|
||||
TsParamPropParam::Ident(ident) => ident_to_param_def(
|
||||
ident,
|
||||
Some(&doc_parser.ast_parser.source_map),
|
||||
),
|
||||
TsParamPropParam::Assign(assign_pat) => {
|
||||
assign_pat_to_param_def(assign_pat)
|
||||
assign_pat_to_param_def(
|
||||
assign_pat,
|
||||
Some(&doc_parser.ast_parser.source_map),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -153,10 +236,11 @@ pub fn class_to_class_def(
|
|||
Method(class_method) => {
|
||||
let method_js_doc = doc_parser.js_doc_for_span(class_method.span());
|
||||
let method_name = prop_name_to_string(
|
||||
&doc_parser.ast_parser.source_map,
|
||||
&class_method.key,
|
||||
Some(&doc_parser.ast_parser.source_map),
|
||||
);
|
||||
let fn_def = function_to_function_def(&class_method.function);
|
||||
let fn_def =
|
||||
function_to_function_def(&doc_parser, &class_method.function);
|
||||
let method_def = ClassMethodDef {
|
||||
js_doc: method_js_doc,
|
||||
accessibility: class_method.accessibility,
|
||||
|
@ -199,8 +283,26 @@ pub fn class_to_class_def(
|
|||
};
|
||||
properties.push(prop_def);
|
||||
}
|
||||
TsIndexSignature(ts_index_sig) => {
|
||||
let mut params = vec![];
|
||||
for param in &ts_index_sig.params {
|
||||
let param_def = ts_fn_param_to_param_def(param, None);
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
let ts_type = ts_index_sig
|
||||
.type_ann
|
||||
.as_ref()
|
||||
.map(|rt| (&*rt.type_ann).into());
|
||||
|
||||
let index_sig_def = ClassIndexSignatureDef {
|
||||
readonly: ts_index_sig.readonly,
|
||||
params,
|
||||
ts_type,
|
||||
};
|
||||
index_signatures.push(index_sig_def);
|
||||
}
|
||||
// TODO(bartlomieju):
|
||||
TsIndexSignature(_) => {}
|
||||
PrivateMethod(_) => {}
|
||||
PrivateProp(_) => {}
|
||||
_ => {}
|
||||
|
@ -210,14 +312,20 @@ pub fn class_to_class_def(
|
|||
let type_params =
|
||||
maybe_type_param_decl_to_type_param_defs(class.type_params.as_ref());
|
||||
|
||||
let super_type_params = maybe_type_param_instantiation_to_type_defs(
|
||||
class.super_type_params.as_ref(),
|
||||
);
|
||||
|
||||
ClassDef {
|
||||
is_abstract: class.is_abstract,
|
||||
extends,
|
||||
implements,
|
||||
constructors,
|
||||
properties,
|
||||
index_signatures,
|
||||
methods,
|
||||
type_params,
|
||||
super_type_params,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
90
cli/doc/display.rs
Normal file
90
cli/doc/display.rs
Normal file
|
@ -0,0 +1,90 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
use crate::colors;
|
||||
use crate::swc_ecma_ast;
|
||||
use std::fmt::{Display, Formatter, Result};
|
||||
|
||||
pub(crate) struct Indent(pub i64);
|
||||
|
||||
impl Display for Indent {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
for _ in 0..self.0 {
|
||||
write!(f, " ")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct SliceDisplayer<'a, T: Display>(&'a [T], &'a str, bool);
|
||||
|
||||
impl<'a, T: Display> SliceDisplayer<'a, T> {
|
||||
pub fn new(
|
||||
slice: &'a [T],
|
||||
separator: &'a str,
|
||||
trailing: bool,
|
||||
) -> SliceDisplayer<'a, T> {
|
||||
SliceDisplayer(slice, separator, trailing)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Display> Display for SliceDisplayer<'_, T> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
if self.0.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
write!(f, "{}", self.0[0])?;
|
||||
for v in &self.0[1..] {
|
||||
write!(f, "{}{}", self.1, v)?;
|
||||
}
|
||||
|
||||
if self.2 {
|
||||
write!(f, "{}", self.1)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn display_abstract(is_abstract: bool) -> impl Display {
|
||||
colors::magenta(if is_abstract { "abstract " } else { "" })
|
||||
}
|
||||
|
||||
pub(crate) fn display_accessibility(
|
||||
accessibility: Option<swc_ecma_ast::Accessibility>,
|
||||
) -> impl Display {
|
||||
colors::magenta(
|
||||
match accessibility.unwrap_or(swc_ecma_ast::Accessibility::Public) {
|
||||
swc_ecma_ast::Accessibility::Public => "",
|
||||
swc_ecma_ast::Accessibility::Protected => "protected ",
|
||||
swc_ecma_ast::Accessibility::Private => "private ",
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn display_async(is_async: bool) -> impl Display {
|
||||
colors::magenta(if is_async { "async " } else { "" })
|
||||
}
|
||||
|
||||
pub(crate) fn display_generator(is_generator: bool) -> impl Display {
|
||||
colors::magenta(if is_generator { "*" } else { "" })
|
||||
}
|
||||
|
||||
pub(crate) fn display_method(method: swc_ecma_ast::MethodKind) -> impl Display {
|
||||
colors::magenta(match method {
|
||||
swc_ecma_ast::MethodKind::Getter => "get ",
|
||||
swc_ecma_ast::MethodKind::Setter => "set ",
|
||||
_ => "",
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn display_optional(is_optional: bool) -> impl Display {
|
||||
colors::magenta(if is_optional { "?" } else { "" })
|
||||
}
|
||||
|
||||
pub(crate) fn display_readonly(is_readonly: bool) -> impl Display {
|
||||
colors::magenta(if is_readonly { "readonly " } else { "" })
|
||||
}
|
||||
|
||||
pub(crate) fn display_static(is_static: bool) -> impl Display {
|
||||
colors::magenta(if is_static { "static " } else { "" })
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
use super::params::pat_to_param_def;
|
||||
use super::parser::DocParser;
|
||||
use super::ts_type::ts_type_ann_to_def;
|
||||
use super::ts_type::TsTypeDef;
|
||||
use super::ts_type_param::maybe_type_param_decl_to_type_param_defs;
|
||||
|
@ -20,12 +21,14 @@ pub struct FunctionDef {
|
|||
}
|
||||
|
||||
pub fn function_to_function_def(
|
||||
doc_parser: &DocParser,
|
||||
function: &swc_ecma_ast::Function,
|
||||
) -> FunctionDef {
|
||||
let mut params = vec![];
|
||||
|
||||
for param in &function.params {
|
||||
let param_def = pat_to_param_def(¶m.pat);
|
||||
let param_def =
|
||||
pat_to_param_def(¶m.pat, Some(&doc_parser.ast_parser.source_map));
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
|
@ -47,9 +50,10 @@ pub fn function_to_function_def(
|
|||
}
|
||||
|
||||
pub fn get_doc_for_fn_decl(
|
||||
doc_parser: &DocParser,
|
||||
fn_decl: &swc_ecma_ast::FnDecl,
|
||||
) -> (String, FunctionDef) {
|
||||
let name = fn_decl.ident.sym.to_string();
|
||||
let fn_def = function_to_function_def(&fn_decl.function);
|
||||
let fn_def = function_to_function_def(&doc_parser, &fn_decl.function);
|
||||
(name, fn_def)
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
use crate::colors;
|
||||
use crate::doc::display::{display_optional, display_readonly, SliceDisplayer};
|
||||
use crate::swc_ecma_ast;
|
||||
use serde::Serialize;
|
||||
|
||||
use super::params::ts_fn_param_to_param_def;
|
||||
use super::parser::DocParser;
|
||||
use super::ts_type::ts_entity_name_to_name;
|
||||
use super::ts_type::ts_type_ann_to_def;
|
||||
use super::ts_type::TsTypeDef;
|
||||
use super::ts_type_param::maybe_type_param_decl_to_type_param_defs;
|
||||
|
@ -12,6 +13,8 @@ use super::ts_type_param::TsTypeParamDef;
|
|||
use super::Location;
|
||||
use super::ParamDef;
|
||||
|
||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InterfaceMethodDef {
|
||||
|
@ -24,6 +27,22 @@ pub struct InterfaceMethodDef {
|
|||
pub type_params: Vec<TsTypeParamDef>,
|
||||
}
|
||||
|
||||
impl Display for InterfaceMethodDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(
|
||||
f,
|
||||
"{}{}({})",
|
||||
colors::bold(&self.name),
|
||||
display_optional(self.optional),
|
||||
SliceDisplayer::new(&self.params, ", ", false),
|
||||
)?;
|
||||
if let Some(return_type) = &self.return_type {
|
||||
write!(f, ": {}", return_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InterfacePropertyDef {
|
||||
|
@ -37,6 +56,44 @@ pub struct InterfacePropertyDef {
|
|||
pub type_params: Vec<TsTypeParamDef>,
|
||||
}
|
||||
|
||||
impl Display for InterfacePropertyDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(
|
||||
f,
|
||||
"{}{}",
|
||||
colors::bold(&self.name),
|
||||
display_optional(self.optional),
|
||||
)?;
|
||||
if let Some(ts_type) = &self.ts_type {
|
||||
write!(f, ": {}", ts_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InterfaceIndexSignatureDef {
|
||||
pub readonly: bool,
|
||||
pub params: Vec<ParamDef>,
|
||||
pub ts_type: Option<TsTypeDef>,
|
||||
}
|
||||
|
||||
impl Display for InterfaceIndexSignatureDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(
|
||||
f,
|
||||
"{}[{}]",
|
||||
display_readonly(self.readonly),
|
||||
SliceDisplayer::new(&self.params, ", ", false)
|
||||
)?;
|
||||
if let Some(ts_type) = &self.ts_type {
|
||||
write!(f, ": {}", ts_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InterfaceCallSignatureDef {
|
||||
|
@ -50,10 +107,11 @@ pub struct InterfaceCallSignatureDef {
|
|||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InterfaceDef {
|
||||
pub extends: Vec<String>,
|
||||
pub extends: Vec<TsTypeDef>,
|
||||
pub methods: Vec<InterfaceMethodDef>,
|
||||
pub properties: Vec<InterfacePropertyDef>,
|
||||
pub call_signatures: Vec<InterfaceCallSignatureDef>,
|
||||
pub index_signatures: Vec<InterfaceIndexSignatureDef>,
|
||||
pub type_params: Vec<TsTypeParamDef>,
|
||||
}
|
||||
|
||||
|
@ -84,6 +142,7 @@ pub fn get_doc_for_ts_interface_decl(
|
|||
let mut methods = vec![];
|
||||
let mut properties = vec![];
|
||||
let mut call_signatures = vec![];
|
||||
let mut index_signatures = vec![];
|
||||
|
||||
for type_element in &interface_decl.body.body {
|
||||
use crate::swc_ecma_ast::TsTypeElement::*;
|
||||
|
@ -95,7 +154,10 @@ pub fn get_doc_for_ts_interface_decl(
|
|||
let mut params = vec![];
|
||||
|
||||
for param in &ts_method_sig.params {
|
||||
let param_def = ts_fn_param_to_param_def(param);
|
||||
let param_def = ts_fn_param_to_param_def(
|
||||
param,
|
||||
Some(&doc_parser.ast_parser.source_map),
|
||||
);
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
|
@ -131,7 +193,10 @@ pub fn get_doc_for_ts_interface_decl(
|
|||
let mut params = vec![];
|
||||
|
||||
for param in &ts_prop_sig.params {
|
||||
let param_def = ts_fn_param_to_param_def(param);
|
||||
let param_def = ts_fn_param_to_param_def(
|
||||
param,
|
||||
Some(&doc_parser.ast_parser.source_map),
|
||||
);
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
|
@ -164,7 +229,10 @@ pub fn get_doc_for_ts_interface_decl(
|
|||
|
||||
let mut params = vec![];
|
||||
for param in &ts_call_sig.params {
|
||||
let param_def = ts_fn_param_to_param_def(param);
|
||||
let param_def = ts_fn_param_to_param_def(
|
||||
param,
|
||||
Some(&doc_parser.ast_parser.source_map),
|
||||
);
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
|
@ -189,9 +257,27 @@ pub fn get_doc_for_ts_interface_decl(
|
|||
};
|
||||
call_signatures.push(call_sig_def);
|
||||
}
|
||||
TsIndexSignature(ts_index_sig) => {
|
||||
let mut params = vec![];
|
||||
for param in &ts_index_sig.params {
|
||||
let param_def = ts_fn_param_to_param_def(param, None);
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
let ts_type = ts_index_sig
|
||||
.type_ann
|
||||
.as_ref()
|
||||
.map(|rt| (&*rt.type_ann).into());
|
||||
|
||||
let index_sig_def = InterfaceIndexSignatureDef {
|
||||
readonly: ts_index_sig.readonly,
|
||||
params,
|
||||
ts_type,
|
||||
};
|
||||
index_signatures.push(index_sig_def);
|
||||
}
|
||||
// TODO:
|
||||
TsConstructSignatureDecl(_) => {}
|
||||
TsIndexSignature(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,17 +285,18 @@ pub fn get_doc_for_ts_interface_decl(
|
|||
interface_decl.type_params.as_ref(),
|
||||
);
|
||||
|
||||
let extends: Vec<String> = interface_decl
|
||||
let extends = interface_decl
|
||||
.extends
|
||||
.iter()
|
||||
.map(|expr| ts_entity_name_to_name(&expr.expr))
|
||||
.collect();
|
||||
.map(|expr| expr.into())
|
||||
.collect::<Vec<TsTypeDef>>();
|
||||
|
||||
let interface_def = InterfaceDef {
|
||||
extends,
|
||||
methods,
|
||||
properties,
|
||||
call_signatures,
|
||||
index_signatures,
|
||||
type_params,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
pub mod class;
|
||||
mod display;
|
||||
pub mod r#enum;
|
||||
pub mod function;
|
||||
pub mod interface;
|
||||
|
@ -17,9 +18,9 @@ pub mod variable;
|
|||
pub use node::DocNode;
|
||||
pub use node::DocNodeKind;
|
||||
pub use node::Location;
|
||||
pub use node::ParamDef;
|
||||
pub use node::ParamKind;
|
||||
pub use params::ParamDef;
|
||||
pub use parser::DocParser;
|
||||
pub use printer::DocPrinter;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
|
|
@ -35,7 +35,8 @@ pub fn get_doc_node_for_export_decl(
|
|||
}
|
||||
}
|
||||
Decl::Fn(fn_decl) => {
|
||||
let (name, function_def) = super::function::get_doc_for_fn_decl(fn_decl);
|
||||
let (name, function_def) =
|
||||
super::function::get_doc_for_fn_decl(doc_parser, fn_decl);
|
||||
DocNode {
|
||||
kind: DocNodeKind::Function,
|
||||
name,
|
||||
|
|
|
@ -14,24 +14,6 @@ pub enum DocNodeKind {
|
|||
Namespace,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum ParamKind {
|
||||
Identifier,
|
||||
Rest,
|
||||
Array,
|
||||
Object,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ParamDef {
|
||||
pub name: String,
|
||||
pub kind: ParamKind,
|
||||
pub optional: bool,
|
||||
pub ts_type: Option<super::ts_type::TsTypeDef>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone, PartialEq)]
|
||||
pub struct Location {
|
||||
pub filename: String,
|
||||
|
@ -82,7 +64,7 @@ pub struct Reexport {
|
|||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ModuleDoc {
|
||||
pub exports: Vec<DocNode>,
|
||||
pub definitions: Vec<DocNode>,
|
||||
pub reexports: Vec<Reexport>,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,58 +1,228 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
use super::display::{display_optional, SliceDisplayer};
|
||||
use super::ts_type::{ts_type_ann_to_def, TsTypeDef};
|
||||
use crate::swc_common::SourceMap;
|
||||
use crate::swc_ecma_ast;
|
||||
use crate::swc_ecma_ast::{ObjectPatProp, Pat, TsFnParam};
|
||||
use serde::Serialize;
|
||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||
|
||||
use super::ts_type::ts_type_ann_to_def;
|
||||
use super::ParamDef;
|
||||
use super::ParamKind;
|
||||
use crate::swc_ecma_ast::Pat;
|
||||
use crate::swc_ecma_ast::TsFnParam;
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(tag = "kind")]
|
||||
pub enum ParamDef {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
Array {
|
||||
elements: Vec<Option<ParamDef>>,
|
||||
optional: bool,
|
||||
ts_type: Option<TsTypeDef>,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
Assign {
|
||||
left: Box<ParamDef>,
|
||||
right: String,
|
||||
ts_type: Option<TsTypeDef>,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
Identifier {
|
||||
name: String,
|
||||
optional: bool,
|
||||
ts_type: Option<TsTypeDef>,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
Object {
|
||||
props: Vec<ObjectPatPropDef>,
|
||||
optional: bool,
|
||||
ts_type: Option<TsTypeDef>,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
Rest {
|
||||
arg: Box<ParamDef>,
|
||||
ts_type: Option<TsTypeDef>,
|
||||
},
|
||||
}
|
||||
|
||||
pub fn ident_to_param_def(ident: &swc_ecma_ast::Ident) -> ParamDef {
|
||||
impl Display for ParamDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
match self {
|
||||
Self::Array {
|
||||
elements,
|
||||
optional,
|
||||
ts_type,
|
||||
} => {
|
||||
write!(f, "[")?;
|
||||
if !elements.is_empty() {
|
||||
if let Some(v) = &elements[0] {
|
||||
write!(f, "{}", v)?;
|
||||
}
|
||||
for maybe_v in &elements[1..] {
|
||||
write!(f, ", ")?;
|
||||
if let Some(v) = maybe_v {
|
||||
write!(f, "{}", v)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
write!(f, "]")?;
|
||||
write!(f, "{}", display_optional(*optional))?;
|
||||
if let Some(ts_type) = ts_type {
|
||||
write!(f, ": {}", ts_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Self::Assign { left, ts_type, .. } => {
|
||||
write!(f, "{}", left)?;
|
||||
if let Some(ts_type) = ts_type {
|
||||
write!(f, ": {}", ts_type)?;
|
||||
}
|
||||
// TODO(SyrupThinker) As we cannot display expressions the value is just omitted
|
||||
// write!(f, " = {}", right)?;
|
||||
Ok(())
|
||||
}
|
||||
Self::Identifier {
|
||||
name,
|
||||
optional,
|
||||
ts_type,
|
||||
} => {
|
||||
write!(f, "{}{}", name, display_optional(*optional))?;
|
||||
if let Some(ts_type) = ts_type {
|
||||
write!(f, ": {}", ts_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Self::Object {
|
||||
props,
|
||||
optional,
|
||||
ts_type,
|
||||
} => {
|
||||
write!(
|
||||
f,
|
||||
"{{{}}}{}",
|
||||
SliceDisplayer::new(&props, ", ", false),
|
||||
display_optional(*optional)
|
||||
)?;
|
||||
if let Some(ts_type) = ts_type {
|
||||
write!(f, ": {}", ts_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Self::Rest { arg, ts_type } => {
|
||||
write!(f, "...{}", arg)?;
|
||||
if let Some(ts_type) = ts_type {
|
||||
write!(f, ": {}", ts_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(tag = "kind")]
|
||||
pub enum ObjectPatPropDef {
|
||||
Assign { key: String, value: Option<String> },
|
||||
KeyValue { key: String, value: Box<ParamDef> },
|
||||
Rest { arg: Box<ParamDef> },
|
||||
}
|
||||
|
||||
impl Display for ObjectPatPropDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
match self {
|
||||
Self::KeyValue { key, .. } => {
|
||||
// The internal identifier does not need to be exposed
|
||||
write!(f, "{}", key)
|
||||
}
|
||||
Self::Assign { key, value } => {
|
||||
if let Some(_value) = value {
|
||||
// TODO(SyrupThinker) As we cannot display expressions the value is just omitted
|
||||
write!(f, "{}", key)
|
||||
} else {
|
||||
write!(f, "{}", key)
|
||||
}
|
||||
}
|
||||
Self::Rest { arg } => write!(f, "...{}", arg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ident_to_param_def(
|
||||
ident: &swc_ecma_ast::Ident,
|
||||
_source_map: Option<&SourceMap>,
|
||||
) -> ParamDef {
|
||||
let ts_type = ident.type_ann.as_ref().map(|rt| ts_type_ann_to_def(rt));
|
||||
|
||||
ParamDef {
|
||||
ParamDef::Identifier {
|
||||
name: ident.sym.to_string(),
|
||||
kind: ParamKind::Identifier,
|
||||
optional: ident.optional,
|
||||
ts_type,
|
||||
}
|
||||
}
|
||||
|
||||
fn rest_pat_to_param_def(rest_pat: &swc_ecma_ast::RestPat) -> ParamDef {
|
||||
let name = match &*rest_pat.arg {
|
||||
Pat::Ident(ident) => ident.sym.to_string(),
|
||||
_ => "<TODO>".to_string(),
|
||||
};
|
||||
fn rest_pat_to_param_def(
|
||||
rest_pat: &swc_ecma_ast::RestPat,
|
||||
source_map: Option<&SourceMap>,
|
||||
) -> ParamDef {
|
||||
let ts_type = rest_pat.type_ann.as_ref().map(|rt| ts_type_ann_to_def(rt));
|
||||
|
||||
ParamDef {
|
||||
name,
|
||||
kind: ParamKind::Rest,
|
||||
optional: false,
|
||||
ParamDef::Rest {
|
||||
arg: Box::new(pat_to_param_def(&*rest_pat.arg, source_map)),
|
||||
ts_type,
|
||||
}
|
||||
}
|
||||
|
||||
fn object_pat_to_param_def(object_pat: &swc_ecma_ast::ObjectPat) -> ParamDef {
|
||||
fn object_pat_prop_to_def(
|
||||
object_pat_prop: &ObjectPatProp,
|
||||
source_map: Option<&SourceMap>,
|
||||
) -> ObjectPatPropDef {
|
||||
match object_pat_prop {
|
||||
ObjectPatProp::Assign(assign) => ObjectPatPropDef::Assign {
|
||||
key: assign.key.sym.to_string(),
|
||||
value: assign.value.as_ref().map(|_| "<UNIMPLEMENTED>".to_string()),
|
||||
},
|
||||
ObjectPatProp::KeyValue(keyvalue) => ObjectPatPropDef::KeyValue {
|
||||
key: prop_name_to_string(&keyvalue.key, source_map),
|
||||
value: Box::new(pat_to_param_def(&*keyvalue.value, source_map)),
|
||||
},
|
||||
ObjectPatProp::Rest(rest) => ObjectPatPropDef::Rest {
|
||||
arg: Box::new(pat_to_param_def(&*rest.arg, source_map)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn object_pat_to_param_def(
|
||||
object_pat: &swc_ecma_ast::ObjectPat,
|
||||
source_map: Option<&SourceMap>,
|
||||
) -> ParamDef {
|
||||
let props = object_pat
|
||||
.props
|
||||
.iter()
|
||||
.map(|prop| object_pat_prop_to_def(prop, source_map))
|
||||
.collect::<Vec<_>>();
|
||||
let ts_type = object_pat
|
||||
.type_ann
|
||||
.as_ref()
|
||||
.map(|rt| ts_type_ann_to_def(rt));
|
||||
|
||||
ParamDef {
|
||||
name: "".to_string(),
|
||||
kind: ParamKind::Object,
|
||||
ParamDef::Object {
|
||||
props,
|
||||
optional: object_pat.optional,
|
||||
ts_type,
|
||||
}
|
||||
}
|
||||
|
||||
fn array_pat_to_param_def(array_pat: &swc_ecma_ast::ArrayPat) -> ParamDef {
|
||||
fn array_pat_to_param_def(
|
||||
array_pat: &swc_ecma_ast::ArrayPat,
|
||||
source_map: Option<&SourceMap>,
|
||||
) -> ParamDef {
|
||||
let elements = array_pat
|
||||
.elems
|
||||
.iter()
|
||||
.map(|elem| elem.as_ref().map(|e| pat_to_param_def(e, source_map)))
|
||||
.collect::<Vec<Option<_>>>();
|
||||
let ts_type = array_pat.type_ann.as_ref().map(|rt| ts_type_ann_to_def(rt));
|
||||
|
||||
ParamDef {
|
||||
name: "".to_string(),
|
||||
kind: ParamKind::Array,
|
||||
ParamDef::Array {
|
||||
elements,
|
||||
optional: array_pat.optional,
|
||||
ts_type,
|
||||
}
|
||||
|
@ -60,28 +230,61 @@ fn array_pat_to_param_def(array_pat: &swc_ecma_ast::ArrayPat) -> ParamDef {
|
|||
|
||||
pub fn assign_pat_to_param_def(
|
||||
assign_pat: &swc_ecma_ast::AssignPat,
|
||||
source_map: Option<&SourceMap>,
|
||||
) -> ParamDef {
|
||||
pat_to_param_def(&*assign_pat.left)
|
||||
let ts_type = assign_pat
|
||||
.type_ann
|
||||
.as_ref()
|
||||
.map(|rt| ts_type_ann_to_def(rt));
|
||||
|
||||
ParamDef::Assign {
|
||||
left: Box::new(pat_to_param_def(&*assign_pat.left, source_map)),
|
||||
right: "<UNIMPLEMENTED>".to_string(),
|
||||
ts_type,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pat_to_param_def(pat: &swc_ecma_ast::Pat) -> ParamDef {
|
||||
pub fn pat_to_param_def(
|
||||
pat: &swc_ecma_ast::Pat,
|
||||
source_map: Option<&SourceMap>,
|
||||
) -> ParamDef {
|
||||
match pat {
|
||||
Pat::Ident(ident) => ident_to_param_def(ident),
|
||||
Pat::Array(array_pat) => array_pat_to_param_def(array_pat),
|
||||
Pat::Rest(rest_pat) => rest_pat_to_param_def(rest_pat),
|
||||
Pat::Object(object_pat) => object_pat_to_param_def(object_pat),
|
||||
Pat::Assign(assign_pat) => assign_pat_to_param_def(assign_pat),
|
||||
Pat::Ident(ident) => ident_to_param_def(ident, source_map),
|
||||
Pat::Array(array_pat) => array_pat_to_param_def(array_pat, source_map),
|
||||
Pat::Rest(rest_pat) => rest_pat_to_param_def(rest_pat, source_map),
|
||||
Pat::Object(object_pat) => object_pat_to_param_def(object_pat, source_map),
|
||||
Pat::Assign(assign_pat) => assign_pat_to_param_def(assign_pat, source_map),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ts_fn_param_to_param_def(
|
||||
ts_fn_param: &swc_ecma_ast::TsFnParam,
|
||||
source_map: Option<&SourceMap>,
|
||||
) -> ParamDef {
|
||||
match ts_fn_param {
|
||||
TsFnParam::Ident(ident) => ident_to_param_def(ident),
|
||||
TsFnParam::Array(array_pat) => array_pat_to_param_def(array_pat),
|
||||
TsFnParam::Rest(rest_pat) => rest_pat_to_param_def(rest_pat),
|
||||
TsFnParam::Object(object_pat) => object_pat_to_param_def(object_pat),
|
||||
TsFnParam::Ident(ident) => ident_to_param_def(ident, source_map),
|
||||
TsFnParam::Array(array_pat) => {
|
||||
array_pat_to_param_def(array_pat, source_map)
|
||||
}
|
||||
TsFnParam::Rest(rest_pat) => rest_pat_to_param_def(rest_pat, source_map),
|
||||
TsFnParam::Object(object_pat) => {
|
||||
object_pat_to_param_def(object_pat, source_map)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prop_name_to_string(
|
||||
prop_name: &swc_ecma_ast::PropName,
|
||||
source_map: Option<&SourceMap>,
|
||||
) -> String {
|
||||
use crate::swc_ecma_ast::PropName;
|
||||
match prop_name {
|
||||
PropName::Ident(ident) => ident.sym.to_string(),
|
||||
PropName::Str(str_) => str_.value.to_string(),
|
||||
PropName::Num(num) => num.value.to_string(),
|
||||
PropName::Computed(comp_prop_name) => source_map
|
||||
.map(|sm| sm.span_to_snippet(comp_prop_name.span).unwrap())
|
||||
.unwrap_or_else(|| "<UNAVAILABLE>".to_string()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,13 +44,15 @@ pub trait DocFileLoader {
|
|||
pub struct DocParser {
|
||||
pub ast_parser: AstParser,
|
||||
pub loader: Box<dyn DocFileLoader>,
|
||||
pub private: bool,
|
||||
}
|
||||
|
||||
impl DocParser {
|
||||
pub fn new(loader: Box<dyn DocFileLoader>) -> Self {
|
||||
pub fn new(loader: Box<dyn DocFileLoader>, private: bool) -> Self {
|
||||
DocParser {
|
||||
loader,
|
||||
ast_parser: AstParser::new(),
|
||||
private,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,7 +72,7 @@ impl DocParser {
|
|||
self.get_doc_nodes_for_module_body(module.body.clone());
|
||||
let reexports = self.get_reexports_for_module_body(module.body);
|
||||
let module_doc = ModuleDoc {
|
||||
exports: doc_entries,
|
||||
definitions: doc_entries,
|
||||
reexports,
|
||||
};
|
||||
Ok(module_doc)
|
||||
|
@ -90,7 +92,7 @@ impl DocParser {
|
|||
source_code: &str,
|
||||
) -> Result<Vec<DocNode>, ErrBox> {
|
||||
let module_doc = self.parse_module(file_name, &source_code)?;
|
||||
Ok(module_doc.exports)
|
||||
Ok(module_doc.definitions)
|
||||
}
|
||||
|
||||
async fn flatten_reexports(
|
||||
|
@ -187,10 +189,10 @@ impl DocParser {
|
|||
let mut flattenned_reexports = self
|
||||
.flatten_reexports(&module_doc.reexports, file_name)
|
||||
.await?;
|
||||
flattenned_reexports.extend(module_doc.exports);
|
||||
flattenned_reexports.extend(module_doc.definitions);
|
||||
flattenned_reexports
|
||||
} else {
|
||||
module_doc.exports
|
||||
module_doc.definitions
|
||||
};
|
||||
|
||||
Ok(flattened_docs)
|
||||
|
@ -231,8 +233,10 @@ impl DocParser {
|
|||
}
|
||||
}
|
||||
DefaultDecl::Fn(fn_expr) => {
|
||||
let function_def =
|
||||
crate::doc::function::function_to_function_def(&fn_expr.function);
|
||||
let function_def = crate::doc::function::function_to_function_def(
|
||||
self,
|
||||
&fn_expr.function,
|
||||
);
|
||||
DocNode {
|
||||
kind: DocNodeKind::Function,
|
||||
name,
|
||||
|
@ -292,7 +296,7 @@ impl DocParser {
|
|||
pub fn get_doc_node_for_decl(&self, decl: &Decl) -> Option<DocNode> {
|
||||
match decl {
|
||||
Decl::Class(class_decl) => {
|
||||
if !class_decl.declare {
|
||||
if !self.private && !class_decl.declare {
|
||||
return None;
|
||||
}
|
||||
let (name, class_def) =
|
||||
|
@ -313,11 +317,11 @@ impl DocParser {
|
|||
})
|
||||
}
|
||||
Decl::Fn(fn_decl) => {
|
||||
if !fn_decl.declare {
|
||||
if !self.private && !fn_decl.declare {
|
||||
return None;
|
||||
}
|
||||
let (name, function_def) =
|
||||
super::function::get_doc_for_fn_decl(fn_decl);
|
||||
super::function::get_doc_for_fn_decl(self, fn_decl);
|
||||
let (js_doc, location) = self.details_for_span(fn_decl.function.span);
|
||||
Some(DocNode {
|
||||
kind: DocNodeKind::Function,
|
||||
|
@ -334,7 +338,7 @@ impl DocParser {
|
|||
})
|
||||
}
|
||||
Decl::Var(var_decl) => {
|
||||
if !var_decl.declare {
|
||||
if !self.private && !var_decl.declare {
|
||||
return None;
|
||||
}
|
||||
let (name, var_def) = super::variable::get_doc_for_var_decl(var_decl);
|
||||
|
@ -354,7 +358,7 @@ impl DocParser {
|
|||
})
|
||||
}
|
||||
Decl::TsInterface(ts_interface_decl) => {
|
||||
if !ts_interface_decl.declare {
|
||||
if !self.private && !ts_interface_decl.declare {
|
||||
return None;
|
||||
}
|
||||
let (name, interface_def) =
|
||||
|
@ -378,7 +382,7 @@ impl DocParser {
|
|||
})
|
||||
}
|
||||
Decl::TsTypeAlias(ts_type_alias) => {
|
||||
if !ts_type_alias.declare {
|
||||
if !self.private && !ts_type_alias.declare {
|
||||
return None;
|
||||
}
|
||||
let (name, type_alias_def) =
|
||||
|
@ -402,7 +406,7 @@ impl DocParser {
|
|||
})
|
||||
}
|
||||
Decl::TsEnum(ts_enum) => {
|
||||
if !ts_enum.declare {
|
||||
if !self.private && !ts_enum.declare {
|
||||
return None;
|
||||
}
|
||||
let (name, enum_def) =
|
||||
|
@ -423,7 +427,7 @@ impl DocParser {
|
|||
})
|
||||
}
|
||||
Decl::TsModule(ts_module) => {
|
||||
if !ts_module.declare {
|
||||
if !self.private && !ts_module.declare {
|
||||
return None;
|
||||
}
|
||||
let (name, namespace_def) =
|
||||
|
|
|
@ -12,540 +12,463 @@
|
|||
|
||||
use crate::colors;
|
||||
use crate::doc;
|
||||
use crate::doc::ts_type::TsTypeDefKind;
|
||||
use crate::doc::display::{
|
||||
display_abstract, display_async, display_generator, Indent, SliceDisplayer,
|
||||
};
|
||||
use crate::doc::DocNodeKind;
|
||||
use crate::swc_ecma_ast;
|
||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||
|
||||
pub fn format(doc_nodes: Vec<doc::DocNode>) -> String {
|
||||
format_(doc_nodes, 0)
|
||||
pub struct DocPrinter<'a> {
|
||||
doc_nodes: &'a [doc::DocNode],
|
||||
details: bool,
|
||||
private: bool,
|
||||
}
|
||||
|
||||
pub fn format_details(node: doc::DocNode) -> String {
|
||||
let mut details = String::new();
|
||||
|
||||
details.push_str(&format!(
|
||||
"{}",
|
||||
colors::gray(&format!(
|
||||
"Defined in {}:{}:{} \n\n",
|
||||
node.location.filename, node.location.line, node.location.col
|
||||
))
|
||||
));
|
||||
|
||||
details.push_str(&format_signature(&node, 0));
|
||||
|
||||
let js_doc = node.js_doc.clone();
|
||||
if let Some(js_doc) = js_doc {
|
||||
details.push_str(&format_jsdoc(js_doc, 1));
|
||||
}
|
||||
details.push_str("\n");
|
||||
|
||||
let maybe_extra = match node.kind {
|
||||
DocNodeKind::Class => Some(format_class_details(node)),
|
||||
DocNodeKind::Enum => Some(format_enum_details(node)),
|
||||
DocNodeKind::Namespace => Some(format_namespace_details(node)),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(extra) = maybe_extra {
|
||||
details.push_str(&extra);
|
||||
impl<'a> DocPrinter<'a> {
|
||||
pub fn new(
|
||||
doc_nodes: &[doc::DocNode],
|
||||
details: bool,
|
||||
private: bool,
|
||||
) -> DocPrinter {
|
||||
DocPrinter {
|
||||
doc_nodes,
|
||||
details,
|
||||
private,
|
||||
}
|
||||
}
|
||||
|
||||
details
|
||||
}
|
||||
|
||||
fn kind_order(kind: &doc::DocNodeKind) -> i64 {
|
||||
match kind {
|
||||
DocNodeKind::Function => 0,
|
||||
DocNodeKind::Variable => 1,
|
||||
DocNodeKind::Class => 2,
|
||||
DocNodeKind::Enum => 3,
|
||||
DocNodeKind::Interface => 4,
|
||||
DocNodeKind::TypeAlias => 5,
|
||||
DocNodeKind::Namespace => 6,
|
||||
}
|
||||
}
|
||||
|
||||
fn format_signature(node: &doc::DocNode, indent: i64) -> String {
|
||||
match node.kind {
|
||||
DocNodeKind::Function => format_function_signature(&node, indent),
|
||||
DocNodeKind::Variable => format_variable_signature(&node, indent),
|
||||
DocNodeKind::Class => format_class_signature(&node, indent),
|
||||
DocNodeKind::Enum => format_enum_signature(&node, indent),
|
||||
DocNodeKind::Interface => format_interface_signature(&node, indent),
|
||||
DocNodeKind::TypeAlias => format_type_alias_signature(&node, indent),
|
||||
DocNodeKind::Namespace => format_namespace_signature(&node, indent),
|
||||
}
|
||||
}
|
||||
|
||||
fn format_(doc_nodes: Vec<doc::DocNode>, indent: i64) -> String {
|
||||
let mut sorted = doc_nodes;
|
||||
sorted.sort_unstable_by(|a, b| {
|
||||
let kind_cmp = kind_order(&a.kind).cmp(&kind_order(&b.kind));
|
||||
if kind_cmp == core::cmp::Ordering::Equal {
|
||||
a.name.cmp(&b.name)
|
||||
pub fn format(&self, w: &mut Formatter<'_>) -> FmtResult {
|
||||
if self.details {
|
||||
self.format_details(w, self.doc_nodes, 0)
|
||||
} else {
|
||||
kind_cmp
|
||||
}
|
||||
});
|
||||
|
||||
let mut output = String::new();
|
||||
|
||||
for node in sorted {
|
||||
output.push_str(&format_signature(&node, indent));
|
||||
if let Some(js_doc) = node.js_doc {
|
||||
output.push_str(&format_jsdoc(js_doc, indent));
|
||||
}
|
||||
output.push_str("\n");
|
||||
if DocNodeKind::Namespace == node.kind {
|
||||
output.push_str(&format_(
|
||||
node.namespace_def.as_ref().unwrap().elements.clone(),
|
||||
indent + 1,
|
||||
));
|
||||
output.push_str("\n");
|
||||
};
|
||||
}
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
fn render_params(params: Vec<doc::ParamDef>) -> String {
|
||||
let mut rendered = String::from("");
|
||||
if !params.is_empty() {
|
||||
for param in params {
|
||||
rendered += param.name.as_str();
|
||||
if param.optional {
|
||||
rendered += "?";
|
||||
}
|
||||
if let Some(ts_type) = param.ts_type {
|
||||
rendered += ": ";
|
||||
rendered += render_ts_type(ts_type).as_str();
|
||||
}
|
||||
rendered += ", ";
|
||||
}
|
||||
rendered.truncate(rendered.len() - 2);
|
||||
}
|
||||
rendered
|
||||
}
|
||||
|
||||
fn render_ts_type(ts_type: doc::ts_type::TsTypeDef) -> String {
|
||||
if ts_type.kind.is_none() {
|
||||
return "<UNIMPLEMENTED>".to_string();
|
||||
}
|
||||
let kind = ts_type.kind.unwrap();
|
||||
match kind {
|
||||
TsTypeDefKind::Array => {
|
||||
format!("{}[]", render_ts_type(*ts_type.array.unwrap()))
|
||||
}
|
||||
TsTypeDefKind::Conditional => {
|
||||
let conditional = ts_type.conditional_type.unwrap();
|
||||
format!(
|
||||
"{} extends {} ? {} : {}",
|
||||
render_ts_type(*conditional.check_type),
|
||||
render_ts_type(*conditional.extends_type),
|
||||
render_ts_type(*conditional.true_type),
|
||||
render_ts_type(*conditional.false_type)
|
||||
)
|
||||
}
|
||||
TsTypeDefKind::FnOrConstructor => {
|
||||
let fn_or_constructor = ts_type.fn_or_constructor.unwrap();
|
||||
format!(
|
||||
"{}({}) => {}",
|
||||
if fn_or_constructor.constructor {
|
||||
"new "
|
||||
} else {
|
||||
""
|
||||
},
|
||||
render_params(fn_or_constructor.params),
|
||||
render_ts_type(fn_or_constructor.ts_type),
|
||||
)
|
||||
}
|
||||
TsTypeDefKind::IndexedAccess => {
|
||||
let indexed_access = ts_type.indexed_access.unwrap();
|
||||
format!(
|
||||
"{}[{}]",
|
||||
render_ts_type(*indexed_access.obj_type),
|
||||
render_ts_type(*indexed_access.index_type)
|
||||
)
|
||||
}
|
||||
TsTypeDefKind::Intersection => {
|
||||
let intersection = ts_type.intersection.unwrap();
|
||||
let mut output = "".to_string();
|
||||
if !intersection.is_empty() {
|
||||
for ts_type in intersection {
|
||||
output += render_ts_type(ts_type).as_str();
|
||||
output += " & "
|
||||
}
|
||||
output.truncate(output.len() - 3);
|
||||
}
|
||||
output
|
||||
}
|
||||
TsTypeDefKind::Keyword => ts_type.keyword.unwrap(),
|
||||
TsTypeDefKind::Literal => {
|
||||
let literal = ts_type.literal.unwrap();
|
||||
match literal.kind {
|
||||
doc::ts_type::LiteralDefKind::Boolean => {
|
||||
format!("{}", literal.boolean.unwrap())
|
||||
}
|
||||
doc::ts_type::LiteralDefKind::String => {
|
||||
"\"".to_string() + literal.string.unwrap().as_str() + "\""
|
||||
}
|
||||
doc::ts_type::LiteralDefKind::Number => {
|
||||
format!("{}", literal.number.unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
TsTypeDefKind::Optional => {
|
||||
format!("{}?", render_ts_type(*ts_type.optional.unwrap()))
|
||||
}
|
||||
TsTypeDefKind::Parenthesized => {
|
||||
format!("({})", render_ts_type(*ts_type.parenthesized.unwrap()))
|
||||
}
|
||||
TsTypeDefKind::Rest => {
|
||||
format!("...{}", render_ts_type(*ts_type.rest.unwrap()))
|
||||
}
|
||||
TsTypeDefKind::This => "this".to_string(),
|
||||
TsTypeDefKind::Tuple => {
|
||||
let tuple = ts_type.tuple.unwrap();
|
||||
let mut output = "[".to_string();
|
||||
if !tuple.is_empty() {
|
||||
for ts_type in tuple {
|
||||
output += render_ts_type(ts_type).as_str();
|
||||
output += ", "
|
||||
}
|
||||
output.truncate(output.len() - 2);
|
||||
}
|
||||
output += "]";
|
||||
output
|
||||
}
|
||||
TsTypeDefKind::TypeLiteral => {
|
||||
let mut output = "".to_string();
|
||||
let type_literal = ts_type.type_literal.unwrap();
|
||||
for node in type_literal.call_signatures {
|
||||
output += format!(
|
||||
"({}){}, ",
|
||||
render_params(node.params),
|
||||
if let Some(ts_type) = node.ts_type {
|
||||
format!(": {}", render_ts_type(ts_type))
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
)
|
||||
.as_str()
|
||||
}
|
||||
for node in type_literal.methods {
|
||||
output += format!(
|
||||
"{}({}){}, ",
|
||||
node.name,
|
||||
render_params(node.params),
|
||||
if let Some(return_type) = node.return_type {
|
||||
format!(": {}", render_ts_type(return_type))
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
)
|
||||
.as_str()
|
||||
}
|
||||
for node in type_literal.properties {
|
||||
output += format!(
|
||||
"{}{}, ",
|
||||
node.name,
|
||||
if let Some(ts_type) = node.ts_type {
|
||||
format!(": {}", render_ts_type(ts_type))
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
)
|
||||
.as_str()
|
||||
}
|
||||
if !output.is_empty() {
|
||||
output.truncate(output.len() - 2);
|
||||
}
|
||||
"{ ".to_string() + output.as_str() + " }"
|
||||
}
|
||||
TsTypeDefKind::TypeOperator => {
|
||||
let operator = ts_type.type_operator.unwrap();
|
||||
format!("{} {}", operator.operator, render_ts_type(operator.ts_type))
|
||||
}
|
||||
TsTypeDefKind::TypeQuery => {
|
||||
format!("typeof {}", ts_type.type_query.unwrap())
|
||||
}
|
||||
TsTypeDefKind::TypeRef => {
|
||||
let type_ref = ts_type.type_ref.unwrap();
|
||||
let mut final_output = type_ref.type_name;
|
||||
if let Some(type_params) = type_ref.type_params {
|
||||
let mut output = "".to_string();
|
||||
if !type_params.is_empty() {
|
||||
for ts_type in type_params {
|
||||
output += render_ts_type(ts_type).as_str();
|
||||
output += ", "
|
||||
}
|
||||
output.truncate(output.len() - 2);
|
||||
}
|
||||
final_output += format!("<{}>", output).as_str();
|
||||
}
|
||||
final_output
|
||||
}
|
||||
TsTypeDefKind::Union => {
|
||||
let union = ts_type.union.unwrap();
|
||||
let mut output = "".to_string();
|
||||
if !union.is_empty() {
|
||||
for ts_type in union {
|
||||
output += render_ts_type(ts_type).as_str();
|
||||
output += " | "
|
||||
}
|
||||
output.truncate(output.len() - 3);
|
||||
}
|
||||
output
|
||||
self.format_summary(w, self.doc_nodes, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_indent(string: String, indent: i64) -> String {
|
||||
let mut indent_str = String::new();
|
||||
for _ in 0..(indent * 2) {
|
||||
indent_str += " ";
|
||||
}
|
||||
indent_str += string.as_str();
|
||||
indent_str
|
||||
}
|
||||
|
||||
// TODO: this should use some sort of markdown to console parser.
|
||||
fn format_jsdoc(jsdoc: String, indent: i64) -> String {
|
||||
let lines = jsdoc.split("\n\n").map(|line| line.replace("\n", " "));
|
||||
|
||||
let mut js_doc = String::new();
|
||||
|
||||
for line in lines {
|
||||
js_doc.push_str(&add_indent(format!("{}\n", line), indent + 1));
|
||||
}
|
||||
|
||||
format!("{}", colors::gray(&js_doc))
|
||||
}
|
||||
|
||||
fn format_class_details(node: doc::DocNode) -> String {
|
||||
let mut details = String::new();
|
||||
|
||||
let class_def = node.class_def.unwrap();
|
||||
for node in class_def.constructors {
|
||||
details.push_str(&add_indent(
|
||||
format!(
|
||||
"{} {}({})\n",
|
||||
colors::magenta("constructor"),
|
||||
colors::bold(&node.name),
|
||||
render_params(node.params),
|
||||
),
|
||||
1,
|
||||
));
|
||||
}
|
||||
for node in class_def.properties.iter().filter(|node| {
|
||||
node
|
||||
.accessibility
|
||||
.unwrap_or(swc_ecma_ast::Accessibility::Public)
|
||||
!= swc_ecma_ast::Accessibility::Private
|
||||
}) {
|
||||
details.push_str(&add_indent(
|
||||
format!(
|
||||
"{}{}{}{}\n",
|
||||
colors::magenta(
|
||||
match node
|
||||
.accessibility
|
||||
.unwrap_or(swc_ecma_ast::Accessibility::Public)
|
||||
{
|
||||
swc_ecma_ast::Accessibility::Protected => "protected ",
|
||||
_ => "",
|
||||
}
|
||||
),
|
||||
colors::bold(&node.name),
|
||||
if node.optional {
|
||||
"?".to_string()
|
||||
} else {
|
||||
"".to_string()
|
||||
},
|
||||
if let Some(ts_type) = node.ts_type.clone() {
|
||||
format!(": {}", render_ts_type(ts_type))
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
),
|
||||
1,
|
||||
));
|
||||
}
|
||||
for node in class_def.methods.iter().filter(|node| {
|
||||
node
|
||||
.accessibility
|
||||
.unwrap_or(swc_ecma_ast::Accessibility::Public)
|
||||
!= swc_ecma_ast::Accessibility::Private
|
||||
}) {
|
||||
let function_def = node.function_def.clone();
|
||||
details.push_str(&add_indent(
|
||||
format!(
|
||||
"{}{}{}{}({}){}\n",
|
||||
colors::magenta(
|
||||
match node
|
||||
.accessibility
|
||||
.unwrap_or(swc_ecma_ast::Accessibility::Public)
|
||||
{
|
||||
swc_ecma_ast::Accessibility::Protected => "protected ",
|
||||
_ => "",
|
||||
}
|
||||
),
|
||||
colors::magenta(match node.kind {
|
||||
swc_ecma_ast::MethodKind::Getter => "get ",
|
||||
swc_ecma_ast::MethodKind::Setter => "set ",
|
||||
_ => "",
|
||||
}),
|
||||
colors::bold(&node.name),
|
||||
if node.optional { "?" } else { "" },
|
||||
render_params(function_def.params),
|
||||
if let Some(return_type) = function_def.return_type {
|
||||
format!(": {}", render_ts_type(return_type))
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
),
|
||||
1,
|
||||
));
|
||||
}
|
||||
details.push_str("\n");
|
||||
details
|
||||
}
|
||||
|
||||
fn format_enum_details(node: doc::DocNode) -> String {
|
||||
let mut details = String::new();
|
||||
let enum_def = node.enum_def.unwrap();
|
||||
for member in enum_def.members {
|
||||
details
|
||||
.push_str(&add_indent(format!("{}\n", colors::bold(&member.name)), 1));
|
||||
}
|
||||
details.push_str("\n");
|
||||
details
|
||||
}
|
||||
|
||||
fn format_namespace_details(node: doc::DocNode) -> String {
|
||||
let mut ns = String::new();
|
||||
|
||||
let elements = node.namespace_def.unwrap().elements;
|
||||
for node in elements {
|
||||
ns.push_str(&format_signature(&node, 1));
|
||||
}
|
||||
ns.push_str("\n");
|
||||
ns
|
||||
}
|
||||
|
||||
fn format_function_signature(node: &doc::DocNode, indent: i64) -> String {
|
||||
let function_def = node.function_def.clone().unwrap();
|
||||
add_indent(
|
||||
format!(
|
||||
"{} {}({}){}\n",
|
||||
colors::magenta("function"),
|
||||
colors::bold(&node.name),
|
||||
render_params(function_def.params),
|
||||
if let Some(return_type) = function_def.return_type {
|
||||
format!(": {}", render_ts_type(return_type).as_str())
|
||||
fn format_summary(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
doc_nodes: &[doc::DocNode],
|
||||
indent: i64,
|
||||
) -> FmtResult {
|
||||
let mut sorted = Vec::from(doc_nodes);
|
||||
sorted.sort_unstable_by(|a, b| {
|
||||
let kind_cmp = self.kind_order(&a.kind).cmp(&self.kind_order(&b.kind));
|
||||
if kind_cmp == core::cmp::Ordering::Equal {
|
||||
a.name.cmp(&b.name)
|
||||
} else {
|
||||
"".to_string()
|
||||
kind_cmp
|
||||
}
|
||||
),
|
||||
indent,
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
fn format_class_signature(node: &doc::DocNode, indent: i64) -> String {
|
||||
let class_def = node.class_def.clone().unwrap();
|
||||
let extends_suffix = if let Some(extends) = class_def.extends {
|
||||
format!(" {} {}", colors::magenta("extends"), colors::bold(&extends))
|
||||
} else {
|
||||
String::from("")
|
||||
};
|
||||
for node in sorted {
|
||||
self.format_signature(w, &node, indent)?;
|
||||
|
||||
let implements = &class_def.implements;
|
||||
let implements_suffix = if !implements.is_empty() {
|
||||
format!(
|
||||
" {} {}",
|
||||
colors::magenta("implements"),
|
||||
colors::bold(&implements.join(", "))
|
||||
)
|
||||
} else {
|
||||
String::from("")
|
||||
};
|
||||
if let Some(js_doc) = &node.js_doc {
|
||||
self.format_jsdoc(w, js_doc, indent + 1, self.details)?;
|
||||
}
|
||||
|
||||
add_indent(
|
||||
format!(
|
||||
"{} {}{}{}\n",
|
||||
writeln!(w)?;
|
||||
|
||||
if DocNodeKind::Namespace == node.kind {
|
||||
self.format_summary(
|
||||
w,
|
||||
&node.namespace_def.as_ref().unwrap().elements,
|
||||
indent + 1,
|
||||
)?;
|
||||
|
||||
writeln!(w)?;
|
||||
};
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn format_details(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
doc_nodes: &[doc::DocNode],
|
||||
indent: i64,
|
||||
) -> FmtResult {
|
||||
for node in doc_nodes {
|
||||
write!(
|
||||
w,
|
||||
"{}",
|
||||
colors::italic_gray(&format!(
|
||||
"Defined in {}:{}:{} \n\n",
|
||||
node.location.filename, node.location.line, node.location.col
|
||||
))
|
||||
)?;
|
||||
|
||||
self.format_signature(w, &node, indent)?;
|
||||
|
||||
let js_doc = &node.js_doc;
|
||||
if let Some(js_doc) = js_doc {
|
||||
self.format_jsdoc(w, js_doc, indent + 1, self.details)?;
|
||||
}
|
||||
writeln!(w)?;
|
||||
|
||||
match node.kind {
|
||||
DocNodeKind::Class => self.format_class_details(w, node)?,
|
||||
DocNodeKind::Enum => self.format_enum_details(w, node)?,
|
||||
DocNodeKind::Interface => self.format_interface_details(w, node)?,
|
||||
DocNodeKind::Namespace => self.format_namespace_details(w, node)?,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn kind_order(&self, kind: &doc::DocNodeKind) -> i64 {
|
||||
match kind {
|
||||
DocNodeKind::Function => 0,
|
||||
DocNodeKind::Variable => 1,
|
||||
DocNodeKind::Class => 2,
|
||||
DocNodeKind::Enum => 3,
|
||||
DocNodeKind::Interface => 4,
|
||||
DocNodeKind::TypeAlias => 5,
|
||||
DocNodeKind::Namespace => 6,
|
||||
}
|
||||
}
|
||||
|
||||
fn format_signature(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
indent: i64,
|
||||
) -> FmtResult {
|
||||
match node.kind {
|
||||
DocNodeKind::Function => self.format_function_signature(w, node, indent),
|
||||
DocNodeKind::Variable => self.format_variable_signature(w, node, indent),
|
||||
DocNodeKind::Class => self.format_class_signature(w, node, indent),
|
||||
DocNodeKind::Enum => self.format_enum_signature(w, node, indent),
|
||||
DocNodeKind::Interface => {
|
||||
self.format_interface_signature(w, node, indent)
|
||||
}
|
||||
DocNodeKind::TypeAlias => {
|
||||
self.format_type_alias_signature(w, node, indent)
|
||||
}
|
||||
DocNodeKind::Namespace => {
|
||||
self.format_namespace_signature(w, node, indent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(SyrupThinker) this should use a JSDoc parser
|
||||
fn format_jsdoc(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
jsdoc: &str,
|
||||
indent: i64,
|
||||
details: bool,
|
||||
) -> FmtResult {
|
||||
for line in jsdoc.lines() {
|
||||
// Only show the first paragraph when summarising
|
||||
// This should use the @summary JSDoc tag instead
|
||||
if !details && line.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
writeln!(w, "{}{}", Indent(indent), colors::gray(&line))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn format_class_details(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
) -> FmtResult {
|
||||
let class_def = node.class_def.as_ref().unwrap();
|
||||
for node in &class_def.constructors {
|
||||
writeln!(w, "{}{}", Indent(1), node,)?;
|
||||
if let Some(js_doc) = &node.js_doc {
|
||||
self.format_jsdoc(w, &js_doc, 2, self.details)?;
|
||||
}
|
||||
}
|
||||
for node in class_def.properties.iter().filter(|node| {
|
||||
self.private
|
||||
|| node
|
||||
.accessibility
|
||||
.unwrap_or(swc_ecma_ast::Accessibility::Public)
|
||||
!= swc_ecma_ast::Accessibility::Private
|
||||
}) {
|
||||
writeln!(w, "{}{}", Indent(1), node,)?;
|
||||
if let Some(js_doc) = &node.js_doc {
|
||||
self.format_jsdoc(w, &js_doc, 2, self.details)?;
|
||||
}
|
||||
}
|
||||
for index_sign_def in &class_def.index_signatures {
|
||||
writeln!(w, "{}{}", Indent(1), index_sign_def)?;
|
||||
}
|
||||
for node in class_def.methods.iter().filter(|node| {
|
||||
self.private
|
||||
|| node
|
||||
.accessibility
|
||||
.unwrap_or(swc_ecma_ast::Accessibility::Public)
|
||||
!= swc_ecma_ast::Accessibility::Private
|
||||
}) {
|
||||
writeln!(w, "{}{}", Indent(1), node,)?;
|
||||
if let Some(js_doc) = &node.js_doc {
|
||||
self.format_jsdoc(w, js_doc, 2, self.details)?;
|
||||
}
|
||||
}
|
||||
writeln!(w)
|
||||
}
|
||||
|
||||
fn format_enum_details(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
) -> FmtResult {
|
||||
let enum_def = node.enum_def.as_ref().unwrap();
|
||||
for member in &enum_def.members {
|
||||
writeln!(w, "{}{}", Indent(1), colors::bold(&member.name))?;
|
||||
}
|
||||
writeln!(w)
|
||||
}
|
||||
|
||||
fn format_interface_details(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
) -> FmtResult {
|
||||
let interface_def = node.interface_def.as_ref().unwrap();
|
||||
|
||||
for property_def in &interface_def.properties {
|
||||
writeln!(w, "{}{}", Indent(1), property_def)?;
|
||||
if let Some(js_doc) = &property_def.js_doc {
|
||||
self.format_jsdoc(w, js_doc, 2, self.details)?;
|
||||
}
|
||||
}
|
||||
for method_def in &interface_def.methods {
|
||||
writeln!(w, "{}{}", Indent(1), method_def)?;
|
||||
if let Some(js_doc) = &method_def.js_doc {
|
||||
self.format_jsdoc(w, js_doc, 2, self.details)?;
|
||||
}
|
||||
}
|
||||
for index_sign_def in &interface_def.index_signatures {
|
||||
writeln!(w, "{}{}", Indent(1), index_sign_def)?;
|
||||
}
|
||||
writeln!(w)
|
||||
}
|
||||
|
||||
fn format_namespace_details(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
) -> FmtResult {
|
||||
let elements = &node.namespace_def.as_ref().unwrap().elements;
|
||||
for node in elements {
|
||||
self.format_signature(w, &node, 1)?;
|
||||
if let Some(js_doc) = &node.js_doc {
|
||||
self.format_jsdoc(w, js_doc, 2, false)?;
|
||||
}
|
||||
}
|
||||
writeln!(w)
|
||||
}
|
||||
|
||||
fn format_class_signature(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
indent: i64,
|
||||
) -> FmtResult {
|
||||
let class_def = node.class_def.as_ref().unwrap();
|
||||
write!(
|
||||
w,
|
||||
"{}{}{} {}",
|
||||
Indent(indent),
|
||||
display_abstract(class_def.is_abstract),
|
||||
colors::magenta("class"),
|
||||
colors::bold(&node.name),
|
||||
extends_suffix,
|
||||
implements_suffix,
|
||||
),
|
||||
indent,
|
||||
)
|
||||
}
|
||||
)?;
|
||||
if !class_def.type_params.is_empty() {
|
||||
write!(
|
||||
w,
|
||||
"<{}>",
|
||||
SliceDisplayer::new(&class_def.type_params, ", ", false)
|
||||
)?;
|
||||
}
|
||||
|
||||
fn format_variable_signature(node: &doc::DocNode, indent: i64) -> String {
|
||||
let variable_def = node.variable_def.clone().unwrap();
|
||||
add_indent(
|
||||
format!(
|
||||
"{} {}{}\n",
|
||||
if let Some(extends) = &class_def.extends {
|
||||
write!(w, " {} {}", colors::magenta("extends"), extends)?;
|
||||
}
|
||||
if !class_def.super_type_params.is_empty() {
|
||||
write!(
|
||||
w,
|
||||
"<{}>",
|
||||
SliceDisplayer::new(&class_def.super_type_params, ", ", false)
|
||||
)?;
|
||||
}
|
||||
|
||||
if !class_def.implements.is_empty() {
|
||||
write!(
|
||||
w,
|
||||
" {} {}",
|
||||
colors::magenta("implements"),
|
||||
SliceDisplayer::new(&class_def.implements, ", ", false)
|
||||
)?;
|
||||
}
|
||||
|
||||
writeln!(w)
|
||||
}
|
||||
|
||||
fn format_enum_signature(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
indent: i64,
|
||||
) -> FmtResult {
|
||||
writeln!(
|
||||
w,
|
||||
"{}{} {}",
|
||||
Indent(indent),
|
||||
colors::magenta("enum"),
|
||||
colors::bold(&node.name)
|
||||
)
|
||||
}
|
||||
|
||||
fn format_function_signature(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
indent: i64,
|
||||
) -> FmtResult {
|
||||
let function_def = node.function_def.as_ref().unwrap();
|
||||
write!(
|
||||
w,
|
||||
"{}{}{}{} {}",
|
||||
Indent(indent),
|
||||
display_async(function_def.is_async),
|
||||
colors::magenta("function"),
|
||||
display_generator(function_def.is_generator),
|
||||
colors::bold(&node.name)
|
||||
)?;
|
||||
if !function_def.type_params.is_empty() {
|
||||
write!(
|
||||
w,
|
||||
"<{}>",
|
||||
SliceDisplayer::new(&function_def.type_params, ", ", false)
|
||||
)?;
|
||||
}
|
||||
write!(
|
||||
w,
|
||||
"({})",
|
||||
SliceDisplayer::new(&function_def.params, ", ", false)
|
||||
)?;
|
||||
if let Some(return_type) = &function_def.return_type {
|
||||
write!(w, ": {}", return_type)?;
|
||||
}
|
||||
writeln!(w)
|
||||
}
|
||||
|
||||
fn format_interface_signature(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
indent: i64,
|
||||
) -> FmtResult {
|
||||
let interface_def = node.interface_def.as_ref().unwrap();
|
||||
write!(
|
||||
w,
|
||||
"{}{} {}",
|
||||
Indent(indent),
|
||||
colors::magenta("interface"),
|
||||
colors::bold(&node.name)
|
||||
)?;
|
||||
|
||||
if !interface_def.type_params.is_empty() {
|
||||
write!(
|
||||
w,
|
||||
"<{}>",
|
||||
SliceDisplayer::new(&interface_def.type_params, ", ", false)
|
||||
)?;
|
||||
}
|
||||
|
||||
if !interface_def.extends.is_empty() {
|
||||
write!(
|
||||
w,
|
||||
" {} {}",
|
||||
colors::magenta("extends"),
|
||||
SliceDisplayer::new(&interface_def.extends, ", ", false)
|
||||
)?;
|
||||
}
|
||||
|
||||
writeln!(w)
|
||||
}
|
||||
|
||||
fn format_type_alias_signature(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
indent: i64,
|
||||
) -> FmtResult {
|
||||
let type_alias_def = node.type_alias_def.as_ref().unwrap();
|
||||
write!(
|
||||
w,
|
||||
"{}{} {}",
|
||||
Indent(indent),
|
||||
colors::magenta("type"),
|
||||
colors::bold(&node.name),
|
||||
)?;
|
||||
|
||||
if !type_alias_def.type_params.is_empty() {
|
||||
write!(
|
||||
w,
|
||||
"<{}>",
|
||||
SliceDisplayer::new(&type_alias_def.type_params, ", ", false)
|
||||
)?;
|
||||
}
|
||||
|
||||
writeln!(w, " = {}", type_alias_def.ts_type)
|
||||
}
|
||||
|
||||
fn format_namespace_signature(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
indent: i64,
|
||||
) -> FmtResult {
|
||||
writeln!(
|
||||
w,
|
||||
"{}{} {}",
|
||||
Indent(indent),
|
||||
colors::magenta("namespace"),
|
||||
colors::bold(&node.name)
|
||||
)
|
||||
}
|
||||
|
||||
fn format_variable_signature(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
indent: i64,
|
||||
) -> FmtResult {
|
||||
let variable_def = node.variable_def.as_ref().unwrap();
|
||||
write!(
|
||||
w,
|
||||
"{}{} {}",
|
||||
Indent(indent),
|
||||
colors::magenta(match variable_def.kind {
|
||||
swc_ecma_ast::VarDeclKind::Const => "const",
|
||||
swc_ecma_ast::VarDeclKind::Let => "let",
|
||||
swc_ecma_ast::VarDeclKind::Var => "var",
|
||||
}),
|
||||
colors::bold(&node.name),
|
||||
if let Some(ts_type) = variable_def.ts_type {
|
||||
format!(": {}", render_ts_type(ts_type))
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
),
|
||||
indent,
|
||||
)
|
||||
)?;
|
||||
if let Some(ts_type) = &variable_def.ts_type {
|
||||
write!(w, ": {}", ts_type)?;
|
||||
}
|
||||
writeln!(w)
|
||||
}
|
||||
}
|
||||
|
||||
fn format_enum_signature(node: &doc::DocNode, indent: i64) -> String {
|
||||
add_indent(
|
||||
format!("{} {}\n", colors::magenta("enum"), colors::bold(&node.name)),
|
||||
indent,
|
||||
)
|
||||
}
|
||||
|
||||
fn format_interface_signature(node: &doc::DocNode, indent: i64) -> String {
|
||||
let interface_def = node.interface_def.clone().unwrap();
|
||||
let extends = &interface_def.extends;
|
||||
let extends_suffix = if !extends.is_empty() {
|
||||
format!(
|
||||
" {} {}",
|
||||
colors::magenta("extends"),
|
||||
colors::bold(&extends.join(", "))
|
||||
)
|
||||
} else {
|
||||
String::from("")
|
||||
};
|
||||
add_indent(
|
||||
format!(
|
||||
"{} {}{}\n",
|
||||
colors::magenta("interface"),
|
||||
colors::bold(&node.name),
|
||||
extends_suffix
|
||||
),
|
||||
indent,
|
||||
)
|
||||
}
|
||||
|
||||
fn format_type_alias_signature(node: &doc::DocNode, indent: i64) -> String {
|
||||
add_indent(
|
||||
format!("{} {}\n", colors::magenta("type"), colors::bold(&node.name)),
|
||||
indent,
|
||||
)
|
||||
}
|
||||
|
||||
fn format_namespace_signature(node: &doc::DocNode, indent: i64) -> String {
|
||||
add_indent(
|
||||
format!(
|
||||
"{} {}\n",
|
||||
colors::magenta("namespace"),
|
||||
colors::bold(&node.name)
|
||||
),
|
||||
indent,
|
||||
)
|
||||
impl<'a> Display for DocPrinter<'a> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
||||
|
|
2605
cli/doc/tests.rs
2605
cli/doc/tests.rs
File diff suppressed because it is too large
Load diff
|
@ -1,30 +1,23 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
use super::display::{display_readonly, SliceDisplayer};
|
||||
use super::interface::expr_to_name;
|
||||
use super::params::ts_fn_param_to_param_def;
|
||||
use super::ts_type_param::maybe_type_param_decl_to_type_param_defs;
|
||||
use super::ts_type_param::TsTypeParamDef;
|
||||
use super::ParamDef;
|
||||
use crate::colors;
|
||||
use crate::doc;
|
||||
use crate::swc_ecma_ast;
|
||||
use crate::swc_ecma_ast::TsArrayType;
|
||||
use crate::swc_ecma_ast::TsConditionalType;
|
||||
use crate::swc_ecma_ast::TsFnOrConstructorType;
|
||||
use crate::swc_ecma_ast::TsIndexedAccessType;
|
||||
use crate::swc_ecma_ast::TsKeywordType;
|
||||
use crate::swc_ecma_ast::TsLit;
|
||||
use crate::swc_ecma_ast::TsLitType;
|
||||
use crate::swc_ecma_ast::TsOptionalType;
|
||||
use crate::swc_ecma_ast::TsParenthesizedType;
|
||||
use crate::swc_ecma_ast::TsRestType;
|
||||
use crate::swc_ecma_ast::TsThisType;
|
||||
use crate::swc_ecma_ast::TsTupleType;
|
||||
use crate::swc_ecma_ast::TsType;
|
||||
use crate::swc_ecma_ast::TsTypeAnn;
|
||||
use crate::swc_ecma_ast::TsTypeLit;
|
||||
use crate::swc_ecma_ast::TsTypeOperator;
|
||||
use crate::swc_ecma_ast::TsTypeQuery;
|
||||
use crate::swc_ecma_ast::TsTypeRef;
|
||||
use crate::swc_ecma_ast::TsUnionOrIntersectionType;
|
||||
use crate::swc_ecma_ast::{
|
||||
TsArrayType, TsConditionalType, TsExprWithTypeArgs, TsFnOrConstructorType,
|
||||
TsIndexedAccessType, TsKeywordType, TsLit, TsLitType, TsOptionalType,
|
||||
TsParenthesizedType, TsRestType, TsThisType, TsTupleType, TsType, TsTypeAnn,
|
||||
TsTypeLit, TsTypeOperator, TsTypeParamInstantiation, TsTypeQuery, TsTypeRef,
|
||||
TsUnionOrIntersectionType,
|
||||
};
|
||||
use serde::Serialize;
|
||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||
|
||||
// pub enum TsType {
|
||||
// * TsKeywordType(TsKeywordType),
|
||||
// * TsThisType(TsThisType),
|
||||
|
@ -316,7 +309,37 @@ impl Into<TsTypeDef> for &TsTypeRef {
|
|||
};
|
||||
|
||||
TsTypeDef {
|
||||
repr: type_name.to_string(),
|
||||
repr: type_name.clone(),
|
||||
type_ref: Some(TsTypeRefDef {
|
||||
type_name,
|
||||
type_params,
|
||||
}),
|
||||
kind: Some(TsTypeDefKind::TypeRef),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<TsTypeDef> for &TsExprWithTypeArgs {
|
||||
fn into(self) -> TsTypeDef {
|
||||
let type_name = ts_entity_name_to_name(&self.expr);
|
||||
|
||||
let type_params = if let Some(type_params_inst) = &self.type_args {
|
||||
let mut ts_type_defs = vec![];
|
||||
|
||||
for type_box in &type_params_inst.params {
|
||||
let ts_type: &TsType = &(*type_box);
|
||||
let def: TsTypeDef = ts_type.into();
|
||||
ts_type_defs.push(def);
|
||||
}
|
||||
|
||||
Some(ts_type_defs)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
TsTypeDef {
|
||||
repr: type_name.clone(),
|
||||
type_ref: Some(TsTypeRefDef {
|
||||
type_name,
|
||||
type_params,
|
||||
|
@ -348,6 +371,7 @@ impl Into<TsTypeDef> for &TsTypeLit {
|
|||
let mut methods = vec![];
|
||||
let mut properties = vec![];
|
||||
let mut call_signatures = vec![];
|
||||
let mut index_signatures = vec![];
|
||||
|
||||
for type_element in &self.members {
|
||||
use crate::swc_ecma_ast::TsTypeElement::*;
|
||||
|
@ -357,7 +381,7 @@ impl Into<TsTypeDef> for &TsTypeLit {
|
|||
let mut params = vec![];
|
||||
|
||||
for param in &ts_method_sig.params {
|
||||
let param_def = ts_fn_param_to_param_def(param);
|
||||
let param_def = ts_fn_param_to_param_def(param, None);
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
|
@ -384,7 +408,7 @@ impl Into<TsTypeDef> for &TsTypeLit {
|
|||
let mut params = vec![];
|
||||
|
||||
for param in &ts_prop_sig.params {
|
||||
let param_def = ts_fn_param_to_param_def(param);
|
||||
let param_def = ts_fn_param_to_param_def(param, None);
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
|
@ -409,7 +433,7 @@ impl Into<TsTypeDef> for &TsTypeLit {
|
|||
TsCallSignatureDecl(ts_call_sig) => {
|
||||
let mut params = vec![];
|
||||
for param in &ts_call_sig.params {
|
||||
let param_def = ts_fn_param_to_param_def(param);
|
||||
let param_def = ts_fn_param_to_param_def(param, None);
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
|
@ -429,9 +453,27 @@ impl Into<TsTypeDef> for &TsTypeLit {
|
|||
};
|
||||
call_signatures.push(call_sig_def);
|
||||
}
|
||||
TsIndexSignature(ts_index_sig) => {
|
||||
let mut params = vec![];
|
||||
for param in &ts_index_sig.params {
|
||||
let param_def = ts_fn_param_to_param_def(param, None);
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
let ts_type = ts_index_sig
|
||||
.type_ann
|
||||
.as_ref()
|
||||
.map(|rt| (&*rt.type_ann).into());
|
||||
|
||||
let index_sig_def = LiteralIndexSignatureDef {
|
||||
readonly: ts_index_sig.readonly,
|
||||
params,
|
||||
ts_type,
|
||||
};
|
||||
index_signatures.push(index_sig_def);
|
||||
}
|
||||
// TODO:
|
||||
TsConstructSignatureDecl(_) => {}
|
||||
TsIndexSignature(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -439,6 +481,7 @@ impl Into<TsTypeDef> for &TsTypeLit {
|
|||
methods,
|
||||
properties,
|
||||
call_signatures,
|
||||
index_signatures,
|
||||
};
|
||||
|
||||
TsTypeDef {
|
||||
|
@ -475,7 +518,7 @@ impl Into<TsTypeDef> for &TsFnOrConstructorType {
|
|||
let mut params = vec![];
|
||||
|
||||
for param in &ts_fn_type.params {
|
||||
let param_def = ts_fn_param_to_param_def(param);
|
||||
let param_def = ts_fn_param_to_param_def(param, None);
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
|
@ -494,7 +537,7 @@ impl Into<TsTypeDef> for &TsFnOrConstructorType {
|
|||
let mut params = vec![];
|
||||
|
||||
for param in &ctor_type.params {
|
||||
let param_def = ts_fn_param_to_param_def(param);
|
||||
let param_def = ts_fn_param_to_param_def(param, None);
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
|
@ -619,6 +662,21 @@ pub struct LiteralMethodDef {
|
|||
pub type_params: Vec<TsTypeParamDef>,
|
||||
}
|
||||
|
||||
impl Display for LiteralMethodDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(
|
||||
f,
|
||||
"{}({})",
|
||||
self.name,
|
||||
SliceDisplayer::new(&self.params, ", ", false)
|
||||
)?;
|
||||
if let Some(return_type) = &self.return_type {
|
||||
write!(f, ": {}", return_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LiteralPropertyDef {
|
||||
|
@ -630,6 +688,15 @@ pub struct LiteralPropertyDef {
|
|||
pub type_params: Vec<TsTypeParamDef>,
|
||||
}
|
||||
|
||||
impl Display for LiteralPropertyDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(f, "{}", self.name)?;
|
||||
if let Some(ts_type) = &self.ts_type {
|
||||
write!(f, ": {}", ts_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LiteralCallSignatureDef {
|
||||
|
@ -638,12 +705,46 @@ pub struct LiteralCallSignatureDef {
|
|||
pub type_params: Vec<TsTypeParamDef>,
|
||||
}
|
||||
|
||||
impl Display for LiteralCallSignatureDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(f, "({})", SliceDisplayer::new(&self.params, ", ", false))?;
|
||||
if let Some(ts_type) = &self.ts_type {
|
||||
write!(f, ": {}", ts_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LiteralIndexSignatureDef {
|
||||
pub readonly: bool,
|
||||
pub params: Vec<ParamDef>,
|
||||
pub ts_type: Option<TsTypeDef>,
|
||||
}
|
||||
|
||||
impl Display for LiteralIndexSignatureDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(
|
||||
f,
|
||||
"{}[{}]",
|
||||
display_readonly(self.readonly),
|
||||
SliceDisplayer::new(&self.params, ", ", false)
|
||||
)?;
|
||||
if let Some(ts_type) = &self.ts_type {
|
||||
write!(f, ": {}", ts_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TsTypeLiteralDef {
|
||||
pub methods: Vec<LiteralMethodDef>,
|
||||
pub properties: Vec<LiteralPropertyDef>,
|
||||
pub call_signatures: Vec<LiteralCallSignatureDef>,
|
||||
pub index_signatures: Vec<LiteralIndexSignatureDef>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Clone)]
|
||||
|
@ -753,3 +854,133 @@ pub fn ts_type_ann_to_def(type_ann: &TsTypeAnn) -> TsTypeDef {
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for TsTypeDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
if self.kind.is_none() {
|
||||
return write!(f, "{}", colors::red("<UNIMPLEMENTED>"));
|
||||
}
|
||||
|
||||
let kind = self.kind.as_ref().unwrap();
|
||||
match kind {
|
||||
TsTypeDefKind::Array => write!(f, "{}[]", &*self.array.as_ref().unwrap()),
|
||||
TsTypeDefKind::Conditional => {
|
||||
let conditional = self.conditional_type.as_ref().unwrap();
|
||||
write!(
|
||||
f,
|
||||
"{} {} {} ? {} : {}",
|
||||
&*conditional.check_type,
|
||||
colors::magenta("extends"),
|
||||
&*conditional.extends_type,
|
||||
&*conditional.true_type,
|
||||
&*conditional.false_type
|
||||
)
|
||||
}
|
||||
TsTypeDefKind::FnOrConstructor => {
|
||||
let fn_or_constructor = self.fn_or_constructor.as_ref().unwrap();
|
||||
write!(
|
||||
f,
|
||||
"{}({}) => {}",
|
||||
colors::magenta(if fn_or_constructor.constructor {
|
||||
"new "
|
||||
} else {
|
||||
""
|
||||
}),
|
||||
SliceDisplayer::new(&fn_or_constructor.params, ", ", false),
|
||||
&fn_or_constructor.ts_type,
|
||||
)
|
||||
}
|
||||
TsTypeDefKind::IndexedAccess => {
|
||||
let indexed_access = self.indexed_access.as_ref().unwrap();
|
||||
write!(
|
||||
f,
|
||||
"{}[{}]",
|
||||
&*indexed_access.obj_type, &*indexed_access.index_type
|
||||
)
|
||||
}
|
||||
TsTypeDefKind::Intersection => {
|
||||
let intersection = self.intersection.as_ref().unwrap();
|
||||
write!(f, "{}", SliceDisplayer::new(&intersection, " & ", false))
|
||||
}
|
||||
TsTypeDefKind::Keyword => {
|
||||
write!(f, "{}", colors::cyan(self.keyword.as_ref().unwrap()))
|
||||
}
|
||||
TsTypeDefKind::Literal => {
|
||||
let literal = self.literal.as_ref().unwrap();
|
||||
match literal.kind {
|
||||
doc::ts_type::LiteralDefKind::Boolean => write!(
|
||||
f,
|
||||
"{}",
|
||||
colors::yellow(&literal.boolean.unwrap().to_string())
|
||||
),
|
||||
doc::ts_type::LiteralDefKind::String => write!(
|
||||
f,
|
||||
"{}",
|
||||
colors::green(&format!("\"{}\"", literal.string.as_ref().unwrap()))
|
||||
),
|
||||
doc::ts_type::LiteralDefKind::Number => write!(
|
||||
f,
|
||||
"{}",
|
||||
colors::yellow(&literal.number.unwrap().to_string())
|
||||
),
|
||||
}
|
||||
}
|
||||
TsTypeDefKind::Optional => {
|
||||
write!(f, "{}?", &*self.optional.as_ref().unwrap())
|
||||
}
|
||||
TsTypeDefKind::Parenthesized => {
|
||||
write!(f, "({})", &*self.parenthesized.as_ref().unwrap())
|
||||
}
|
||||
TsTypeDefKind::Rest => write!(f, "...{}", &*self.rest.as_ref().unwrap()),
|
||||
TsTypeDefKind::This => write!(f, "this"),
|
||||
TsTypeDefKind::Tuple => {
|
||||
let tuple = self.tuple.as_ref().unwrap();
|
||||
write!(f, "[{}]", SliceDisplayer::new(&tuple, ", ", false))
|
||||
}
|
||||
TsTypeDefKind::TypeLiteral => {
|
||||
let type_literal = self.type_literal.as_ref().unwrap();
|
||||
write!(
|
||||
f,
|
||||
"{{ {}{}{}{}}}",
|
||||
SliceDisplayer::new(&type_literal.call_signatures, "; ", true),
|
||||
SliceDisplayer::new(&type_literal.methods, "; ", true),
|
||||
SliceDisplayer::new(&type_literal.properties, "; ", true),
|
||||
SliceDisplayer::new(&type_literal.index_signatures, "; ", true),
|
||||
)
|
||||
}
|
||||
TsTypeDefKind::TypeOperator => {
|
||||
let operator = self.type_operator.as_ref().unwrap();
|
||||
write!(f, "{} {}", operator.operator, &operator.ts_type)
|
||||
}
|
||||
TsTypeDefKind::TypeQuery => {
|
||||
write!(f, "typeof {}", self.type_query.as_ref().unwrap())
|
||||
}
|
||||
TsTypeDefKind::TypeRef => {
|
||||
let type_ref = self.type_ref.as_ref().unwrap();
|
||||
write!(f, "{}", colors::intense_blue(&type_ref.type_name))?;
|
||||
if let Some(type_params) = &type_ref.type_params {
|
||||
write!(f, "<{}>", SliceDisplayer::new(type_params, ", ", false))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
TsTypeDefKind::Union => {
|
||||
let union = self.union.as_ref().unwrap();
|
||||
write!(f, "{}", SliceDisplayer::new(union, " | ", false))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maybe_type_param_instantiation_to_type_defs(
|
||||
maybe_type_param_instantiation: Option<&TsTypeParamInstantiation>,
|
||||
) -> Vec<TsTypeDef> {
|
||||
if let Some(type_param_instantiation) = maybe_type_param_instantiation {
|
||||
type_param_instantiation
|
||||
.params
|
||||
.iter()
|
||||
.map(|type_param| type_param.as_ref().into())
|
||||
.collect::<Vec<TsTypeDef>>()
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ use super::ts_type::TsTypeDef;
|
|||
use crate::swc_ecma_ast::TsTypeParam;
|
||||
use crate::swc_ecma_ast::TsTypeParamDecl;
|
||||
use serde::Serialize;
|
||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
@ -16,6 +17,19 @@ pub struct TsTypeParamDef {
|
|||
pub default: Option<TsTypeDef>,
|
||||
}
|
||||
|
||||
impl Display for TsTypeParamDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(f, "{}", self.name)?;
|
||||
if let Some(constraint) = &self.constraint {
|
||||
write!(f, " extends {}", constraint)?;
|
||||
}
|
||||
if let Some(default) = &self.default {
|
||||
write!(f, " = {}", default)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<TsTypeParamDef> for &TsTypeParam {
|
||||
fn into(self) -> TsTypeParamDef {
|
||||
let name = self.name.sym.to_string();
|
||||
|
|
35
cli/flags.rs
35
cli/flags.rs
|
@ -23,6 +23,7 @@ pub enum DenoSubcommand {
|
|||
buf: Box<[u8]>,
|
||||
},
|
||||
Doc {
|
||||
private: bool,
|
||||
json: bool,
|
||||
source_file: Option<String>,
|
||||
filter: Option<String>,
|
||||
|
@ -598,12 +599,14 @@ fn doc_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
|
|||
unstable_arg_parse(flags, matches);
|
||||
|
||||
let source_file = matches.value_of("source_file").map(String::from);
|
||||
let private = matches.is_present("private");
|
||||
let json = matches.is_present("json");
|
||||
let filter = matches.value_of("filter").map(String::from);
|
||||
flags.subcommand = DenoSubcommand::Doc {
|
||||
source_file,
|
||||
json,
|
||||
filter,
|
||||
private,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -915,6 +918,9 @@ fn doc_subcommand<'a, 'b>() -> App<'a, 'b> {
|
|||
Output documentation to standard output:
|
||||
deno doc ./path/to/module.ts
|
||||
|
||||
Output private documentation to standard output:
|
||||
deno doc --private ./path/to/module.ts
|
||||
|
||||
Output documentation in JSON format:
|
||||
deno doc --json ./path/to/module.ts
|
||||
|
||||
|
@ -932,6 +938,12 @@ Show documentation for runtime built-ins:
|
|||
.help("Output documentation in JSON format.")
|
||||
.takes_value(false),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("private")
|
||||
.long("private")
|
||||
.help("Output private documentation")
|
||||
.takes_value(false),
|
||||
)
|
||||
// TODO(nayeemrmn): Make `--builtin` a proper option. Blocked by
|
||||
// https://github.com/clap-rs/clap/issues/1794. Currently `--builtin` is
|
||||
// just a possible value of `source_file` so leading hyphens must be
|
||||
|
@ -2910,6 +2922,7 @@ mod tests {
|
|||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Doc {
|
||||
private: false,
|
||||
json: true,
|
||||
source_file: Some("path/to/module.ts".to_string()),
|
||||
filter: None,
|
||||
|
@ -2928,6 +2941,7 @@ mod tests {
|
|||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Doc {
|
||||
private: false,
|
||||
json: false,
|
||||
source_file: Some("path/to/module.ts".to_string()),
|
||||
filter: Some("SomeClass.someField".to_string()),
|
||||
|
@ -2941,6 +2955,7 @@ mod tests {
|
|||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Doc {
|
||||
private: false,
|
||||
json: false,
|
||||
source_file: None,
|
||||
filter: None,
|
||||
|
@ -2955,6 +2970,7 @@ mod tests {
|
|||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Doc {
|
||||
private: false,
|
||||
json: false,
|
||||
source_file: Some("--builtin".to_string()),
|
||||
filter: Some("Deno.Listener".to_string()),
|
||||
|
@ -2962,6 +2978,25 @@ mod tests {
|
|||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
||||
let r = flags_from_vec_safe(svec![
|
||||
"deno",
|
||||
"doc",
|
||||
"--private",
|
||||
"path/to/module.js"
|
||||
]);
|
||||
assert_eq!(
|
||||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Doc {
|
||||
private: true,
|
||||
json: false,
|
||||
source_file: Some("path/to/module.js".to_string()),
|
||||
filter: None,
|
||||
},
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
14
cli/main.rs
14
cli/main.rs
|
@ -521,6 +521,7 @@ async fn doc_command(
|
|||
source_file: Option<String>,
|
||||
json: bool,
|
||||
maybe_filter: Option<String>,
|
||||
private: bool,
|
||||
) -> Result<(), ErrBox> {
|
||||
let global_state = GlobalState::new(flags.clone())?;
|
||||
let source_file = source_file.unwrap_or_else(|| "--builtin".to_string());
|
||||
|
@ -546,7 +547,7 @@ async fn doc_command(
|
|||
}
|
||||
|
||||
let loader = Box::new(global_state.file_fetcher.clone());
|
||||
let doc_parser = doc::DocParser::new(loader);
|
||||
let doc_parser = doc::DocParser::new(loader, private);
|
||||
|
||||
let parse_result = if source_file == "--builtin" {
|
||||
doc_parser.parse_source("lib.deno.d.ts", get_types(flags.unstable).as_str())
|
||||
|
@ -576,13 +577,9 @@ async fn doc_command(
|
|||
eprintln!("Node {} was not found!", filter);
|
||||
std::process::exit(1);
|
||||
}
|
||||
let mut details = String::new();
|
||||
for node in nodes {
|
||||
details.push_str(doc::printer::format_details(node).as_str());
|
||||
}
|
||||
details
|
||||
format!("{}", doc::DocPrinter::new(&nodes, true, private))
|
||||
} else {
|
||||
doc::printer::format(doc_nodes)
|
||||
format!("{}", doc::DocPrinter::new(&doc_nodes, false, private))
|
||||
};
|
||||
|
||||
write_to_stdout_ignore_sigpipe(details.as_bytes()).map_err(ErrBox::from)
|
||||
|
@ -720,7 +717,8 @@ pub fn main() {
|
|||
source_file,
|
||||
json,
|
||||
filter,
|
||||
} => doc_command(flags, source_file, json, filter).boxed_local(),
|
||||
private,
|
||||
} => doc_command(flags, source_file, json, filter, private).boxed_local(),
|
||||
DenoSubcommand::Eval {
|
||||
print,
|
||||
code,
|
||||
|
|
Loading…
Reference in a new issue