mirror of
https://github.com/denoland/deno.git
synced 2025-01-21 21:50:00 -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::env;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::Write;
|
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};
|
use termcolor::{Ansi, ColorSpec, WriteColor};
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
@ -54,7 +54,10 @@ pub fn red_bold(s: &str) -> impl fmt::Display {
|
||||||
|
|
||||||
pub fn green_bold(s: &str) -> impl fmt::Display {
|
pub fn green_bold(s: &str) -> impl fmt::Display {
|
||||||
let mut style_spec = ColorSpec::new();
|
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)
|
style(&s, style_spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +105,7 @@ pub fn red(s: &str) -> impl fmt::Display {
|
||||||
|
|
||||||
pub fn green(s: &str) -> impl fmt::Display {
|
pub fn green(s: &str) -> impl fmt::Display {
|
||||||
let mut style_spec = ColorSpec::new();
|
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)
|
style(&s, style_spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,6 +127,12 @@ pub fn gray(s: &str) -> impl fmt::Display {
|
||||||
style(&s, style_spec)
|
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 {
|
pub fn italic_bold_gray(s: &str) -> impl fmt::Display {
|
||||||
let mut style_spec = ColorSpec::new();
|
let mut style_spec = ColorSpec::new();
|
||||||
style_spec
|
style_spec
|
||||||
|
@ -132,3 +141,9 @@ pub fn italic_bold_gray(s: &str) -> impl fmt::Display {
|
||||||
.set_italic(true);
|
.set_italic(true);
|
||||||
style(&s, style_spec)
|
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.
|
// 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_common::Spanned;
|
||||||
use crate::swc_ecma_ast;
|
use crate::swc_ecma_ast;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
@ -7,18 +12,21 @@ use serde::Serialize;
|
||||||
use super::function::function_to_function_def;
|
use super::function::function_to_function_def;
|
||||||
use super::function::FunctionDef;
|
use super::function::FunctionDef;
|
||||||
use super::interface::expr_to_name;
|
use super::interface::expr_to_name;
|
||||||
use super::params::assign_pat_to_param_def;
|
use super::params::{
|
||||||
use super::params::ident_to_param_def;
|
assign_pat_to_param_def, ident_to_param_def, pat_to_param_def,
|
||||||
use super::params::pat_to_param_def;
|
prop_name_to_string, ts_fn_param_to_param_def,
|
||||||
|
};
|
||||||
use super::parser::DocParser;
|
use super::parser::DocParser;
|
||||||
use super::ts_type::ts_entity_name_to_name;
|
use super::ts_type::{
|
||||||
use super::ts_type::ts_type_ann_to_def;
|
maybe_type_param_instantiation_to_type_defs, ts_type_ann_to_def, TsTypeDef,
|
||||||
use super::ts_type::TsTypeDef;
|
};
|
||||||
use super::ts_type_param::maybe_type_param_decl_to_type_param_defs;
|
use super::ts_type_param::maybe_type_param_decl_to_type_param_defs;
|
||||||
use super::ts_type_param::TsTypeParamDef;
|
use super::ts_type_param::TsTypeParamDef;
|
||||||
use super::Location;
|
use super::Location;
|
||||||
use super::ParamDef;
|
use super::ParamDef;
|
||||||
|
|
||||||
|
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Clone)]
|
#[derive(Debug, Serialize, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ClassConstructorDef {
|
pub struct ClassConstructorDef {
|
||||||
|
@ -29,6 +37,18 @@ pub struct ClassConstructorDef {
|
||||||
pub location: Location,
|
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)]
|
#[derive(Debug, Serialize, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ClassPropertyDef {
|
pub struct ClassPropertyDef {
|
||||||
|
@ -43,6 +63,48 @@ pub struct ClassPropertyDef {
|
||||||
pub location: Location,
|
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)]
|
#[derive(Debug, Serialize, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ClassMethodDef {
|
pub struct ClassMethodDef {
|
||||||
|
@ -57,32 +119,41 @@ pub struct ClassMethodDef {
|
||||||
pub location: Location,
|
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)]
|
#[derive(Debug, Serialize, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ClassDef {
|
pub struct ClassDef {
|
||||||
// TODO(bartlomieju): decorators, super_type_params
|
// TODO(bartlomieju): decorators
|
||||||
pub is_abstract: bool,
|
pub is_abstract: bool,
|
||||||
pub constructors: Vec<ClassConstructorDef>,
|
pub constructors: Vec<ClassConstructorDef>,
|
||||||
pub properties: Vec<ClassPropertyDef>,
|
pub properties: Vec<ClassPropertyDef>,
|
||||||
|
pub index_signatures: Vec<ClassIndexSignatureDef>,
|
||||||
pub methods: Vec<ClassMethodDef>,
|
pub methods: Vec<ClassMethodDef>,
|
||||||
pub extends: Option<String>,
|
pub extends: Option<String>,
|
||||||
pub implements: Vec<String>,
|
pub implements: Vec<TsTypeDef>,
|
||||||
pub type_params: Vec<TsTypeParamDef>,
|
pub type_params: Vec<TsTypeParamDef>,
|
||||||
}
|
pub super_type_params: Vec<TsTypeDef>,
|
||||||
|
|
||||||
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 fn class_to_class_def(
|
pub fn class_to_class_def(
|
||||||
|
@ -92,6 +163,7 @@ pub fn class_to_class_def(
|
||||||
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 mut index_signatures = vec![];
|
||||||
|
|
||||||
let extends: Option<String> = match &class.super_class {
|
let extends: Option<String> = match &class.super_class {
|
||||||
Some(boxed) => {
|
Some(boxed) => {
|
||||||
|
@ -105,11 +177,11 @@ pub fn class_to_class_def(
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let implements: Vec<String> = class
|
let implements = class
|
||||||
.implements
|
.implements
|
||||||
.iter()
|
.iter()
|
||||||
.map(|expr| ts_entity_name_to_name(&expr.expr))
|
.map(|expr| expr.into())
|
||||||
.collect();
|
.collect::<Vec<TsTypeDef>>();
|
||||||
|
|
||||||
for member in &class.body {
|
for member in &class.body {
|
||||||
use crate::swc_ecma_ast::ClassMember::*;
|
use crate::swc_ecma_ast::ClassMember::*;
|
||||||
|
@ -117,8 +189,10 @@ pub fn class_to_class_def(
|
||||||
match member {
|
match member {
|
||||||
Constructor(ctor) => {
|
Constructor(ctor) => {
|
||||||
let ctor_js_doc = doc_parser.js_doc_for_span(ctor.span());
|
let ctor_js_doc = doc_parser.js_doc_for_span(ctor.span());
|
||||||
let constructor_name =
|
let constructor_name = prop_name_to_string(
|
||||||
prop_name_to_string(&doc_parser.ast_parser.source_map, &ctor.key);
|
&ctor.key,
|
||||||
|
Some(&doc_parser.ast_parser.source_map),
|
||||||
|
);
|
||||||
|
|
||||||
let mut params = vec![];
|
let mut params = vec![];
|
||||||
|
|
||||||
|
@ -126,14 +200,23 @@ pub fn class_to_class_def(
|
||||||
use crate::swc_ecma_ast::ParamOrTsParamProp::*;
|
use crate::swc_ecma_ast::ParamOrTsParamProp::*;
|
||||||
|
|
||||||
let param_def = match param {
|
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) => {
|
TsParamProp(ts_param_prop) => {
|
||||||
use swc_ecma_ast::TsParamPropParam;
|
use swc_ecma_ast::TsParamPropParam;
|
||||||
|
|
||||||
match &ts_param_prop.param {
|
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) => {
|
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) => {
|
Method(class_method) => {
|
||||||
let method_js_doc = doc_parser.js_doc_for_span(class_method.span());
|
let method_js_doc = doc_parser.js_doc_for_span(class_method.span());
|
||||||
let method_name = prop_name_to_string(
|
let method_name = prop_name_to_string(
|
||||||
&doc_parser.ast_parser.source_map,
|
|
||||||
&class_method.key,
|
&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 {
|
let method_def = ClassMethodDef {
|
||||||
js_doc: method_js_doc,
|
js_doc: method_js_doc,
|
||||||
accessibility: class_method.accessibility,
|
accessibility: class_method.accessibility,
|
||||||
|
@ -199,8 +283,26 @@ pub fn class_to_class_def(
|
||||||
};
|
};
|
||||||
properties.push(prop_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):
|
// TODO(bartlomieju):
|
||||||
TsIndexSignature(_) => {}
|
|
||||||
PrivateMethod(_) => {}
|
PrivateMethod(_) => {}
|
||||||
PrivateProp(_) => {}
|
PrivateProp(_) => {}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -210,14 +312,20 @@ pub fn class_to_class_def(
|
||||||
let type_params =
|
let type_params =
|
||||||
maybe_type_param_decl_to_type_param_defs(class.type_params.as_ref());
|
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 {
|
ClassDef {
|
||||||
is_abstract: class.is_abstract,
|
is_abstract: class.is_abstract,
|
||||||
extends,
|
extends,
|
||||||
implements,
|
implements,
|
||||||
constructors,
|
constructors,
|
||||||
properties,
|
properties,
|
||||||
|
index_signatures,
|
||||||
methods,
|
methods,
|
||||||
type_params,
|
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.
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||||
use super::params::pat_to_param_def;
|
use super::params::pat_to_param_def;
|
||||||
|
use super::parser::DocParser;
|
||||||
use super::ts_type::ts_type_ann_to_def;
|
use super::ts_type::ts_type_ann_to_def;
|
||||||
use super::ts_type::TsTypeDef;
|
use super::ts_type::TsTypeDef;
|
||||||
use super::ts_type_param::maybe_type_param_decl_to_type_param_defs;
|
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(
|
pub fn function_to_function_def(
|
||||||
|
doc_parser: &DocParser,
|
||||||
function: &swc_ecma_ast::Function,
|
function: &swc_ecma_ast::Function,
|
||||||
) -> FunctionDef {
|
) -> FunctionDef {
|
||||||
let mut params = vec![];
|
let mut params = vec![];
|
||||||
|
|
||||||
for param in &function.params {
|
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);
|
params.push(param_def);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,9 +50,10 @@ pub fn function_to_function_def(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_doc_for_fn_decl(
|
pub fn get_doc_for_fn_decl(
|
||||||
|
doc_parser: &DocParser,
|
||||||
fn_decl: &swc_ecma_ast::FnDecl,
|
fn_decl: &swc_ecma_ast::FnDecl,
|
||||||
) -> (String, FunctionDef) {
|
) -> (String, FunctionDef) {
|
||||||
let name = fn_decl.ident.sym.to_string();
|
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)
|
(name, fn_def)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
// 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 crate::swc_ecma_ast;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::params::ts_fn_param_to_param_def;
|
use super::params::ts_fn_param_to_param_def;
|
||||||
use super::parser::DocParser;
|
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::ts_type_ann_to_def;
|
||||||
use super::ts_type::TsTypeDef;
|
use super::ts_type::TsTypeDef;
|
||||||
use super::ts_type_param::maybe_type_param_decl_to_type_param_defs;
|
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::Location;
|
||||||
use super::ParamDef;
|
use super::ParamDef;
|
||||||
|
|
||||||
|
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Clone)]
|
#[derive(Debug, Serialize, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct InterfaceMethodDef {
|
pub struct InterfaceMethodDef {
|
||||||
|
@ -24,6 +27,22 @@ pub struct InterfaceMethodDef {
|
||||||
pub type_params: Vec<TsTypeParamDef>,
|
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)]
|
#[derive(Debug, Serialize, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct InterfacePropertyDef {
|
pub struct InterfacePropertyDef {
|
||||||
|
@ -37,6 +56,44 @@ pub struct InterfacePropertyDef {
|
||||||
pub type_params: Vec<TsTypeParamDef>,
|
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)]
|
#[derive(Debug, Serialize, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct InterfaceCallSignatureDef {
|
pub struct InterfaceCallSignatureDef {
|
||||||
|
@ -50,10 +107,11 @@ pub struct InterfaceCallSignatureDef {
|
||||||
#[derive(Debug, Serialize, Clone)]
|
#[derive(Debug, Serialize, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct InterfaceDef {
|
pub struct InterfaceDef {
|
||||||
pub extends: Vec<String>,
|
pub extends: Vec<TsTypeDef>,
|
||||||
pub methods: Vec<InterfaceMethodDef>,
|
pub methods: Vec<InterfaceMethodDef>,
|
||||||
pub properties: Vec<InterfacePropertyDef>,
|
pub properties: Vec<InterfacePropertyDef>,
|
||||||
pub call_signatures: Vec<InterfaceCallSignatureDef>,
|
pub call_signatures: Vec<InterfaceCallSignatureDef>,
|
||||||
|
pub index_signatures: Vec<InterfaceIndexSignatureDef>,
|
||||||
pub type_params: Vec<TsTypeParamDef>,
|
pub type_params: Vec<TsTypeParamDef>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,6 +142,7 @@ pub fn get_doc_for_ts_interface_decl(
|
||||||
let mut methods = vec![];
|
let mut methods = vec![];
|
||||||
let mut properties = vec![];
|
let mut properties = vec![];
|
||||||
let mut call_signatures = vec![];
|
let mut call_signatures = vec![];
|
||||||
|
let mut index_signatures = vec![];
|
||||||
|
|
||||||
for type_element in &interface_decl.body.body {
|
for type_element in &interface_decl.body.body {
|
||||||
use crate::swc_ecma_ast::TsTypeElement::*;
|
use crate::swc_ecma_ast::TsTypeElement::*;
|
||||||
|
@ -95,7 +154,10 @@ pub fn get_doc_for_ts_interface_decl(
|
||||||
let mut params = vec![];
|
let mut params = vec![];
|
||||||
|
|
||||||
for param in &ts_method_sig.params {
|
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);
|
params.push(param_def);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +193,10 @@ pub fn get_doc_for_ts_interface_decl(
|
||||||
let mut params = vec![];
|
let mut params = vec![];
|
||||||
|
|
||||||
for param in &ts_prop_sig.params {
|
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);
|
params.push(param_def);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +229,10 @@ pub fn get_doc_for_ts_interface_decl(
|
||||||
|
|
||||||
let mut params = vec![];
|
let mut params = vec![];
|
||||||
for param in &ts_call_sig.params {
|
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);
|
params.push(param_def);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,9 +257,27 @@ pub fn get_doc_for_ts_interface_decl(
|
||||||
};
|
};
|
||||||
call_signatures.push(call_sig_def);
|
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:
|
// TODO:
|
||||||
TsConstructSignatureDecl(_) => {}
|
TsConstructSignatureDecl(_) => {}
|
||||||
TsIndexSignature(_) => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,17 +285,18 @@ pub fn get_doc_for_ts_interface_decl(
|
||||||
interface_decl.type_params.as_ref(),
|
interface_decl.type_params.as_ref(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let extends: Vec<String> = interface_decl
|
let extends = interface_decl
|
||||||
.extends
|
.extends
|
||||||
.iter()
|
.iter()
|
||||||
.map(|expr| ts_entity_name_to_name(&expr.expr))
|
.map(|expr| expr.into())
|
||||||
.collect();
|
.collect::<Vec<TsTypeDef>>();
|
||||||
|
|
||||||
let interface_def = InterfaceDef {
|
let interface_def = InterfaceDef {
|
||||||
extends,
|
extends,
|
||||||
methods,
|
methods,
|
||||||
properties,
|
properties,
|
||||||
call_signatures,
|
call_signatures,
|
||||||
|
index_signatures,
|
||||||
type_params,
|
type_params,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||||
pub mod class;
|
pub mod class;
|
||||||
|
mod display;
|
||||||
pub mod r#enum;
|
pub mod r#enum;
|
||||||
pub mod function;
|
pub mod function;
|
||||||
pub mod interface;
|
pub mod interface;
|
||||||
|
@ -17,9 +18,9 @@ pub mod variable;
|
||||||
pub use node::DocNode;
|
pub use node::DocNode;
|
||||||
pub use node::DocNodeKind;
|
pub use node::DocNodeKind;
|
||||||
pub use node::Location;
|
pub use node::Location;
|
||||||
pub use node::ParamDef;
|
pub use params::ParamDef;
|
||||||
pub use node::ParamKind;
|
|
||||||
pub use parser::DocParser;
|
pub use parser::DocParser;
|
||||||
|
pub use printer::DocPrinter;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
|
@ -35,7 +35,8 @@ pub fn get_doc_node_for_export_decl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Decl::Fn(fn_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 {
|
DocNode {
|
||||||
kind: DocNodeKind::Function,
|
kind: DocNodeKind::Function,
|
||||||
name,
|
name,
|
||||||
|
|
|
@ -14,24 +14,6 @@ pub enum DocNodeKind {
|
||||||
Namespace,
|
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)]
|
#[derive(Debug, Serialize, Clone, PartialEq)]
|
||||||
pub struct Location {
|
pub struct Location {
|
||||||
pub filename: String,
|
pub filename: String,
|
||||||
|
@ -82,7 +64,7 @@ pub struct Reexport {
|
||||||
#[derive(Debug, Serialize, Clone)]
|
#[derive(Debug, Serialize, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ModuleDoc {
|
pub struct ModuleDoc {
|
||||||
pub exports: Vec<DocNode>,
|
pub definitions: Vec<DocNode>,
|
||||||
pub reexports: Vec<Reexport>,
|
pub reexports: Vec<Reexport>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,58 +1,228 @@
|
||||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
// 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;
|
||||||
|
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;
|
#[derive(Debug, Serialize, Clone)]
|
||||||
use super::ParamDef;
|
#[serde(rename_all = "camelCase")]
|
||||||
use super::ParamKind;
|
#[serde(tag = "kind")]
|
||||||
use crate::swc_ecma_ast::Pat;
|
pub enum ParamDef {
|
||||||
use crate::swc_ecma_ast::TsFnParam;
|
#[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));
|
let ts_type = ident.type_ann.as_ref().map(|rt| ts_type_ann_to_def(rt));
|
||||||
|
|
||||||
ParamDef {
|
ParamDef::Identifier {
|
||||||
name: ident.sym.to_string(),
|
name: ident.sym.to_string(),
|
||||||
kind: ParamKind::Identifier,
|
|
||||||
optional: ident.optional,
|
optional: ident.optional,
|
||||||
ts_type,
|
ts_type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rest_pat_to_param_def(rest_pat: &swc_ecma_ast::RestPat) -> ParamDef {
|
fn rest_pat_to_param_def(
|
||||||
let name = match &*rest_pat.arg {
|
rest_pat: &swc_ecma_ast::RestPat,
|
||||||
Pat::Ident(ident) => ident.sym.to_string(),
|
source_map: Option<&SourceMap>,
|
||||||
_ => "<TODO>".to_string(),
|
) -> ParamDef {
|
||||||
};
|
|
||||||
let ts_type = rest_pat.type_ann.as_ref().map(|rt| ts_type_ann_to_def(rt));
|
let ts_type = rest_pat.type_ann.as_ref().map(|rt| ts_type_ann_to_def(rt));
|
||||||
|
|
||||||
ParamDef {
|
ParamDef::Rest {
|
||||||
name,
|
arg: Box::new(pat_to_param_def(&*rest_pat.arg, source_map)),
|
||||||
kind: ParamKind::Rest,
|
|
||||||
optional: false,
|
|
||||||
ts_type,
|
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
|
let ts_type = object_pat
|
||||||
.type_ann
|
.type_ann
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|rt| ts_type_ann_to_def(rt));
|
.map(|rt| ts_type_ann_to_def(rt));
|
||||||
|
|
||||||
ParamDef {
|
ParamDef::Object {
|
||||||
name: "".to_string(),
|
props,
|
||||||
kind: ParamKind::Object,
|
|
||||||
optional: object_pat.optional,
|
optional: object_pat.optional,
|
||||||
ts_type,
|
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));
|
let ts_type = array_pat.type_ann.as_ref().map(|rt| ts_type_ann_to_def(rt));
|
||||||
|
|
||||||
ParamDef {
|
ParamDef::Array {
|
||||||
name: "".to_string(),
|
elements,
|
||||||
kind: ParamKind::Array,
|
|
||||||
optional: array_pat.optional,
|
optional: array_pat.optional,
|
||||||
ts_type,
|
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(
|
pub fn assign_pat_to_param_def(
|
||||||
assign_pat: &swc_ecma_ast::AssignPat,
|
assign_pat: &swc_ecma_ast::AssignPat,
|
||||||
|
source_map: Option<&SourceMap>,
|
||||||
) -> ParamDef {
|
) -> 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 {
|
match pat {
|
||||||
Pat::Ident(ident) => ident_to_param_def(ident),
|
Pat::Ident(ident) => ident_to_param_def(ident, source_map),
|
||||||
Pat::Array(array_pat) => array_pat_to_param_def(array_pat),
|
Pat::Array(array_pat) => array_pat_to_param_def(array_pat, source_map),
|
||||||
Pat::Rest(rest_pat) => rest_pat_to_param_def(rest_pat),
|
Pat::Rest(rest_pat) => rest_pat_to_param_def(rest_pat, source_map),
|
||||||
Pat::Object(object_pat) => object_pat_to_param_def(object_pat),
|
Pat::Object(object_pat) => object_pat_to_param_def(object_pat, source_map),
|
||||||
Pat::Assign(assign_pat) => assign_pat_to_param_def(assign_pat),
|
Pat::Assign(assign_pat) => assign_pat_to_param_def(assign_pat, source_map),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ts_fn_param_to_param_def(
|
pub fn ts_fn_param_to_param_def(
|
||||||
ts_fn_param: &swc_ecma_ast::TsFnParam,
|
ts_fn_param: &swc_ecma_ast::TsFnParam,
|
||||||
|
source_map: Option<&SourceMap>,
|
||||||
) -> ParamDef {
|
) -> ParamDef {
|
||||||
match ts_fn_param {
|
match ts_fn_param {
|
||||||
TsFnParam::Ident(ident) => ident_to_param_def(ident),
|
TsFnParam::Ident(ident) => ident_to_param_def(ident, source_map),
|
||||||
TsFnParam::Array(array_pat) => array_pat_to_param_def(array_pat),
|
TsFnParam::Array(array_pat) => {
|
||||||
TsFnParam::Rest(rest_pat) => rest_pat_to_param_def(rest_pat),
|
array_pat_to_param_def(array_pat, source_map)
|
||||||
TsFnParam::Object(object_pat) => object_pat_to_param_def(object_pat),
|
}
|
||||||
|
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 struct DocParser {
|
||||||
pub ast_parser: AstParser,
|
pub ast_parser: AstParser,
|
||||||
pub loader: Box<dyn DocFileLoader>,
|
pub loader: Box<dyn DocFileLoader>,
|
||||||
|
pub private: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DocParser {
|
impl DocParser {
|
||||||
pub fn new(loader: Box<dyn DocFileLoader>) -> Self {
|
pub fn new(loader: Box<dyn DocFileLoader>, private: bool) -> Self {
|
||||||
DocParser {
|
DocParser {
|
||||||
loader,
|
loader,
|
||||||
ast_parser: AstParser::new(),
|
ast_parser: AstParser::new(),
|
||||||
|
private,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +72,7 @@ impl DocParser {
|
||||||
self.get_doc_nodes_for_module_body(module.body.clone());
|
self.get_doc_nodes_for_module_body(module.body.clone());
|
||||||
let reexports = self.get_reexports_for_module_body(module.body);
|
let reexports = self.get_reexports_for_module_body(module.body);
|
||||||
let module_doc = ModuleDoc {
|
let module_doc = ModuleDoc {
|
||||||
exports: doc_entries,
|
definitions: doc_entries,
|
||||||
reexports,
|
reexports,
|
||||||
};
|
};
|
||||||
Ok(module_doc)
|
Ok(module_doc)
|
||||||
|
@ -90,7 +92,7 @@ impl DocParser {
|
||||||
source_code: &str,
|
source_code: &str,
|
||||||
) -> Result<Vec<DocNode>, ErrBox> {
|
) -> Result<Vec<DocNode>, ErrBox> {
|
||||||
let module_doc = self.parse_module(file_name, &source_code)?;
|
let module_doc = self.parse_module(file_name, &source_code)?;
|
||||||
Ok(module_doc.exports)
|
Ok(module_doc.definitions)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn flatten_reexports(
|
async fn flatten_reexports(
|
||||||
|
@ -187,10 +189,10 @@ impl DocParser {
|
||||||
let mut flattenned_reexports = self
|
let mut flattenned_reexports = self
|
||||||
.flatten_reexports(&module_doc.reexports, file_name)
|
.flatten_reexports(&module_doc.reexports, file_name)
|
||||||
.await?;
|
.await?;
|
||||||
flattenned_reexports.extend(module_doc.exports);
|
flattenned_reexports.extend(module_doc.definitions);
|
||||||
flattenned_reexports
|
flattenned_reexports
|
||||||
} else {
|
} else {
|
||||||
module_doc.exports
|
module_doc.definitions
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(flattened_docs)
|
Ok(flattened_docs)
|
||||||
|
@ -231,8 +233,10 @@ impl DocParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DefaultDecl::Fn(fn_expr) => {
|
DefaultDecl::Fn(fn_expr) => {
|
||||||
let function_def =
|
let function_def = crate::doc::function::function_to_function_def(
|
||||||
crate::doc::function::function_to_function_def(&fn_expr.function);
|
self,
|
||||||
|
&fn_expr.function,
|
||||||
|
);
|
||||||
DocNode {
|
DocNode {
|
||||||
kind: DocNodeKind::Function,
|
kind: DocNodeKind::Function,
|
||||||
name,
|
name,
|
||||||
|
@ -292,7 +296,7 @@ impl DocParser {
|
||||||
pub fn get_doc_node_for_decl(&self, decl: &Decl) -> Option<DocNode> {
|
pub fn get_doc_node_for_decl(&self, decl: &Decl) -> Option<DocNode> {
|
||||||
match decl {
|
match decl {
|
||||||
Decl::Class(class_decl) => {
|
Decl::Class(class_decl) => {
|
||||||
if !class_decl.declare {
|
if !self.private && !class_decl.declare {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let (name, class_def) =
|
let (name, class_def) =
|
||||||
|
@ -313,11 +317,11 @@ impl DocParser {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Decl::Fn(fn_decl) => {
|
Decl::Fn(fn_decl) => {
|
||||||
if !fn_decl.declare {
|
if !self.private && !fn_decl.declare {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let (name, function_def) =
|
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);
|
let (js_doc, location) = self.details_for_span(fn_decl.function.span);
|
||||||
Some(DocNode {
|
Some(DocNode {
|
||||||
kind: DocNodeKind::Function,
|
kind: DocNodeKind::Function,
|
||||||
|
@ -334,7 +338,7 @@ impl DocParser {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Decl::Var(var_decl) => {
|
Decl::Var(var_decl) => {
|
||||||
if !var_decl.declare {
|
if !self.private && !var_decl.declare {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let (name, var_def) = super::variable::get_doc_for_var_decl(var_decl);
|
let (name, var_def) = super::variable::get_doc_for_var_decl(var_decl);
|
||||||
|
@ -354,7 +358,7 @@ impl DocParser {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Decl::TsInterface(ts_interface_decl) => {
|
Decl::TsInterface(ts_interface_decl) => {
|
||||||
if !ts_interface_decl.declare {
|
if !self.private && !ts_interface_decl.declare {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let (name, interface_def) =
|
let (name, interface_def) =
|
||||||
|
@ -378,7 +382,7 @@ impl DocParser {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Decl::TsTypeAlias(ts_type_alias) => {
|
Decl::TsTypeAlias(ts_type_alias) => {
|
||||||
if !ts_type_alias.declare {
|
if !self.private && !ts_type_alias.declare {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let (name, type_alias_def) =
|
let (name, type_alias_def) =
|
||||||
|
@ -402,7 +406,7 @@ impl DocParser {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Decl::TsEnum(ts_enum) => {
|
Decl::TsEnum(ts_enum) => {
|
||||||
if !ts_enum.declare {
|
if !self.private && !ts_enum.declare {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let (name, enum_def) =
|
let (name, enum_def) =
|
||||||
|
@ -423,7 +427,7 @@ impl DocParser {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Decl::TsModule(ts_module) => {
|
Decl::TsModule(ts_module) => {
|
||||||
if !ts_module.declare {
|
if !self.private && !ts_module.declare {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let (name, namespace_def) =
|
let (name, namespace_def) =
|
||||||
|
|
|
@ -12,48 +12,116 @@
|
||||||
|
|
||||||
use crate::colors;
|
use crate::colors;
|
||||||
use crate::doc;
|
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::doc::DocNodeKind;
|
||||||
use crate::swc_ecma_ast;
|
use crate::swc_ecma_ast;
|
||||||
|
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||||
|
|
||||||
pub fn format(doc_nodes: Vec<doc::DocNode>) -> String {
|
pub struct DocPrinter<'a> {
|
||||||
format_(doc_nodes, 0)
|
doc_nodes: &'a [doc::DocNode],
|
||||||
|
details: bool,
|
||||||
|
private: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format_details(node: doc::DocNode) -> String {
|
impl<'a> DocPrinter<'a> {
|
||||||
let mut details = String::new();
|
pub fn new(
|
||||||
|
doc_nodes: &[doc::DocNode],
|
||||||
|
details: bool,
|
||||||
|
private: bool,
|
||||||
|
) -> DocPrinter {
|
||||||
|
DocPrinter {
|
||||||
|
doc_nodes,
|
||||||
|
details,
|
||||||
|
private,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
details.push_str(&format!(
|
pub fn format(&self, w: &mut Formatter<'_>) -> FmtResult {
|
||||||
|
if self.details {
|
||||||
|
self.format_details(w, self.doc_nodes, 0)
|
||||||
|
} else {
|
||||||
|
self.format_summary(w, self.doc_nodes, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
kind_cmp
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for node in sorted {
|
||||||
|
self.format_signature(w, &node, indent)?;
|
||||||
|
|
||||||
|
if let Some(js_doc) = &node.js_doc {
|
||||||
|
self.format_jsdoc(w, js_doc, indent + 1, self.details)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
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::gray(&format!(
|
colors::italic_gray(&format!(
|
||||||
"Defined in {}:{}:{} \n\n",
|
"Defined in {}:{}:{} \n\n",
|
||||||
node.location.filename, node.location.line, node.location.col
|
node.location.filename, node.location.line, node.location.col
|
||||||
))
|
))
|
||||||
));
|
)?;
|
||||||
|
|
||||||
details.push_str(&format_signature(&node, 0));
|
self.format_signature(w, &node, indent)?;
|
||||||
|
|
||||||
let js_doc = node.js_doc.clone();
|
let js_doc = &node.js_doc;
|
||||||
if let Some(js_doc) = js_doc {
|
if let Some(js_doc) = js_doc {
|
||||||
details.push_str(&format_jsdoc(js_doc, 1));
|
self.format_jsdoc(w, js_doc, indent + 1, self.details)?;
|
||||||
}
|
}
|
||||||
details.push_str("\n");
|
writeln!(w)?;
|
||||||
|
|
||||||
let maybe_extra = match node.kind {
|
match node.kind {
|
||||||
DocNodeKind::Class => Some(format_class_details(node)),
|
DocNodeKind::Class => self.format_class_details(w, node)?,
|
||||||
DocNodeKind::Enum => Some(format_enum_details(node)),
|
DocNodeKind::Enum => self.format_enum_details(w, node)?,
|
||||||
DocNodeKind::Namespace => Some(format_namespace_details(node)),
|
DocNodeKind::Interface => self.format_interface_details(w, node)?,
|
||||||
_ => None,
|
DocNodeKind::Namespace => self.format_namespace_details(w, node)?,
|
||||||
};
|
_ => {}
|
||||||
|
}
|
||||||
if let Some(extra) = maybe_extra {
|
|
||||||
details.push_str(&extra);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
details
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn kind_order(kind: &doc::DocNodeKind) -> i64 {
|
fn kind_order(&self, kind: &doc::DocNodeKind) -> i64 {
|
||||||
match kind {
|
match kind {
|
||||||
DocNodeKind::Function => 0,
|
DocNodeKind::Function => 0,
|
||||||
DocNodeKind::Variable => 1,
|
DocNodeKind::Variable => 1,
|
||||||
|
@ -63,489 +131,344 @@ fn kind_order(kind: &doc::DocNodeKind) -> i64 {
|
||||||
DocNodeKind::TypeAlias => 5,
|
DocNodeKind::TypeAlias => 5,
|
||||||
DocNodeKind::Namespace => 6,
|
DocNodeKind::Namespace => 6,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_signature(node: &doc::DocNode, indent: i64) -> String {
|
fn format_signature(
|
||||||
|
&self,
|
||||||
|
w: &mut Formatter<'_>,
|
||||||
|
node: &doc::DocNode,
|
||||||
|
indent: i64,
|
||||||
|
) -> FmtResult {
|
||||||
match node.kind {
|
match node.kind {
|
||||||
DocNodeKind::Function => format_function_signature(&node, indent),
|
DocNodeKind::Function => self.format_function_signature(w, node, indent),
|
||||||
DocNodeKind::Variable => format_variable_signature(&node, indent),
|
DocNodeKind::Variable => self.format_variable_signature(w, node, indent),
|
||||||
DocNodeKind::Class => format_class_signature(&node, indent),
|
DocNodeKind::Class => self.format_class_signature(w, node, indent),
|
||||||
DocNodeKind::Enum => format_enum_signature(&node, indent),
|
DocNodeKind::Enum => self.format_enum_signature(w, node, indent),
|
||||||
DocNodeKind::Interface => format_interface_signature(&node, indent),
|
DocNodeKind::Interface => {
|
||||||
DocNodeKind::TypeAlias => format_type_alias_signature(&node, indent),
|
self.format_interface_signature(w, node, indent)
|
||||||
DocNodeKind::Namespace => format_namespace_signature(&node, indent),
|
|
||||||
}
|
}
|
||||||
}
|
DocNodeKind::TypeAlias => {
|
||||||
|
self.format_type_alias_signature(w, node, indent)
|
||||||
fn format_(doc_nodes: Vec<doc::DocNode>, indent: i64) -> String {
|
}
|
||||||
let mut sorted = doc_nodes;
|
DocNodeKind::Namespace => {
|
||||||
sorted.sort_unstable_by(|a, b| {
|
self.format_namespace_signature(w, node, indent)
|
||||||
let kind_cmp = kind_order(&a.kind).cmp(&kind_order(&b.kind));
|
|
||||||
if kind_cmp == core::cmp::Ordering::Equal {
|
|
||||||
a.name.cmp(&b.name)
|
|
||||||
} 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
|
// TODO(SyrupThinker) this should use a JSDoc parser
|
||||||
}
|
fn format_jsdoc(
|
||||||
|
&self,
|
||||||
fn render_params(params: Vec<doc::ParamDef>) -> String {
|
w: &mut Formatter<'_>,
|
||||||
let mut rendered = String::from("");
|
jsdoc: &str,
|
||||||
if !params.is_empty() {
|
indent: i64,
|
||||||
for param in params {
|
details: bool,
|
||||||
rendered += param.name.as_str();
|
) -> FmtResult {
|
||||||
if param.optional {
|
for line in jsdoc.lines() {
|
||||||
rendered += "?";
|
// Only show the first paragraph when summarising
|
||||||
}
|
// This should use the @summary JSDoc tag instead
|
||||||
if let Some(ts_type) = param.ts_type {
|
if !details && line.is_empty() {
|
||||||
rendered += ": ";
|
break;
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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))
|
writeln!(w, "{}{}", Indent(indent), colors::gray(&line))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_class_details(node: doc::DocNode) -> String {
|
Ok(())
|
||||||
let mut details = String::new();
|
}
|
||||||
|
|
||||||
let class_def = node.class_def.unwrap();
|
fn format_class_details(
|
||||||
for node in class_def.constructors {
|
&self,
|
||||||
details.push_str(&add_indent(
|
w: &mut Formatter<'_>,
|
||||||
format!(
|
node: &doc::DocNode,
|
||||||
"{} {}({})\n",
|
) -> FmtResult {
|
||||||
colors::magenta("constructor"),
|
let class_def = node.class_def.as_ref().unwrap();
|
||||||
colors::bold(&node.name),
|
for node in &class_def.constructors {
|
||||||
render_params(node.params),
|
writeln!(w, "{}{}", Indent(1), node,)?;
|
||||||
),
|
if let Some(js_doc) = &node.js_doc {
|
||||||
1,
|
self.format_jsdoc(w, &js_doc, 2, self.details)?;
|
||||||
));
|
}
|
||||||
}
|
}
|
||||||
for node in class_def.properties.iter().filter(|node| {
|
for node in class_def.properties.iter().filter(|node| {
|
||||||
node
|
self.private
|
||||||
|
|| node
|
||||||
.accessibility
|
.accessibility
|
||||||
.unwrap_or(swc_ecma_ast::Accessibility::Public)
|
.unwrap_or(swc_ecma_ast::Accessibility::Public)
|
||||||
!= swc_ecma_ast::Accessibility::Private
|
!= swc_ecma_ast::Accessibility::Private
|
||||||
}) {
|
}) {
|
||||||
details.push_str(&add_indent(
|
writeln!(w, "{}{}", Indent(1), node,)?;
|
||||||
format!(
|
if let Some(js_doc) = &node.js_doc {
|
||||||
"{}{}{}{}\n",
|
self.format_jsdoc(w, &js_doc, 2, self.details)?;
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
),
|
for index_sign_def in &class_def.index_signatures {
|
||||||
1,
|
writeln!(w, "{}{}", Indent(1), index_sign_def)?;
|
||||||
));
|
|
||||||
}
|
}
|
||||||
for node in class_def.methods.iter().filter(|node| {
|
for node in class_def.methods.iter().filter(|node| {
|
||||||
node
|
self.private
|
||||||
|
|| node
|
||||||
.accessibility
|
.accessibility
|
||||||
.unwrap_or(swc_ecma_ast::Accessibility::Public)
|
.unwrap_or(swc_ecma_ast::Accessibility::Public)
|
||||||
!= swc_ecma_ast::Accessibility::Private
|
!= swc_ecma_ast::Accessibility::Private
|
||||||
}) {
|
}) {
|
||||||
let function_def = node.function_def.clone();
|
writeln!(w, "{}{}", Indent(1), node,)?;
|
||||||
details.push_str(&add_indent(
|
if let Some(js_doc) = &node.js_doc {
|
||||||
format!(
|
self.format_jsdoc(w, js_doc, 2, self.details)?;
|
||||||
"{}{}{}{}({}){}\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()
|
|
||||||
}
|
}
|
||||||
),
|
writeln!(w)
|
||||||
1,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
details.push_str("\n");
|
|
||||||
details
|
|
||||||
}
|
|
||||||
|
|
||||||
fn format_enum_details(node: doc::DocNode) -> String {
|
fn format_enum_details(
|
||||||
let mut details = String::new();
|
&self,
|
||||||
let enum_def = node.enum_def.unwrap();
|
w: &mut Formatter<'_>,
|
||||||
for member in enum_def.members {
|
node: &doc::DocNode,
|
||||||
details
|
) -> FmtResult {
|
||||||
.push_str(&add_indent(format!("{}\n", colors::bold(&member.name)), 1));
|
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)
|
||||||
}
|
}
|
||||||
details.push_str("\n");
|
|
||||||
details
|
|
||||||
}
|
|
||||||
|
|
||||||
fn format_namespace_details(node: doc::DocNode) -> String {
|
fn format_interface_details(
|
||||||
let mut ns = String::new();
|
&self,
|
||||||
|
w: &mut Formatter<'_>,
|
||||||
|
node: &doc::DocNode,
|
||||||
|
) -> FmtResult {
|
||||||
|
let interface_def = node.interface_def.as_ref().unwrap();
|
||||||
|
|
||||||
let elements = node.namespace_def.unwrap().elements;
|
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 {
|
for node in elements {
|
||||||
ns.push_str(&format_signature(&node, 1));
|
self.format_signature(w, &node, 1)?;
|
||||||
|
if let Some(js_doc) = &node.js_doc {
|
||||||
|
self.format_jsdoc(w, js_doc, 2, false)?;
|
||||||
}
|
}
|
||||||
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())
|
|
||||||
} else {
|
|
||||||
"".to_string()
|
|
||||||
}
|
}
|
||||||
),
|
writeln!(w)
|
||||||
indent,
|
}
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn format_class_signature(node: &doc::DocNode, indent: i64) -> String {
|
fn format_class_signature(
|
||||||
let class_def = node.class_def.clone().unwrap();
|
&self,
|
||||||
let extends_suffix = if let Some(extends) = class_def.extends {
|
w: &mut Formatter<'_>,
|
||||||
format!(" {} {}", colors::magenta("extends"), colors::bold(&extends))
|
node: &doc::DocNode,
|
||||||
} else {
|
indent: i64,
|
||||||
String::from("")
|
) -> FmtResult {
|
||||||
};
|
let class_def = node.class_def.as_ref().unwrap();
|
||||||
|
write!(
|
||||||
let implements = &class_def.implements;
|
w,
|
||||||
let implements_suffix = if !implements.is_empty() {
|
"{}{}{} {}",
|
||||||
format!(
|
Indent(indent),
|
||||||
" {} {}",
|
display_abstract(class_def.is_abstract),
|
||||||
colors::magenta("implements"),
|
|
||||||
colors::bold(&implements.join(", "))
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
String::from("")
|
|
||||||
};
|
|
||||||
|
|
||||||
add_indent(
|
|
||||||
format!(
|
|
||||||
"{} {}{}{}\n",
|
|
||||||
colors::magenta("class"),
|
colors::magenta("class"),
|
||||||
colors::bold(&node.name),
|
colors::bold(&node.name),
|
||||||
extends_suffix,
|
)?;
|
||||||
implements_suffix,
|
if !class_def.type_params.is_empty() {
|
||||||
),
|
write!(
|
||||||
indent,
|
w,
|
||||||
)
|
"<{}>",
|
||||||
}
|
SliceDisplayer::new(&class_def.type_params, ", ", false)
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
fn format_variable_signature(node: &doc::DocNode, indent: i64) -> String {
|
if let Some(extends) = &class_def.extends {
|
||||||
let variable_def = node.variable_def.clone().unwrap();
|
write!(w, " {} {}", colors::magenta("extends"), extends)?;
|
||||||
add_indent(
|
}
|
||||||
format!(
|
if !class_def.super_type_params.is_empty() {
|
||||||
"{} {}{}\n",
|
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 {
|
colors::magenta(match variable_def.kind {
|
||||||
swc_ecma_ast::VarDeclKind::Const => "const",
|
swc_ecma_ast::VarDeclKind::Const => "const",
|
||||||
swc_ecma_ast::VarDeclKind::Let => "let",
|
swc_ecma_ast::VarDeclKind::Let => "let",
|
||||||
swc_ecma_ast::VarDeclKind::Var => "var",
|
swc_ecma_ast::VarDeclKind::Var => "var",
|
||||||
}),
|
}),
|
||||||
colors::bold(&node.name),
|
colors::bold(&node.name),
|
||||||
if let Some(ts_type) = variable_def.ts_type {
|
)?;
|
||||||
format!(": {}", render_ts_type(ts_type))
|
if let Some(ts_type) = &variable_def.ts_type {
|
||||||
} else {
|
write!(w, ": {}", ts_type)?;
|
||||||
"".to_string()
|
}
|
||||||
|
writeln!(w)
|
||||||
}
|
}
|
||||||
),
|
|
||||||
indent,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_enum_signature(node: &doc::DocNode, indent: i64) -> String {
|
impl<'a> Display for DocPrinter<'a> {
|
||||||
add_indent(
|
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||||
format!("{} {}\n", colors::magenta("enum"), colors::bold(&node.name)),
|
self.format(f)
|
||||||
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,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
2349
cli/doc/tests.rs
2349
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.
|
// 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::interface::expr_to_name;
|
||||||
use super::params::ts_fn_param_to_param_def;
|
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::maybe_type_param_decl_to_type_param_defs;
|
||||||
use super::ts_type_param::TsTypeParamDef;
|
use super::ts_type_param::TsTypeParamDef;
|
||||||
use super::ParamDef;
|
use super::ParamDef;
|
||||||
|
use crate::colors;
|
||||||
|
use crate::doc;
|
||||||
use crate::swc_ecma_ast;
|
use crate::swc_ecma_ast;
|
||||||
use crate::swc_ecma_ast::TsArrayType;
|
use crate::swc_ecma_ast::{
|
||||||
use crate::swc_ecma_ast::TsConditionalType;
|
TsArrayType, TsConditionalType, TsExprWithTypeArgs, TsFnOrConstructorType,
|
||||||
use crate::swc_ecma_ast::TsFnOrConstructorType;
|
TsIndexedAccessType, TsKeywordType, TsLit, TsLitType, TsOptionalType,
|
||||||
use crate::swc_ecma_ast::TsIndexedAccessType;
|
TsParenthesizedType, TsRestType, TsThisType, TsTupleType, TsType, TsTypeAnn,
|
||||||
use crate::swc_ecma_ast::TsKeywordType;
|
TsTypeLit, TsTypeOperator, TsTypeParamInstantiation, TsTypeQuery, TsTypeRef,
|
||||||
use crate::swc_ecma_ast::TsLit;
|
TsUnionOrIntersectionType,
|
||||||
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 serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||||
|
|
||||||
// pub enum TsType {
|
// pub enum TsType {
|
||||||
// * TsKeywordType(TsKeywordType),
|
// * TsKeywordType(TsKeywordType),
|
||||||
// * TsThisType(TsThisType),
|
// * TsThisType(TsThisType),
|
||||||
|
@ -316,7 +309,37 @@ impl Into<TsTypeDef> for &TsTypeRef {
|
||||||
};
|
};
|
||||||
|
|
||||||
TsTypeDef {
|
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_ref: Some(TsTypeRefDef {
|
||||||
type_name,
|
type_name,
|
||||||
type_params,
|
type_params,
|
||||||
|
@ -348,6 +371,7 @@ impl Into<TsTypeDef> for &TsTypeLit {
|
||||||
let mut methods = vec![];
|
let mut methods = vec![];
|
||||||
let mut properties = vec![];
|
let mut properties = vec![];
|
||||||
let mut call_signatures = vec![];
|
let mut call_signatures = vec![];
|
||||||
|
let mut index_signatures = vec![];
|
||||||
|
|
||||||
for type_element in &self.members {
|
for type_element in &self.members {
|
||||||
use crate::swc_ecma_ast::TsTypeElement::*;
|
use crate::swc_ecma_ast::TsTypeElement::*;
|
||||||
|
@ -357,7 +381,7 @@ impl Into<TsTypeDef> for &TsTypeLit {
|
||||||
let mut params = vec![];
|
let mut params = vec![];
|
||||||
|
|
||||||
for param in &ts_method_sig.params {
|
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);
|
params.push(param_def);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,7 +408,7 @@ impl Into<TsTypeDef> for &TsTypeLit {
|
||||||
let mut params = vec![];
|
let mut params = vec![];
|
||||||
|
|
||||||
for param in &ts_prop_sig.params {
|
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);
|
params.push(param_def);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -409,7 +433,7 @@ impl Into<TsTypeDef> for &TsTypeLit {
|
||||||
TsCallSignatureDecl(ts_call_sig) => {
|
TsCallSignatureDecl(ts_call_sig) => {
|
||||||
let mut params = vec![];
|
let mut params = vec![];
|
||||||
for param in &ts_call_sig.params {
|
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);
|
params.push(param_def);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,9 +453,27 @@ impl Into<TsTypeDef> for &TsTypeLit {
|
||||||
};
|
};
|
||||||
call_signatures.push(call_sig_def);
|
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:
|
// TODO:
|
||||||
TsConstructSignatureDecl(_) => {}
|
TsConstructSignatureDecl(_) => {}
|
||||||
TsIndexSignature(_) => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,6 +481,7 @@ impl Into<TsTypeDef> for &TsTypeLit {
|
||||||
methods,
|
methods,
|
||||||
properties,
|
properties,
|
||||||
call_signatures,
|
call_signatures,
|
||||||
|
index_signatures,
|
||||||
};
|
};
|
||||||
|
|
||||||
TsTypeDef {
|
TsTypeDef {
|
||||||
|
@ -475,7 +518,7 @@ impl Into<TsTypeDef> for &TsFnOrConstructorType {
|
||||||
let mut params = vec![];
|
let mut params = vec![];
|
||||||
|
|
||||||
for param in &ts_fn_type.params {
|
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);
|
params.push(param_def);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,7 +537,7 @@ impl Into<TsTypeDef> for &TsFnOrConstructorType {
|
||||||
let mut params = vec![];
|
let mut params = vec![];
|
||||||
|
|
||||||
for param in &ctor_type.params {
|
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);
|
params.push(param_def);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -619,6 +662,21 @@ pub struct LiteralMethodDef {
|
||||||
pub type_params: Vec<TsTypeParamDef>,
|
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)]
|
#[derive(Debug, Serialize, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct LiteralPropertyDef {
|
pub struct LiteralPropertyDef {
|
||||||
|
@ -630,6 +688,15 @@ pub struct LiteralPropertyDef {
|
||||||
pub type_params: Vec<TsTypeParamDef>,
|
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)]
|
#[derive(Debug, Serialize, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct LiteralCallSignatureDef {
|
pub struct LiteralCallSignatureDef {
|
||||||
|
@ -638,12 +705,46 @@ pub struct LiteralCallSignatureDef {
|
||||||
pub type_params: Vec<TsTypeParamDef>,
|
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)]
|
#[derive(Debug, Serialize, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct TsTypeLiteralDef {
|
pub struct TsTypeLiteralDef {
|
||||||
pub methods: Vec<LiteralMethodDef>,
|
pub methods: Vec<LiteralMethodDef>,
|
||||||
pub properties: Vec<LiteralPropertyDef>,
|
pub properties: Vec<LiteralPropertyDef>,
|
||||||
pub call_signatures: Vec<LiteralCallSignatureDef>,
|
pub call_signatures: Vec<LiteralCallSignatureDef>,
|
||||||
|
pub index_signatures: Vec<LiteralIndexSignatureDef>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Clone)]
|
#[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::TsTypeParam;
|
||||||
use crate::swc_ecma_ast::TsTypeParamDecl;
|
use crate::swc_ecma_ast::TsTypeParamDecl;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Clone)]
|
#[derive(Debug, Serialize, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
@ -16,6 +17,19 @@ pub struct TsTypeParamDef {
|
||||||
pub default: Option<TsTypeDef>,
|
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 {
|
impl Into<TsTypeParamDef> for &TsTypeParam {
|
||||||
fn into(self) -> TsTypeParamDef {
|
fn into(self) -> TsTypeParamDef {
|
||||||
let name = self.name.sym.to_string();
|
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]>,
|
buf: Box<[u8]>,
|
||||||
},
|
},
|
||||||
Doc {
|
Doc {
|
||||||
|
private: bool,
|
||||||
json: bool,
|
json: bool,
|
||||||
source_file: Option<String>,
|
source_file: Option<String>,
|
||||||
filter: Option<String>,
|
filter: Option<String>,
|
||||||
|
@ -598,12 +599,14 @@ fn doc_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
|
||||||
unstable_arg_parse(flags, matches);
|
unstable_arg_parse(flags, matches);
|
||||||
|
|
||||||
let source_file = matches.value_of("source_file").map(String::from);
|
let source_file = matches.value_of("source_file").map(String::from);
|
||||||
|
let private = matches.is_present("private");
|
||||||
let json = matches.is_present("json");
|
let json = matches.is_present("json");
|
||||||
let filter = matches.value_of("filter").map(String::from);
|
let filter = matches.value_of("filter").map(String::from);
|
||||||
flags.subcommand = DenoSubcommand::Doc {
|
flags.subcommand = DenoSubcommand::Doc {
|
||||||
source_file,
|
source_file,
|
||||||
json,
|
json,
|
||||||
filter,
|
filter,
|
||||||
|
private,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -915,6 +918,9 @@ fn doc_subcommand<'a, 'b>() -> App<'a, 'b> {
|
||||||
Output documentation to standard output:
|
Output documentation to standard output:
|
||||||
deno doc ./path/to/module.ts
|
deno doc ./path/to/module.ts
|
||||||
|
|
||||||
|
Output private documentation to standard output:
|
||||||
|
deno doc --private ./path/to/module.ts
|
||||||
|
|
||||||
Output documentation in JSON format:
|
Output documentation in JSON format:
|
||||||
deno doc --json ./path/to/module.ts
|
deno doc --json ./path/to/module.ts
|
||||||
|
|
||||||
|
@ -932,6 +938,12 @@ Show documentation for runtime built-ins:
|
||||||
.help("Output documentation in JSON format.")
|
.help("Output documentation in JSON format.")
|
||||||
.takes_value(false),
|
.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
|
// TODO(nayeemrmn): Make `--builtin` a proper option. Blocked by
|
||||||
// https://github.com/clap-rs/clap/issues/1794. Currently `--builtin` is
|
// https://github.com/clap-rs/clap/issues/1794. Currently `--builtin` is
|
||||||
// just a possible value of `source_file` so leading hyphens must be
|
// just a possible value of `source_file` so leading hyphens must be
|
||||||
|
@ -2910,6 +2922,7 @@ mod tests {
|
||||||
r.unwrap(),
|
r.unwrap(),
|
||||||
Flags {
|
Flags {
|
||||||
subcommand: DenoSubcommand::Doc {
|
subcommand: DenoSubcommand::Doc {
|
||||||
|
private: false,
|
||||||
json: true,
|
json: true,
|
||||||
source_file: Some("path/to/module.ts".to_string()),
|
source_file: Some("path/to/module.ts".to_string()),
|
||||||
filter: None,
|
filter: None,
|
||||||
|
@ -2928,6 +2941,7 @@ mod tests {
|
||||||
r.unwrap(),
|
r.unwrap(),
|
||||||
Flags {
|
Flags {
|
||||||
subcommand: DenoSubcommand::Doc {
|
subcommand: DenoSubcommand::Doc {
|
||||||
|
private: false,
|
||||||
json: false,
|
json: false,
|
||||||
source_file: Some("path/to/module.ts".to_string()),
|
source_file: Some("path/to/module.ts".to_string()),
|
||||||
filter: Some("SomeClass.someField".to_string()),
|
filter: Some("SomeClass.someField".to_string()),
|
||||||
|
@ -2941,6 +2955,7 @@ mod tests {
|
||||||
r.unwrap(),
|
r.unwrap(),
|
||||||
Flags {
|
Flags {
|
||||||
subcommand: DenoSubcommand::Doc {
|
subcommand: DenoSubcommand::Doc {
|
||||||
|
private: false,
|
||||||
json: false,
|
json: false,
|
||||||
source_file: None,
|
source_file: None,
|
||||||
filter: None,
|
filter: None,
|
||||||
|
@ -2955,6 +2970,7 @@ mod tests {
|
||||||
r.unwrap(),
|
r.unwrap(),
|
||||||
Flags {
|
Flags {
|
||||||
subcommand: DenoSubcommand::Doc {
|
subcommand: DenoSubcommand::Doc {
|
||||||
|
private: false,
|
||||||
json: false,
|
json: false,
|
||||||
source_file: Some("--builtin".to_string()),
|
source_file: Some("--builtin".to_string()),
|
||||||
filter: Some("Deno.Listener".to_string()),
|
filter: Some("Deno.Listener".to_string()),
|
||||||
|
@ -2962,6 +2978,25 @@ mod tests {
|
||||||
..Flags::default()
|
..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]
|
#[test]
|
||||||
|
|
14
cli/main.rs
14
cli/main.rs
|
@ -521,6 +521,7 @@ async fn doc_command(
|
||||||
source_file: Option<String>,
|
source_file: Option<String>,
|
||||||
json: bool,
|
json: bool,
|
||||||
maybe_filter: Option<String>,
|
maybe_filter: Option<String>,
|
||||||
|
private: bool,
|
||||||
) -> Result<(), ErrBox> {
|
) -> Result<(), ErrBox> {
|
||||||
let global_state = GlobalState::new(flags.clone())?;
|
let global_state = GlobalState::new(flags.clone())?;
|
||||||
let source_file = source_file.unwrap_or_else(|| "--builtin".to_string());
|
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 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" {
|
let parse_result = if source_file == "--builtin" {
|
||||||
doc_parser.parse_source("lib.deno.d.ts", get_types(flags.unstable).as_str())
|
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);
|
eprintln!("Node {} was not found!", filter);
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
let mut details = String::new();
|
format!("{}", doc::DocPrinter::new(&nodes, true, private))
|
||||||
for node in nodes {
|
|
||||||
details.push_str(doc::printer::format_details(node).as_str());
|
|
||||||
}
|
|
||||||
details
|
|
||||||
} else {
|
} 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)
|
write_to_stdout_ignore_sigpipe(details.as_bytes()).map_err(ErrBox::from)
|
||||||
|
@ -720,7 +717,8 @@ pub fn main() {
|
||||||
source_file,
|
source_file,
|
||||||
json,
|
json,
|
||||||
filter,
|
filter,
|
||||||
} => doc_command(flags, source_file, json, filter).boxed_local(),
|
private,
|
||||||
|
} => doc_command(flags, source_file, json, filter, private).boxed_local(),
|
||||||
DenoSubcommand::Eval {
|
DenoSubcommand::Eval {
|
||||||
print,
|
print,
|
||||||
code,
|
code,
|
||||||
|
|
Loading…
Add table
Reference in a new issue