mirror of
https://github.com/denoland/deno.git
synced 2025-01-11 00:21:05 -05:00
refactor: move cli/doc/ to separate crate (#7103)
This commit is contained in:
parent
1507a8cf2d
commit
be1e7ab532
24 changed files with 93 additions and 5683 deletions
18
Cargo.lock
generated
18
Cargo.lock
generated
|
@ -329,6 +329,7 @@ dependencies = [
|
|||
"bytes",
|
||||
"clap",
|
||||
"deno_core",
|
||||
"deno_doc",
|
||||
"deno_lint",
|
||||
"deno_web",
|
||||
"dissimilar",
|
||||
|
@ -392,6 +393,23 @@ dependencies = [
|
|||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deno_doc"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1700f692f75fb14c854ca5e2b5e74c23c5b5cc2b3ea9adec4ff0cd5693deab0"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"lazy_static",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"swc_common",
|
||||
"swc_ecmascript",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deno_lint"
|
||||
version = "0.1.23"
|
||||
|
|
|
@ -24,9 +24,9 @@ winapi = "0.3.9"
|
|||
|
||||
[dependencies]
|
||||
deno_core = { path = "../core", version = "0.53.0" }
|
||||
deno_doc = { version = "0.1.0" }
|
||||
deno_lint = { version = "0.1.23", features = ["json"] }
|
||||
|
||||
|
||||
atty = "0.2.14"
|
||||
base64 = "0.12.3"
|
||||
bytes = "0.5.6"
|
||||
|
|
339
cli/doc/class.rs
339
cli/doc/class.rs
|
@ -1,339 +0,0 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
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 serde::Serialize;
|
||||
use swc_common::Spanned;
|
||||
|
||||
use super::function::function_to_function_def;
|
||||
use super::function::FunctionDef;
|
||||
use super::interface::expr_to_name;
|
||||
use super::params::{
|
||||
assign_pat_to_param_def, ident_to_param_def, pat_to_param_def,
|
||||
prop_name_to_string, ts_fn_param_to_param_def,
|
||||
};
|
||||
use super::parser::DocParser;
|
||||
use super::ts_type::{
|
||||
maybe_type_param_instantiation_to_type_defs, ts_type_ann_to_def, TsTypeDef,
|
||||
};
|
||||
use super::ts_type_param::maybe_type_param_decl_to_type_param_defs;
|
||||
use super::ts_type_param::TsTypeParamDef;
|
||||
use super::Location;
|
||||
use super::ParamDef;
|
||||
|
||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ClassConstructorDef {
|
||||
pub js_doc: Option<String>,
|
||||
pub accessibility: Option<swc_ecmascript::ast::Accessibility>,
|
||||
pub name: String,
|
||||
pub params: Vec<ParamDef>,
|
||||
pub location: Location,
|
||||
}
|
||||
|
||||
impl Display for ClassConstructorDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(
|
||||
f,
|
||||
"{}{}({})",
|
||||
display_accessibility(self.accessibility),
|
||||
colors::magenta("constructor"),
|
||||
SliceDisplayer::new(&self.params, ", ", false),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ClassPropertyDef {
|
||||
pub js_doc: Option<String>,
|
||||
pub ts_type: Option<TsTypeDef>,
|
||||
pub readonly: bool,
|
||||
pub accessibility: Option<swc_ecmascript::ast::Accessibility>,
|
||||
pub optional: bool,
|
||||
pub is_abstract: bool,
|
||||
pub is_static: bool,
|
||||
pub name: String,
|
||||
pub location: Location,
|
||||
}
|
||||
|
||||
impl Display for ClassPropertyDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(
|
||||
f,
|
||||
"{}{}{}{}{}{}",
|
||||
display_abstract(self.is_abstract),
|
||||
display_accessibility(self.accessibility),
|
||||
display_static(self.is_static),
|
||||
display_readonly(self.readonly),
|
||||
colors::bold(&self.name),
|
||||
display_optional(self.optional),
|
||||
)?;
|
||||
if let Some(ts_type) = &self.ts_type {
|
||||
write!(f, ": {}", ts_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ClassIndexSignatureDef {
|
||||
pub readonly: bool,
|
||||
pub params: Vec<ParamDef>,
|
||||
pub ts_type: Option<TsTypeDef>,
|
||||
}
|
||||
|
||||
impl Display for ClassIndexSignatureDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(
|
||||
f,
|
||||
"{}[{}]",
|
||||
display_readonly(self.readonly),
|
||||
SliceDisplayer::new(&self.params, ", ", false)
|
||||
)?;
|
||||
if let Some(ts_type) = &self.ts_type {
|
||||
write!(f, ": {}", ts_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ClassMethodDef {
|
||||
pub js_doc: Option<String>,
|
||||
pub accessibility: Option<swc_ecmascript::ast::Accessibility>,
|
||||
pub optional: bool,
|
||||
pub is_abstract: bool,
|
||||
pub is_static: bool,
|
||||
pub name: String,
|
||||
pub kind: swc_ecmascript::ast::MethodKind,
|
||||
pub function_def: FunctionDef,
|
||||
pub location: Location,
|
||||
}
|
||||
|
||||
impl Display for ClassMethodDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(
|
||||
f,
|
||||
"{}{}{}{}{}{}{}{}({})",
|
||||
display_abstract(self.is_abstract),
|
||||
display_accessibility(self.accessibility),
|
||||
display_static(self.is_static),
|
||||
display_async(self.function_def.is_async),
|
||||
display_method(self.kind),
|
||||
display_generator(self.function_def.is_generator),
|
||||
colors::bold(&self.name),
|
||||
display_optional(self.optional),
|
||||
SliceDisplayer::new(&self.function_def.params, ", ", false),
|
||||
)?;
|
||||
if let Some(return_type) = &self.function_def.return_type {
|
||||
write!(f, ": {}", return_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ClassDef {
|
||||
// TODO(bartlomieju): decorators
|
||||
pub is_abstract: bool,
|
||||
pub constructors: Vec<ClassConstructorDef>,
|
||||
pub properties: Vec<ClassPropertyDef>,
|
||||
pub index_signatures: Vec<ClassIndexSignatureDef>,
|
||||
pub methods: Vec<ClassMethodDef>,
|
||||
pub extends: Option<String>,
|
||||
pub implements: Vec<TsTypeDef>,
|
||||
pub type_params: Vec<TsTypeParamDef>,
|
||||
pub super_type_params: Vec<TsTypeDef>,
|
||||
}
|
||||
|
||||
pub fn class_to_class_def(
|
||||
doc_parser: &DocParser,
|
||||
class: &swc_ecmascript::ast::Class,
|
||||
) -> ClassDef {
|
||||
let mut constructors = vec![];
|
||||
let mut methods = vec![];
|
||||
let mut properties = vec![];
|
||||
let mut index_signatures = vec![];
|
||||
|
||||
let extends: Option<String> = match &class.super_class {
|
||||
Some(boxed) => {
|
||||
use swc_ecmascript::ast::Expr;
|
||||
let expr: &Expr = &**boxed;
|
||||
match expr {
|
||||
Expr::Ident(ident) => Some(ident.sym.to_string()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
let implements = class
|
||||
.implements
|
||||
.iter()
|
||||
.map(|expr| expr.into())
|
||||
.collect::<Vec<TsTypeDef>>();
|
||||
|
||||
for member in &class.body {
|
||||
use swc_ecmascript::ast::ClassMember::*;
|
||||
|
||||
match member {
|
||||
Constructor(ctor) => {
|
||||
let ctor_js_doc = doc_parser.js_doc_for_span(ctor.span());
|
||||
let constructor_name = prop_name_to_string(
|
||||
&ctor.key,
|
||||
Some(&doc_parser.ast_parser.source_map),
|
||||
);
|
||||
|
||||
let mut params = vec![];
|
||||
|
||||
for param in &ctor.params {
|
||||
use swc_ecmascript::ast::ParamOrTsParamProp::*;
|
||||
|
||||
let param_def = match param {
|
||||
Param(param) => pat_to_param_def(
|
||||
¶m.pat,
|
||||
Some(&doc_parser.ast_parser.source_map),
|
||||
),
|
||||
TsParamProp(ts_param_prop) => {
|
||||
use swc_ecmascript::ast::TsParamPropParam;
|
||||
|
||||
match &ts_param_prop.param {
|
||||
TsParamPropParam::Ident(ident) => ident_to_param_def(
|
||||
ident,
|
||||
Some(&doc_parser.ast_parser.source_map),
|
||||
),
|
||||
TsParamPropParam::Assign(assign_pat) => {
|
||||
assign_pat_to_param_def(
|
||||
assign_pat,
|
||||
Some(&doc_parser.ast_parser.source_map),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
let constructor_def = ClassConstructorDef {
|
||||
js_doc: ctor_js_doc,
|
||||
accessibility: ctor.accessibility,
|
||||
name: constructor_name,
|
||||
params,
|
||||
location: doc_parser.ast_parser.get_span_location(ctor.span).into(),
|
||||
};
|
||||
constructors.push(constructor_def);
|
||||
}
|
||||
Method(class_method) => {
|
||||
let method_js_doc = doc_parser.js_doc_for_span(class_method.span());
|
||||
let method_name = prop_name_to_string(
|
||||
&class_method.key,
|
||||
Some(&doc_parser.ast_parser.source_map),
|
||||
);
|
||||
let fn_def =
|
||||
function_to_function_def(&doc_parser, &class_method.function);
|
||||
let method_def = ClassMethodDef {
|
||||
js_doc: method_js_doc,
|
||||
accessibility: class_method.accessibility,
|
||||
optional: class_method.is_optional,
|
||||
is_abstract: class_method.is_abstract,
|
||||
is_static: class_method.is_static,
|
||||
name: method_name,
|
||||
kind: class_method.kind,
|
||||
function_def: fn_def,
|
||||
location: doc_parser
|
||||
.ast_parser
|
||||
.get_span_location(class_method.span)
|
||||
.into(),
|
||||
};
|
||||
methods.push(method_def);
|
||||
}
|
||||
ClassProp(class_prop) => {
|
||||
let prop_js_doc = doc_parser.js_doc_for_span(class_prop.span());
|
||||
|
||||
let ts_type = class_prop
|
||||
.type_ann
|
||||
.as_ref()
|
||||
.map(|rt| ts_type_ann_to_def(rt));
|
||||
|
||||
let prop_name = expr_to_name(&*class_prop.key);
|
||||
|
||||
let prop_def = ClassPropertyDef {
|
||||
js_doc: prop_js_doc,
|
||||
ts_type,
|
||||
readonly: class_prop.readonly,
|
||||
optional: class_prop.is_optional,
|
||||
is_abstract: class_prop.is_abstract,
|
||||
is_static: class_prop.is_static,
|
||||
accessibility: class_prop.accessibility,
|
||||
name: prop_name,
|
||||
location: doc_parser
|
||||
.ast_parser
|
||||
.get_span_location(class_prop.span)
|
||||
.into(),
|
||||
};
|
||||
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):
|
||||
PrivateMethod(_) => {}
|
||||
PrivateProp(_) => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let type_params =
|
||||
maybe_type_param_decl_to_type_param_defs(class.type_params.as_ref());
|
||||
|
||||
let super_type_params = maybe_type_param_instantiation_to_type_defs(
|
||||
class.super_type_params.as_ref(),
|
||||
);
|
||||
|
||||
ClassDef {
|
||||
is_abstract: class.is_abstract,
|
||||
extends,
|
||||
implements,
|
||||
constructors,
|
||||
properties,
|
||||
index_signatures,
|
||||
methods,
|
||||
type_params,
|
||||
super_type_params,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_doc_for_class_decl(
|
||||
doc_parser: &DocParser,
|
||||
class_decl: &swc_ecmascript::ast::ClassDecl,
|
||||
) -> (String, ClassDef) {
|
||||
let class_name = class_decl.ident.sym.to_string();
|
||||
let class_def = class_to_class_def(doc_parser, &class_decl.class);
|
||||
|
||||
(class_name, class_def)
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
use crate::colors;
|
||||
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_ecmascript::ast::Accessibility>,
|
||||
) -> impl Display {
|
||||
colors::magenta(
|
||||
match accessibility.unwrap_or(swc_ecmascript::ast::Accessibility::Public) {
|
||||
swc_ecmascript::ast::Accessibility::Public => "",
|
||||
swc_ecmascript::ast::Accessibility::Protected => "protected ",
|
||||
swc_ecmascript::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_ecmascript::ast::MethodKind,
|
||||
) -> impl Display {
|
||||
colors::magenta(match method {
|
||||
swc_ecmascript::ast::MethodKind::Getter => "get ",
|
||||
swc_ecmascript::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,40 +0,0 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
use serde::Serialize;
|
||||
|
||||
use super::parser::DocParser;
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EnumMemberDef {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EnumDef {
|
||||
pub members: Vec<EnumMemberDef>,
|
||||
}
|
||||
|
||||
pub fn get_doc_for_ts_enum_decl(
|
||||
_doc_parser: &DocParser,
|
||||
enum_decl: &swc_ecmascript::ast::TsEnumDecl,
|
||||
) -> (String, EnumDef) {
|
||||
let enum_name = enum_decl.id.sym.to_string();
|
||||
let mut members = vec![];
|
||||
|
||||
for enum_member in &enum_decl.members {
|
||||
use swc_ecmascript::ast::TsEnumMemberId::*;
|
||||
|
||||
let member_name = match &enum_member.id {
|
||||
Ident(ident) => ident.sym.to_string(),
|
||||
Str(str_) => str_.value.to_string(),
|
||||
};
|
||||
|
||||
let member_def = EnumMemberDef { name: member_name };
|
||||
members.push(member_def);
|
||||
}
|
||||
|
||||
let enum_def = EnumDef { members };
|
||||
|
||||
(enum_name, enum_def)
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
use super::params::pat_to_param_def;
|
||||
use super::parser::DocParser;
|
||||
use super::ts_type::ts_type_ann_to_def;
|
||||
use super::ts_type::TsTypeDef;
|
||||
use super::ts_type_param::maybe_type_param_decl_to_type_param_defs;
|
||||
use super::ts_type_param::TsTypeParamDef;
|
||||
use super::ParamDef;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FunctionDef {
|
||||
pub params: Vec<ParamDef>,
|
||||
pub return_type: Option<TsTypeDef>,
|
||||
pub is_async: bool,
|
||||
pub is_generator: bool,
|
||||
pub type_params: Vec<TsTypeParamDef>,
|
||||
// TODO(bartlomieju): decorators
|
||||
}
|
||||
|
||||
pub fn function_to_function_def(
|
||||
doc_parser: &DocParser,
|
||||
function: &swc_ecmascript::ast::Function,
|
||||
) -> FunctionDef {
|
||||
let mut params = vec![];
|
||||
|
||||
for param in &function.params {
|
||||
let param_def =
|
||||
pat_to_param_def(¶m.pat, Some(&doc_parser.ast_parser.source_map));
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
let maybe_return_type = function
|
||||
.return_type
|
||||
.as_ref()
|
||||
.map(|rt| ts_type_ann_to_def(rt));
|
||||
|
||||
let type_params =
|
||||
maybe_type_param_decl_to_type_param_defs(function.type_params.as_ref());
|
||||
|
||||
FunctionDef {
|
||||
params,
|
||||
return_type: maybe_return_type,
|
||||
is_async: function.is_async,
|
||||
is_generator: function.is_generator,
|
||||
type_params,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_doc_for_fn_decl(
|
||||
doc_parser: &DocParser,
|
||||
fn_decl: &swc_ecmascript::ast::FnDecl,
|
||||
) -> (String, FunctionDef) {
|
||||
let name = fn_decl.ident.sym.to_string();
|
||||
let fn_def = function_to_function_def(&doc_parser, &fn_decl.function);
|
||||
(name, fn_def)
|
||||
}
|
|
@ -1,303 +0,0 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
use crate::colors;
|
||||
use crate::doc::display::{display_optional, display_readonly, SliceDisplayer};
|
||||
use serde::Serialize;
|
||||
|
||||
use super::params::ts_fn_param_to_param_def;
|
||||
use super::parser::DocParser;
|
||||
use super::ts_type::ts_type_ann_to_def;
|
||||
use super::ts_type::TsTypeDef;
|
||||
use super::ts_type_param::maybe_type_param_decl_to_type_param_defs;
|
||||
use super::ts_type_param::TsTypeParamDef;
|
||||
use super::Location;
|
||||
use super::ParamDef;
|
||||
|
||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InterfaceMethodDef {
|
||||
pub name: String,
|
||||
pub location: Location,
|
||||
pub js_doc: Option<String>,
|
||||
pub optional: bool,
|
||||
pub params: Vec<ParamDef>,
|
||||
pub return_type: Option<TsTypeDef>,
|
||||
pub type_params: Vec<TsTypeParamDef>,
|
||||
}
|
||||
|
||||
impl Display for InterfaceMethodDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(
|
||||
f,
|
||||
"{}{}({})",
|
||||
colors::bold(&self.name),
|
||||
display_optional(self.optional),
|
||||
SliceDisplayer::new(&self.params, ", ", false),
|
||||
)?;
|
||||
if let Some(return_type) = &self.return_type {
|
||||
write!(f, ": {}", return_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InterfacePropertyDef {
|
||||
pub name: String,
|
||||
pub location: Location,
|
||||
pub js_doc: Option<String>,
|
||||
pub params: Vec<ParamDef>,
|
||||
pub computed: bool,
|
||||
pub optional: bool,
|
||||
pub ts_type: Option<TsTypeDef>,
|
||||
pub type_params: Vec<TsTypeParamDef>,
|
||||
}
|
||||
|
||||
impl Display for InterfacePropertyDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(
|
||||
f,
|
||||
"{}{}",
|
||||
colors::bold(&self.name),
|
||||
display_optional(self.optional),
|
||||
)?;
|
||||
if let Some(ts_type) = &self.ts_type {
|
||||
write!(f, ": {}", ts_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InterfaceIndexSignatureDef {
|
||||
pub readonly: bool,
|
||||
pub params: Vec<ParamDef>,
|
||||
pub ts_type: Option<TsTypeDef>,
|
||||
}
|
||||
|
||||
impl Display for InterfaceIndexSignatureDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(
|
||||
f,
|
||||
"{}[{}]",
|
||||
display_readonly(self.readonly),
|
||||
SliceDisplayer::new(&self.params, ", ", false)
|
||||
)?;
|
||||
if let Some(ts_type) = &self.ts_type {
|
||||
write!(f, ": {}", ts_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InterfaceCallSignatureDef {
|
||||
pub location: Location,
|
||||
pub js_doc: Option<String>,
|
||||
pub params: Vec<ParamDef>,
|
||||
pub ts_type: Option<TsTypeDef>,
|
||||
pub type_params: Vec<TsTypeParamDef>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InterfaceDef {
|
||||
pub extends: Vec<TsTypeDef>,
|
||||
pub methods: Vec<InterfaceMethodDef>,
|
||||
pub properties: Vec<InterfacePropertyDef>,
|
||||
pub call_signatures: Vec<InterfaceCallSignatureDef>,
|
||||
pub index_signatures: Vec<InterfaceIndexSignatureDef>,
|
||||
pub type_params: Vec<TsTypeParamDef>,
|
||||
}
|
||||
|
||||
pub fn expr_to_name(expr: &swc_ecmascript::ast::Expr) -> String {
|
||||
use swc_ecmascript::ast::Expr::*;
|
||||
use swc_ecmascript::ast::ExprOrSuper::*;
|
||||
|
||||
match expr {
|
||||
Ident(ident) => ident.sym.to_string(),
|
||||
Member(member_expr) => {
|
||||
let left = match &member_expr.obj {
|
||||
Super(_) => "super".to_string(),
|
||||
Expr(boxed_expr) => expr_to_name(&*boxed_expr),
|
||||
};
|
||||
let right = expr_to_name(&*member_expr.prop);
|
||||
format!("[{}.{}]", left, right)
|
||||
}
|
||||
_ => "<TODO>".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_doc_for_ts_interface_decl(
|
||||
doc_parser: &DocParser,
|
||||
interface_decl: &swc_ecmascript::ast::TsInterfaceDecl,
|
||||
) -> (String, InterfaceDef) {
|
||||
let interface_name = interface_decl.id.sym.to_string();
|
||||
|
||||
let mut methods = vec![];
|
||||
let mut properties = vec![];
|
||||
let mut call_signatures = vec![];
|
||||
let mut index_signatures = vec![];
|
||||
|
||||
for type_element in &interface_decl.body.body {
|
||||
use swc_ecmascript::ast::TsTypeElement::*;
|
||||
|
||||
match &type_element {
|
||||
TsMethodSignature(ts_method_sig) => {
|
||||
let method_js_doc = doc_parser.js_doc_for_span(ts_method_sig.span);
|
||||
|
||||
let mut params = vec![];
|
||||
|
||||
for param in &ts_method_sig.params {
|
||||
let param_def = ts_fn_param_to_param_def(
|
||||
param,
|
||||
Some(&doc_parser.ast_parser.source_map),
|
||||
);
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
let name = expr_to_name(&*ts_method_sig.key);
|
||||
|
||||
let maybe_return_type = ts_method_sig
|
||||
.type_ann
|
||||
.as_ref()
|
||||
.map(|rt| ts_type_ann_to_def(rt));
|
||||
|
||||
let type_params = maybe_type_param_decl_to_type_param_defs(
|
||||
ts_method_sig.type_params.as_ref(),
|
||||
);
|
||||
|
||||
let method_def = InterfaceMethodDef {
|
||||
name,
|
||||
js_doc: method_js_doc,
|
||||
location: doc_parser
|
||||
.ast_parser
|
||||
.get_span_location(ts_method_sig.span)
|
||||
.into(),
|
||||
optional: ts_method_sig.optional,
|
||||
params,
|
||||
return_type: maybe_return_type,
|
||||
type_params,
|
||||
};
|
||||
methods.push(method_def);
|
||||
}
|
||||
TsPropertySignature(ts_prop_sig) => {
|
||||
let prop_js_doc = doc_parser.js_doc_for_span(ts_prop_sig.span);
|
||||
let name = expr_to_name(&*ts_prop_sig.key);
|
||||
|
||||
let mut params = vec![];
|
||||
|
||||
for param in &ts_prop_sig.params {
|
||||
let param_def = ts_fn_param_to_param_def(
|
||||
param,
|
||||
Some(&doc_parser.ast_parser.source_map),
|
||||
);
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
let ts_type = ts_prop_sig
|
||||
.type_ann
|
||||
.as_ref()
|
||||
.map(|rt| ts_type_ann_to_def(rt));
|
||||
|
||||
let type_params = maybe_type_param_decl_to_type_param_defs(
|
||||
ts_prop_sig.type_params.as_ref(),
|
||||
);
|
||||
|
||||
let prop_def = InterfacePropertyDef {
|
||||
name,
|
||||
js_doc: prop_js_doc,
|
||||
location: doc_parser
|
||||
.ast_parser
|
||||
.get_span_location(ts_prop_sig.span)
|
||||
.into(),
|
||||
params,
|
||||
ts_type,
|
||||
computed: ts_prop_sig.computed,
|
||||
optional: ts_prop_sig.optional,
|
||||
type_params,
|
||||
};
|
||||
properties.push(prop_def);
|
||||
}
|
||||
TsCallSignatureDecl(ts_call_sig) => {
|
||||
let call_sig_js_doc = doc_parser.js_doc_for_span(ts_call_sig.span);
|
||||
|
||||
let mut params = vec![];
|
||||
for param in &ts_call_sig.params {
|
||||
let param_def = ts_fn_param_to_param_def(
|
||||
param,
|
||||
Some(&doc_parser.ast_parser.source_map),
|
||||
);
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
let ts_type = ts_call_sig
|
||||
.type_ann
|
||||
.as_ref()
|
||||
.map(|rt| ts_type_ann_to_def(rt));
|
||||
|
||||
let type_params = maybe_type_param_decl_to_type_param_defs(
|
||||
ts_call_sig.type_params.as_ref(),
|
||||
);
|
||||
|
||||
let call_sig_def = InterfaceCallSignatureDef {
|
||||
js_doc: call_sig_js_doc,
|
||||
location: doc_parser
|
||||
.ast_parser
|
||||
.get_span_location(ts_call_sig.span)
|
||||
.into(),
|
||||
params,
|
||||
ts_type,
|
||||
type_params,
|
||||
};
|
||||
call_signatures.push(call_sig_def);
|
||||
}
|
||||
TsIndexSignature(ts_index_sig) => {
|
||||
let mut params = vec![];
|
||||
for param in &ts_index_sig.params {
|
||||
let param_def = ts_fn_param_to_param_def(param, None);
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
let ts_type = ts_index_sig
|
||||
.type_ann
|
||||
.as_ref()
|
||||
.map(|rt| (&*rt.type_ann).into());
|
||||
|
||||
let index_sig_def = InterfaceIndexSignatureDef {
|
||||
readonly: ts_index_sig.readonly,
|
||||
params,
|
||||
ts_type,
|
||||
};
|
||||
index_signatures.push(index_sig_def);
|
||||
}
|
||||
// TODO:
|
||||
TsConstructSignatureDecl(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
let type_params = maybe_type_param_decl_to_type_param_defs(
|
||||
interface_decl.type_params.as_ref(),
|
||||
);
|
||||
|
||||
let extends = interface_decl
|
||||
.extends
|
||||
.iter()
|
||||
.map(|expr| expr.into())
|
||||
.collect::<Vec<TsTypeDef>>();
|
||||
|
||||
let interface_def = InterfaceDef {
|
||||
extends,
|
||||
methods,
|
||||
properties,
|
||||
call_signatures,
|
||||
index_signatures,
|
||||
type_params,
|
||||
};
|
||||
|
||||
(interface_name, interface_def)
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
pub mod class;
|
||||
mod display;
|
||||
pub mod r#enum;
|
||||
pub mod function;
|
||||
pub mod interface;
|
||||
pub mod module;
|
||||
pub mod namespace;
|
||||
mod node;
|
||||
pub mod params;
|
||||
pub mod parser;
|
||||
pub mod printer;
|
||||
pub mod ts_type;
|
||||
pub mod ts_type_param;
|
||||
pub mod type_alias;
|
||||
pub mod variable;
|
||||
|
||||
pub use node::DocNode;
|
||||
pub use node::DocNodeKind;
|
||||
pub use node::ImportDef;
|
||||
pub use node::Location;
|
||||
pub use params::ParamDef;
|
||||
pub use parser::DocParser;
|
||||
pub use printer::DocPrinter;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub fn find_nodes_by_name_recursively(
|
||||
doc_nodes: Vec<DocNode>,
|
||||
name: String,
|
||||
) -> Vec<DocNode> {
|
||||
let mut parts = name.splitn(2, '.');
|
||||
let name = parts.next();
|
||||
let leftover = parts.next();
|
||||
if name.is_none() {
|
||||
return doc_nodes;
|
||||
}
|
||||
|
||||
let name = name.unwrap();
|
||||
let doc_nodes = find_nodes_by_name(doc_nodes, name.to_string());
|
||||
|
||||
let mut found: Vec<DocNode> = vec![];
|
||||
match leftover {
|
||||
Some(leftover) => {
|
||||
for node in doc_nodes {
|
||||
let children = find_children_by_name(node, leftover.to_string());
|
||||
found.extend(children);
|
||||
}
|
||||
found
|
||||
}
|
||||
None => doc_nodes,
|
||||
}
|
||||
}
|
||||
|
||||
fn find_nodes_by_name(doc_nodes: Vec<DocNode>, name: String) -> Vec<DocNode> {
|
||||
let mut found: Vec<DocNode> = vec![];
|
||||
for node in doc_nodes {
|
||||
if node.name == name {
|
||||
found.push(node);
|
||||
}
|
||||
}
|
||||
found
|
||||
}
|
||||
|
||||
fn find_children_by_name(node: DocNode, name: String) -> Vec<DocNode> {
|
||||
match node.kind {
|
||||
DocNodeKind::Namespace => {
|
||||
let namespace_def = node.namespace_def.unwrap();
|
||||
find_nodes_by_name_recursively(namespace_def.elements, name)
|
||||
}
|
||||
// TODO(#4516) handle class, interface etc...
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
use swc_common::Spanned;
|
||||
|
||||
use super::parser::DocParser;
|
||||
use super::DocNode;
|
||||
|
||||
pub fn get_doc_node_for_export_decl(
|
||||
doc_parser: &DocParser,
|
||||
export_decl: &swc_ecmascript::ast::ExportDecl,
|
||||
) -> DocNode {
|
||||
let export_span = export_decl.span();
|
||||
use swc_ecmascript::ast::Decl;
|
||||
|
||||
let js_doc = doc_parser.js_doc_for_span(export_span);
|
||||
let location = doc_parser.ast_parser.get_span_location(export_span).into();
|
||||
|
||||
match &export_decl.decl {
|
||||
Decl::Class(class_decl) => {
|
||||
let (name, class_def) =
|
||||
super::class::get_doc_for_class_decl(doc_parser, class_decl);
|
||||
DocNode::class(name, location, js_doc, class_def)
|
||||
}
|
||||
Decl::Fn(fn_decl) => {
|
||||
let (name, function_def) =
|
||||
super::function::get_doc_for_fn_decl(doc_parser, fn_decl);
|
||||
DocNode::function(name, location, js_doc, function_def)
|
||||
}
|
||||
Decl::Var(var_decl) => {
|
||||
let (name, var_def) = super::variable::get_doc_for_var_decl(var_decl);
|
||||
DocNode::variable(name, location, js_doc, var_def)
|
||||
}
|
||||
Decl::TsInterface(ts_interface_decl) => {
|
||||
let (name, interface_def) =
|
||||
super::interface::get_doc_for_ts_interface_decl(
|
||||
doc_parser,
|
||||
ts_interface_decl,
|
||||
);
|
||||
DocNode::interface(name, location, js_doc, interface_def)
|
||||
}
|
||||
Decl::TsTypeAlias(ts_type_alias) => {
|
||||
let (name, type_alias_def) =
|
||||
super::type_alias::get_doc_for_ts_type_alias_decl(
|
||||
doc_parser,
|
||||
ts_type_alias,
|
||||
);
|
||||
DocNode::type_alias(name, location, js_doc, type_alias_def)
|
||||
}
|
||||
Decl::TsEnum(ts_enum) => {
|
||||
let (name, enum_def) =
|
||||
super::r#enum::get_doc_for_ts_enum_decl(doc_parser, ts_enum);
|
||||
DocNode::r#enum(name, location, js_doc, enum_def)
|
||||
}
|
||||
Decl::TsModule(ts_module) => {
|
||||
let (name, namespace_def) =
|
||||
super::namespace::get_doc_for_ts_module(doc_parser, ts_module);
|
||||
DocNode::namespace(name, location, js_doc, namespace_def)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
use serde::Serialize;
|
||||
|
||||
use super::parser::DocParser;
|
||||
use super::DocNode;
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
pub struct NamespaceDef {
|
||||
pub elements: Vec<DocNode>,
|
||||
}
|
||||
|
||||
pub fn get_doc_for_ts_namespace_decl(
|
||||
doc_parser: &DocParser,
|
||||
ts_namespace_decl: &swc_ecmascript::ast::TsNamespaceDecl,
|
||||
) -> DocNode {
|
||||
let js_doc = doc_parser.js_doc_for_span(ts_namespace_decl.span);
|
||||
let location = doc_parser
|
||||
.ast_parser
|
||||
.get_span_location(ts_namespace_decl.span)
|
||||
.into();
|
||||
let namespace_name = ts_namespace_decl.id.sym.to_string();
|
||||
|
||||
use swc_ecmascript::ast::TsNamespaceBody::*;
|
||||
|
||||
let elements = match &*ts_namespace_decl.body {
|
||||
TsModuleBlock(ts_module_block) => {
|
||||
doc_parser.get_doc_nodes_for_module_body(ts_module_block.body.clone())
|
||||
}
|
||||
TsNamespaceDecl(ts_namespace_decl) => {
|
||||
vec![get_doc_for_ts_namespace_decl(doc_parser, ts_namespace_decl)]
|
||||
}
|
||||
};
|
||||
|
||||
let ns_def = NamespaceDef { elements };
|
||||
|
||||
DocNode::namespace(namespace_name, location, js_doc, ns_def)
|
||||
}
|
||||
|
||||
pub fn get_doc_for_ts_module(
|
||||
doc_parser: &DocParser,
|
||||
ts_module_decl: &swc_ecmascript::ast::TsModuleDecl,
|
||||
) -> (String, NamespaceDef) {
|
||||
use swc_ecmascript::ast::TsModuleName;
|
||||
let namespace_name = match &ts_module_decl.id {
|
||||
TsModuleName::Ident(ident) => ident.sym.to_string(),
|
||||
TsModuleName::Str(str_) => str_.value.to_string(),
|
||||
};
|
||||
|
||||
let elements = if let Some(body) = &ts_module_decl.body {
|
||||
use swc_ecmascript::ast::TsNamespaceBody::*;
|
||||
|
||||
match &body {
|
||||
TsModuleBlock(ts_module_block) => {
|
||||
doc_parser.get_doc_nodes_for_module_body(ts_module_block.body.clone())
|
||||
}
|
||||
TsNamespaceDecl(ts_namespace_decl) => {
|
||||
vec![get_doc_for_ts_namespace_decl(doc_parser, ts_namespace_decl)]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
let ns_def = NamespaceDef { elements };
|
||||
|
||||
(namespace_name, ns_def)
|
||||
}
|
287
cli/doc/node.rs
287
cli/doc/node.rs
|
@ -1,287 +0,0 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum DocNodeKind {
|
||||
Function,
|
||||
Variable,
|
||||
Class,
|
||||
Enum,
|
||||
Interface,
|
||||
TypeAlias,
|
||||
Namespace,
|
||||
Import,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone, PartialEq)]
|
||||
pub struct Location {
|
||||
pub filename: String,
|
||||
pub line: usize,
|
||||
pub col: usize,
|
||||
}
|
||||
|
||||
impl Into<Location> for swc_common::Loc {
|
||||
fn into(self) -> Location {
|
||||
use swc_common::FileName::*;
|
||||
|
||||
let filename = match &self.file.name {
|
||||
Real(path_buf) => path_buf.to_string_lossy().to_string(),
|
||||
Custom(str_) => str_.to_string(),
|
||||
_ => panic!("invalid filename"),
|
||||
};
|
||||
|
||||
Location {
|
||||
filename,
|
||||
line: self.line,
|
||||
col: self.col_display,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum ReexportKind {
|
||||
/// export * from "./path/to/module.js";
|
||||
All,
|
||||
/// export * as someNamespace from "./path/to/module.js";
|
||||
Namespace(String),
|
||||
/// export default from "./path/to/module.js";
|
||||
Default,
|
||||
/// (identifier, optional alias)
|
||||
/// export { foo } from "./path/to/module.js";
|
||||
/// export { foo as bar } from "./path/to/module.js";
|
||||
Named(String, Option<String>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Reexport {
|
||||
pub kind: ReexportKind,
|
||||
pub src: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ModuleDoc {
|
||||
pub definitions: Vec<DocNode>,
|
||||
pub reexports: Vec<Reexport>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ImportDef {
|
||||
pub src: String,
|
||||
pub imported: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocNode {
|
||||
pub kind: DocNodeKind,
|
||||
pub name: String,
|
||||
pub location: Location,
|
||||
pub js_doc: Option<String>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub function_def: Option<super::function::FunctionDef>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub variable_def: Option<super::variable::VariableDef>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub enum_def: Option<super::r#enum::EnumDef>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub class_def: Option<super::class::ClassDef>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub type_alias_def: Option<super::type_alias::TypeAliasDef>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub namespace_def: Option<super::namespace::NamespaceDef>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub interface_def: Option<super::interface::InterfaceDef>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub import_def: Option<ImportDef>,
|
||||
}
|
||||
|
||||
impl DocNode {
|
||||
pub fn function(
|
||||
name: String,
|
||||
location: Location,
|
||||
js_doc: Option<String>,
|
||||
fn_def: super::function::FunctionDef,
|
||||
) -> Self {
|
||||
Self {
|
||||
kind: DocNodeKind::Function,
|
||||
name,
|
||||
location,
|
||||
js_doc,
|
||||
function_def: Some(fn_def),
|
||||
variable_def: None,
|
||||
enum_def: None,
|
||||
class_def: None,
|
||||
type_alias_def: None,
|
||||
namespace_def: None,
|
||||
interface_def: None,
|
||||
import_def: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn variable(
|
||||
name: String,
|
||||
location: Location,
|
||||
js_doc: Option<String>,
|
||||
var_def: super::variable::VariableDef,
|
||||
) -> Self {
|
||||
Self {
|
||||
kind: DocNodeKind::Variable,
|
||||
name,
|
||||
location,
|
||||
js_doc,
|
||||
function_def: None,
|
||||
variable_def: Some(var_def),
|
||||
enum_def: None,
|
||||
class_def: None,
|
||||
type_alias_def: None,
|
||||
namespace_def: None,
|
||||
interface_def: None,
|
||||
import_def: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn r#enum(
|
||||
name: String,
|
||||
location: Location,
|
||||
js_doc: Option<String>,
|
||||
enum_def: super::r#enum::EnumDef,
|
||||
) -> Self {
|
||||
Self {
|
||||
kind: DocNodeKind::Enum,
|
||||
name,
|
||||
location,
|
||||
js_doc,
|
||||
function_def: None,
|
||||
variable_def: None,
|
||||
enum_def: Some(enum_def),
|
||||
class_def: None,
|
||||
type_alias_def: None,
|
||||
namespace_def: None,
|
||||
interface_def: None,
|
||||
import_def: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn class(
|
||||
name: String,
|
||||
location: Location,
|
||||
js_doc: Option<String>,
|
||||
class_def: super::class::ClassDef,
|
||||
) -> Self {
|
||||
Self {
|
||||
kind: DocNodeKind::Class,
|
||||
name,
|
||||
location,
|
||||
js_doc,
|
||||
function_def: None,
|
||||
variable_def: None,
|
||||
enum_def: None,
|
||||
class_def: Some(class_def),
|
||||
type_alias_def: None,
|
||||
namespace_def: None,
|
||||
interface_def: None,
|
||||
import_def: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_alias(
|
||||
name: String,
|
||||
location: Location,
|
||||
js_doc: Option<String>,
|
||||
type_alias_def: super::type_alias::TypeAliasDef,
|
||||
) -> Self {
|
||||
Self {
|
||||
kind: DocNodeKind::TypeAlias,
|
||||
name,
|
||||
location,
|
||||
js_doc,
|
||||
function_def: None,
|
||||
variable_def: None,
|
||||
enum_def: None,
|
||||
class_def: None,
|
||||
type_alias_def: Some(type_alias_def),
|
||||
namespace_def: None,
|
||||
interface_def: None,
|
||||
import_def: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn namespace(
|
||||
name: String,
|
||||
location: Location,
|
||||
js_doc: Option<String>,
|
||||
namespace_def: super::namespace::NamespaceDef,
|
||||
) -> Self {
|
||||
Self {
|
||||
kind: DocNodeKind::Namespace,
|
||||
name,
|
||||
location,
|
||||
js_doc,
|
||||
function_def: None,
|
||||
variable_def: None,
|
||||
enum_def: None,
|
||||
class_def: None,
|
||||
type_alias_def: None,
|
||||
namespace_def: Some(namespace_def),
|
||||
interface_def: None,
|
||||
import_def: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn interface(
|
||||
name: String,
|
||||
location: Location,
|
||||
js_doc: Option<String>,
|
||||
interface_def: super::interface::InterfaceDef,
|
||||
) -> Self {
|
||||
Self {
|
||||
kind: DocNodeKind::Interface,
|
||||
name,
|
||||
location,
|
||||
js_doc,
|
||||
function_def: None,
|
||||
variable_def: None,
|
||||
enum_def: None,
|
||||
class_def: None,
|
||||
type_alias_def: None,
|
||||
namespace_def: None,
|
||||
interface_def: Some(interface_def),
|
||||
import_def: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn import(
|
||||
name: String,
|
||||
location: Location,
|
||||
js_doc: Option<String>,
|
||||
import_def: ImportDef,
|
||||
) -> Self {
|
||||
Self {
|
||||
kind: DocNodeKind::Import,
|
||||
name,
|
||||
location,
|
||||
js_doc,
|
||||
function_def: None,
|
||||
variable_def: None,
|
||||
enum_def: None,
|
||||
class_def: None,
|
||||
type_alias_def: None,
|
||||
namespace_def: None,
|
||||
interface_def: None,
|
||||
import_def: Some(import_def),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,289 +0,0 @@
|
|||
// 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 serde::Serialize;
|
||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||
use swc_common::SourceMap;
|
||||
use swc_ecmascript::ast::{ObjectPatProp, Pat, TsFnParam};
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(tag = "kind")]
|
||||
pub enum ParamDef {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
Array {
|
||||
elements: Vec<Option<ParamDef>>,
|
||||
optional: bool,
|
||||
ts_type: Option<TsTypeDef>,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
Assign {
|
||||
left: Box<ParamDef>,
|
||||
right: String,
|
||||
ts_type: Option<TsTypeDef>,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
Identifier {
|
||||
name: String,
|
||||
optional: bool,
|
||||
ts_type: Option<TsTypeDef>,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
Object {
|
||||
props: Vec<ObjectPatPropDef>,
|
||||
optional: bool,
|
||||
ts_type: Option<TsTypeDef>,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
Rest {
|
||||
arg: Box<ParamDef>,
|
||||
ts_type: Option<TsTypeDef>,
|
||||
},
|
||||
}
|
||||
|
||||
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_ecmascript::ast::Ident,
|
||||
_source_map: Option<&SourceMap>,
|
||||
) -> ParamDef {
|
||||
let ts_type = ident.type_ann.as_ref().map(|rt| ts_type_ann_to_def(rt));
|
||||
|
||||
ParamDef::Identifier {
|
||||
name: ident.sym.to_string(),
|
||||
optional: ident.optional,
|
||||
ts_type,
|
||||
}
|
||||
}
|
||||
|
||||
fn rest_pat_to_param_def(
|
||||
rest_pat: &swc_ecmascript::ast::RestPat,
|
||||
source_map: Option<&SourceMap>,
|
||||
) -> ParamDef {
|
||||
let ts_type = rest_pat.type_ann.as_ref().map(|rt| ts_type_ann_to_def(rt));
|
||||
|
||||
ParamDef::Rest {
|
||||
arg: Box::new(pat_to_param_def(&*rest_pat.arg, source_map)),
|
||||
ts_type,
|
||||
}
|
||||
}
|
||||
|
||||
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_ecmascript::ast::ObjectPat,
|
||||
source_map: Option<&SourceMap>,
|
||||
) -> ParamDef {
|
||||
let props = object_pat
|
||||
.props
|
||||
.iter()
|
||||
.map(|prop| object_pat_prop_to_def(prop, source_map))
|
||||
.collect::<Vec<_>>();
|
||||
let ts_type = object_pat
|
||||
.type_ann
|
||||
.as_ref()
|
||||
.map(|rt| ts_type_ann_to_def(rt));
|
||||
|
||||
ParamDef::Object {
|
||||
props,
|
||||
optional: object_pat.optional,
|
||||
ts_type,
|
||||
}
|
||||
}
|
||||
|
||||
fn array_pat_to_param_def(
|
||||
array_pat: &swc_ecmascript::ast::ArrayPat,
|
||||
source_map: Option<&SourceMap>,
|
||||
) -> ParamDef {
|
||||
let elements = array_pat
|
||||
.elems
|
||||
.iter()
|
||||
.map(|elem| elem.as_ref().map(|e| pat_to_param_def(e, source_map)))
|
||||
.collect::<Vec<Option<_>>>();
|
||||
let ts_type = array_pat.type_ann.as_ref().map(|rt| ts_type_ann_to_def(rt));
|
||||
|
||||
ParamDef::Array {
|
||||
elements,
|
||||
optional: array_pat.optional,
|
||||
ts_type,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assign_pat_to_param_def(
|
||||
assign_pat: &swc_ecmascript::ast::AssignPat,
|
||||
source_map: Option<&SourceMap>,
|
||||
) -> ParamDef {
|
||||
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_ecmascript::ast::Pat,
|
||||
source_map: Option<&SourceMap>,
|
||||
) -> ParamDef {
|
||||
match pat {
|
||||
Pat::Ident(ident) => ident_to_param_def(ident, source_map),
|
||||
Pat::Array(array_pat) => array_pat_to_param_def(array_pat, source_map),
|
||||
Pat::Rest(rest_pat) => rest_pat_to_param_def(rest_pat, source_map),
|
||||
Pat::Object(object_pat) => object_pat_to_param_def(object_pat, source_map),
|
||||
Pat::Assign(assign_pat) => assign_pat_to_param_def(assign_pat, source_map),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ts_fn_param_to_param_def(
|
||||
ts_fn_param: &swc_ecmascript::ast::TsFnParam,
|
||||
source_map: Option<&SourceMap>,
|
||||
) -> ParamDef {
|
||||
match ts_fn_param {
|
||||
TsFnParam::Ident(ident) => ident_to_param_def(ident, source_map),
|
||||
TsFnParam::Array(array_pat) => {
|
||||
array_pat_to_param_def(array_pat, source_map)
|
||||
}
|
||||
TsFnParam::Rest(rest_pat) => rest_pat_to_param_def(rest_pat, source_map),
|
||||
TsFnParam::Object(object_pat) => {
|
||||
object_pat_to_param_def(object_pat, source_map)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prop_name_to_string(
|
||||
prop_name: &swc_ecmascript::ast::PropName,
|
||||
source_map: Option<&SourceMap>,
|
||||
) -> String {
|
||||
use swc_ecmascript::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()),
|
||||
}
|
||||
}
|
|
@ -1,505 +0,0 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
use crate::file_fetcher::map_file_extension;
|
||||
use crate::op_error::OpError;
|
||||
use crate::swc_util::AstParser;
|
||||
use swc_common::comments::CommentKind;
|
||||
use swc_common::Span;
|
||||
use swc_ecmascript::ast::Decl;
|
||||
use swc_ecmascript::ast::DefaultDecl;
|
||||
use swc_ecmascript::ast::ModuleDecl;
|
||||
use swc_ecmascript::ast::Stmt;
|
||||
|
||||
use deno_core::ErrBox;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use futures::Future;
|
||||
use regex::Regex;
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::pin::Pin;
|
||||
|
||||
use super::namespace::NamespaceDef;
|
||||
use super::node;
|
||||
use super::node::ModuleDoc;
|
||||
use super::DocNode;
|
||||
use super::DocNodeKind;
|
||||
use super::ImportDef;
|
||||
use super::Location;
|
||||
|
||||
pub trait DocFileLoader {
|
||||
fn resolve(
|
||||
&self,
|
||||
specifier: &str,
|
||||
referrer: &str,
|
||||
) -> Result<ModuleSpecifier, OpError> {
|
||||
ModuleSpecifier::resolve_import(specifier, referrer).map_err(OpError::from)
|
||||
}
|
||||
|
||||
fn load_source_code(
|
||||
&self,
|
||||
specifier: &str,
|
||||
) -> Pin<Box<dyn Future<Output = Result<String, OpError>>>>;
|
||||
}
|
||||
|
||||
pub struct DocParser {
|
||||
pub ast_parser: AstParser,
|
||||
pub loader: Box<dyn DocFileLoader>,
|
||||
pub private: bool,
|
||||
}
|
||||
|
||||
impl DocParser {
|
||||
pub fn new(loader: Box<dyn DocFileLoader>, private: bool) -> Self {
|
||||
DocParser {
|
||||
loader,
|
||||
ast_parser: AstParser::default(),
|
||||
private,
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_module(
|
||||
&self,
|
||||
file_name: &str,
|
||||
source_code: &str,
|
||||
) -> Result<ModuleDoc, ErrBox> {
|
||||
let media_type = map_file_extension(&PathBuf::from(file_name));
|
||||
let parse_result =
|
||||
self
|
||||
.ast_parser
|
||||
.parse_module(file_name, media_type, source_code);
|
||||
let module = parse_result?;
|
||||
let mut doc_entries =
|
||||
self.get_doc_nodes_for_module_body(module.body.clone());
|
||||
let import_doc_entries =
|
||||
self.get_doc_nodes_for_module_imports(module.body.clone(), file_name)?;
|
||||
doc_entries.extend(import_doc_entries);
|
||||
let reexports = self.get_reexports_for_module_body(module.body);
|
||||
let module_doc = ModuleDoc {
|
||||
definitions: doc_entries,
|
||||
reexports,
|
||||
};
|
||||
Ok(module_doc)
|
||||
}
|
||||
|
||||
pub async fn parse(&self, file_name: &str) -> Result<Vec<DocNode>, ErrBox> {
|
||||
let source_code = self.loader.load_source_code(file_name).await?;
|
||||
|
||||
self.parse_source(file_name, source_code.as_str())
|
||||
}
|
||||
|
||||
pub fn parse_source(
|
||||
&self,
|
||||
file_name: &str,
|
||||
source_code: &str,
|
||||
) -> Result<Vec<DocNode>, ErrBox> {
|
||||
let module_doc = self.parse_module(file_name, &source_code)?;
|
||||
Ok(module_doc.definitions)
|
||||
}
|
||||
|
||||
async fn flatten_reexports(
|
||||
&self,
|
||||
reexports: &[node::Reexport],
|
||||
referrer: &str,
|
||||
) -> Result<Vec<DocNode>, ErrBox> {
|
||||
let mut by_src: HashMap<String, Vec<node::Reexport>> = HashMap::new();
|
||||
|
||||
let mut processed_reexports: Vec<DocNode> = vec![];
|
||||
|
||||
for reexport in reexports {
|
||||
if by_src.get(&reexport.src).is_none() {
|
||||
by_src.insert(reexport.src.to_string(), vec![]);
|
||||
}
|
||||
|
||||
let bucket = by_src.get_mut(&reexport.src).unwrap();
|
||||
bucket.push(reexport.clone());
|
||||
}
|
||||
|
||||
for specifier in by_src.keys() {
|
||||
let resolved_specifier = self.loader.resolve(specifier, referrer)?;
|
||||
let doc_nodes = self.parse(&resolved_specifier.to_string()).await?;
|
||||
let reexports_for_specifier = by_src.get(specifier).unwrap();
|
||||
|
||||
for reexport in reexports_for_specifier {
|
||||
match &reexport.kind {
|
||||
node::ReexportKind::All => {
|
||||
processed_reexports.extend(doc_nodes.clone())
|
||||
}
|
||||
node::ReexportKind::Namespace(ns_name) => {
|
||||
let ns_def = NamespaceDef {
|
||||
elements: doc_nodes.clone(),
|
||||
};
|
||||
let ns_doc_node = DocNode {
|
||||
kind: DocNodeKind::Namespace,
|
||||
name: ns_name.to_string(),
|
||||
location: Location {
|
||||
filename: specifier.to_string(),
|
||||
line: 1,
|
||||
col: 0,
|
||||
},
|
||||
js_doc: None,
|
||||
namespace_def: Some(ns_def),
|
||||
enum_def: None,
|
||||
type_alias_def: None,
|
||||
interface_def: None,
|
||||
variable_def: None,
|
||||
function_def: None,
|
||||
class_def: None,
|
||||
import_def: None,
|
||||
};
|
||||
processed_reexports.push(ns_doc_node);
|
||||
}
|
||||
node::ReexportKind::Named(ident, maybe_alias) => {
|
||||
// Try to find reexport.
|
||||
// NOTE: the reexport might actually be reexport from another
|
||||
// module; for now we're skipping nested reexports.
|
||||
let maybe_doc_node =
|
||||
doc_nodes.iter().find(|node| &node.name == ident);
|
||||
|
||||
if let Some(doc_node) = maybe_doc_node {
|
||||
let doc_node = doc_node.clone();
|
||||
let doc_node = if let Some(alias) = maybe_alias {
|
||||
DocNode {
|
||||
name: alias.to_string(),
|
||||
..doc_node
|
||||
}
|
||||
} else {
|
||||
doc_node
|
||||
};
|
||||
|
||||
processed_reexports.push(doc_node);
|
||||
}
|
||||
}
|
||||
node::ReexportKind::Default => {
|
||||
// TODO: handle default export from child module
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(processed_reexports)
|
||||
}
|
||||
|
||||
pub async fn parse_with_reexports(
|
||||
&self,
|
||||
file_name: &str,
|
||||
) -> Result<Vec<DocNode>, ErrBox> {
|
||||
let source_code = self.loader.load_source_code(file_name).await?;
|
||||
|
||||
let module_doc = self.parse_module(file_name, &source_code)?;
|
||||
|
||||
let flattened_docs = if !module_doc.reexports.is_empty() {
|
||||
let mut flattenned_reexports = self
|
||||
.flatten_reexports(&module_doc.reexports, file_name)
|
||||
.await?;
|
||||
flattenned_reexports.extend(module_doc.definitions);
|
||||
flattenned_reexports
|
||||
} else {
|
||||
module_doc.definitions
|
||||
};
|
||||
|
||||
Ok(flattened_docs)
|
||||
}
|
||||
|
||||
fn get_doc_nodes_for_module_imports(
|
||||
&self,
|
||||
module_body: Vec<swc_ecmascript::ast::ModuleItem>,
|
||||
referrer: &str,
|
||||
) -> Result<Vec<DocNode>, ErrBox> {
|
||||
let mut imports = vec![];
|
||||
|
||||
for node in module_body.iter() {
|
||||
if let swc_ecmascript::ast::ModuleItem::ModuleDecl(module_decl) = node {
|
||||
if let ModuleDecl::Import(import_decl) = module_decl {
|
||||
let (js_doc, location) = self.details_for_span(import_decl.span);
|
||||
for specifier in &import_decl.specifiers {
|
||||
use swc_ecmascript::ast::ImportSpecifier::*;
|
||||
|
||||
let (name, maybe_imported_name, src) = match specifier {
|
||||
Named(named_specifier) => (
|
||||
named_specifier.local.sym.to_string(),
|
||||
named_specifier
|
||||
.imported
|
||||
.as_ref()
|
||||
.map(|ident| ident.sym.to_string())
|
||||
.or_else(|| Some(named_specifier.local.sym.to_string())),
|
||||
import_decl.src.value.to_string(),
|
||||
),
|
||||
Default(default_specifier) => (
|
||||
default_specifier.local.sym.to_string(),
|
||||
Some("default".to_string()),
|
||||
import_decl.src.value.to_string(),
|
||||
),
|
||||
Namespace(namespace_specifier) => (
|
||||
namespace_specifier.local.sym.to_string(),
|
||||
None,
|
||||
import_decl.src.value.to_string(),
|
||||
),
|
||||
};
|
||||
|
||||
let resolved_specifier = self.loader.resolve(&src, referrer)?;
|
||||
let import_def = ImportDef {
|
||||
src: resolved_specifier.to_string(),
|
||||
imported: maybe_imported_name,
|
||||
};
|
||||
|
||||
let doc_node = DocNode::import(
|
||||
name,
|
||||
location.clone(),
|
||||
js_doc.clone(),
|
||||
import_def,
|
||||
);
|
||||
|
||||
imports.push(doc_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(imports)
|
||||
}
|
||||
|
||||
pub fn get_doc_nodes_for_module_exports(
|
||||
&self,
|
||||
module_decl: &ModuleDecl,
|
||||
) -> Vec<DocNode> {
|
||||
match module_decl {
|
||||
ModuleDecl::ExportDecl(export_decl) => {
|
||||
vec![super::module::get_doc_node_for_export_decl(
|
||||
self,
|
||||
export_decl,
|
||||
)]
|
||||
}
|
||||
ModuleDecl::ExportDefaultDecl(export_default_decl) => {
|
||||
let (js_doc, location) =
|
||||
self.details_for_span(export_default_decl.span);
|
||||
let name = "default".to_string();
|
||||
|
||||
let doc_node = match &export_default_decl.decl {
|
||||
DefaultDecl::Class(class_expr) => {
|
||||
let class_def =
|
||||
crate::doc::class::class_to_class_def(self, &class_expr.class);
|
||||
DocNode::class(name, location, js_doc, class_def)
|
||||
}
|
||||
DefaultDecl::Fn(fn_expr) => {
|
||||
let function_def = crate::doc::function::function_to_function_def(
|
||||
self,
|
||||
&fn_expr.function,
|
||||
);
|
||||
DocNode::function(name, location, js_doc, function_def)
|
||||
}
|
||||
DefaultDecl::TsInterfaceDecl(interface_decl) => {
|
||||
let (_, interface_def) =
|
||||
crate::doc::interface::get_doc_for_ts_interface_decl(
|
||||
self,
|
||||
interface_decl,
|
||||
);
|
||||
DocNode::interface(name, location, js_doc, interface_def)
|
||||
}
|
||||
};
|
||||
|
||||
vec![doc_node]
|
||||
}
|
||||
ModuleDecl::ExportDefaultExpr(_export_default_expr) => vec![],
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_doc_node_for_stmt(&self, stmt: &Stmt) -> Option<DocNode> {
|
||||
match stmt {
|
||||
Stmt::Decl(decl) => self.get_doc_node_for_decl(decl),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn details_for_span(&self, span: Span) -> (Option<String>, Location) {
|
||||
let js_doc = self.js_doc_for_span(span);
|
||||
let location = self.ast_parser.get_span_location(span).into();
|
||||
(js_doc, location)
|
||||
}
|
||||
|
||||
pub fn get_doc_node_for_decl(&self, decl: &Decl) -> Option<DocNode> {
|
||||
match decl {
|
||||
Decl::Class(class_decl) => {
|
||||
if !self.private && !class_decl.declare {
|
||||
return None;
|
||||
}
|
||||
let (name, class_def) =
|
||||
super::class::get_doc_for_class_decl(self, class_decl);
|
||||
let (js_doc, location) = self.details_for_span(class_decl.class.span);
|
||||
Some(DocNode::class(name, location, js_doc, class_def))
|
||||
}
|
||||
Decl::Fn(fn_decl) => {
|
||||
if !self.private && !fn_decl.declare {
|
||||
return None;
|
||||
}
|
||||
let (name, function_def) =
|
||||
super::function::get_doc_for_fn_decl(self, fn_decl);
|
||||
let (js_doc, location) = self.details_for_span(fn_decl.function.span);
|
||||
Some(DocNode::function(name, location, js_doc, function_def))
|
||||
}
|
||||
Decl::Var(var_decl) => {
|
||||
if !self.private && !var_decl.declare {
|
||||
return None;
|
||||
}
|
||||
let (name, var_def) = super::variable::get_doc_for_var_decl(var_decl);
|
||||
let (js_doc, location) = self.details_for_span(var_decl.span);
|
||||
Some(DocNode::variable(name, location, js_doc, var_def))
|
||||
}
|
||||
Decl::TsInterface(ts_interface_decl) => {
|
||||
if !self.private && !ts_interface_decl.declare {
|
||||
return None;
|
||||
}
|
||||
let (name, interface_def) =
|
||||
super::interface::get_doc_for_ts_interface_decl(
|
||||
self,
|
||||
ts_interface_decl,
|
||||
);
|
||||
let (js_doc, location) = self.details_for_span(ts_interface_decl.span);
|
||||
Some(DocNode::interface(name, location, js_doc, interface_def))
|
||||
}
|
||||
Decl::TsTypeAlias(ts_type_alias) => {
|
||||
if !self.private && !ts_type_alias.declare {
|
||||
return None;
|
||||
}
|
||||
let (name, type_alias_def) =
|
||||
super::type_alias::get_doc_for_ts_type_alias_decl(
|
||||
self,
|
||||
ts_type_alias,
|
||||
);
|
||||
let (js_doc, location) = self.details_for_span(ts_type_alias.span);
|
||||
Some(DocNode::type_alias(name, location, js_doc, type_alias_def))
|
||||
}
|
||||
Decl::TsEnum(ts_enum) => {
|
||||
if !self.private && !ts_enum.declare {
|
||||
return None;
|
||||
}
|
||||
let (name, enum_def) =
|
||||
super::r#enum::get_doc_for_ts_enum_decl(self, ts_enum);
|
||||
let (js_doc, location) = self.details_for_span(ts_enum.span);
|
||||
Some(DocNode::r#enum(name, location, js_doc, enum_def))
|
||||
}
|
||||
Decl::TsModule(ts_module) => {
|
||||
if !self.private && !ts_module.declare {
|
||||
return None;
|
||||
}
|
||||
let (name, namespace_def) =
|
||||
super::namespace::get_doc_for_ts_module(self, ts_module);
|
||||
let (js_doc, location) = self.details_for_span(ts_module.span);
|
||||
Some(DocNode::namespace(name, location, js_doc, namespace_def))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_reexports_for_module_body(
|
||||
&self,
|
||||
module_body: Vec<swc_ecmascript::ast::ModuleItem>,
|
||||
) -> Vec<node::Reexport> {
|
||||
use swc_ecmascript::ast::ExportSpecifier::*;
|
||||
|
||||
let mut reexports: Vec<node::Reexport> = vec![];
|
||||
|
||||
for node in module_body.iter() {
|
||||
if let swc_ecmascript::ast::ModuleItem::ModuleDecl(module_decl) = node {
|
||||
let r = match module_decl {
|
||||
ModuleDecl::ExportNamed(named_export) => {
|
||||
if let Some(src) = &named_export.src {
|
||||
let src_str = src.value.to_string();
|
||||
named_export
|
||||
.specifiers
|
||||
.iter()
|
||||
.map(|export_specifier| match export_specifier {
|
||||
Namespace(ns_export) => node::Reexport {
|
||||
kind: node::ReexportKind::Namespace(
|
||||
ns_export.name.sym.to_string(),
|
||||
),
|
||||
src: src_str.to_string(),
|
||||
},
|
||||
Default(_) => node::Reexport {
|
||||
kind: node::ReexportKind::Default,
|
||||
src: src_str.to_string(),
|
||||
},
|
||||
Named(named_export) => {
|
||||
let ident = named_export.orig.sym.to_string();
|
||||
let maybe_alias =
|
||||
named_export.exported.as_ref().map(|e| e.sym.to_string());
|
||||
let kind = node::ReexportKind::Named(ident, maybe_alias);
|
||||
node::Reexport {
|
||||
kind,
|
||||
src: src_str.to_string(),
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Vec<node::Reexport>>()
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
ModuleDecl::ExportAll(export_all) => {
|
||||
let reexport = node::Reexport {
|
||||
kind: node::ReexportKind::All,
|
||||
src: export_all.src.value.to_string(),
|
||||
};
|
||||
vec![reexport]
|
||||
}
|
||||
_ => vec![],
|
||||
};
|
||||
|
||||
reexports.extend(r);
|
||||
}
|
||||
}
|
||||
|
||||
reexports
|
||||
}
|
||||
|
||||
pub fn get_doc_nodes_for_module_body(
|
||||
&self,
|
||||
module_body: Vec<swc_ecmascript::ast::ModuleItem>,
|
||||
) -> Vec<DocNode> {
|
||||
let mut doc_entries: Vec<DocNode> = vec![];
|
||||
for node in module_body.iter() {
|
||||
match node {
|
||||
swc_ecmascript::ast::ModuleItem::ModuleDecl(module_decl) => {
|
||||
doc_entries
|
||||
.extend(self.get_doc_nodes_for_module_exports(module_decl));
|
||||
}
|
||||
swc_ecmascript::ast::ModuleItem::Stmt(stmt) => {
|
||||
if let Some(doc_node) = self.get_doc_node_for_stmt(stmt) {
|
||||
doc_entries.push(doc_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
doc_entries
|
||||
}
|
||||
|
||||
pub fn js_doc_for_span(&self, span: Span) -> Option<String> {
|
||||
let comments = self.ast_parser.get_span_comments(span);
|
||||
let js_doc_comment = comments.iter().rev().find(|comment| {
|
||||
comment.kind == CommentKind::Block && comment.text.starts_with('*')
|
||||
})?;
|
||||
|
||||
let mut margin_pat = String::from("");
|
||||
if let Some(margin) = self.ast_parser.source_map.span_to_margin(span) {
|
||||
for _ in 0..margin {
|
||||
margin_pat.push(' ');
|
||||
}
|
||||
}
|
||||
|
||||
let js_doc_re = Regex::new(r#" ?\* ?"#).unwrap();
|
||||
let txt = js_doc_comment
|
||||
.text
|
||||
.split('\n')
|
||||
.map(|line| js_doc_re.replace(line, "").to_string())
|
||||
.map(|line| {
|
||||
if line.starts_with(&margin_pat) {
|
||||
line[margin_pat.len()..].to_string()
|
||||
} else {
|
||||
line
|
||||
}
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n");
|
||||
|
||||
let txt = txt.trim_start().trim_end().to_string();
|
||||
|
||||
Some(txt)
|
||||
}
|
||||
}
|
|
@ -1,426 +0,0 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
// TODO(ry) This module builds up output by appending to a string. Instead it
|
||||
// should either use a formatting trait
|
||||
// https://doc.rust-lang.org/std/fmt/index.html#formatting-traits
|
||||
// Or perhaps implement a Serializer for serde
|
||||
// https://docs.serde.rs/serde/ser/trait.Serializer.html
|
||||
|
||||
// TODO(ry) The methods in this module take ownership of the DocNodes, this is
|
||||
// unnecessary and can result in unnecessary copying. Instead they should take
|
||||
// references.
|
||||
|
||||
use crate::colors;
|
||||
use crate::doc;
|
||||
use crate::doc::display::{
|
||||
display_abstract, display_async, display_generator, Indent, SliceDisplayer,
|
||||
};
|
||||
use crate::doc::DocNodeKind;
|
||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||
|
||||
pub struct DocPrinter<'a> {
|
||||
doc_nodes: &'a [doc::DocNode],
|
||||
private: bool,
|
||||
}
|
||||
|
||||
impl<'a> DocPrinter<'a> {
|
||||
pub fn new(doc_nodes: &[doc::DocNode], private: bool) -> DocPrinter {
|
||||
DocPrinter { doc_nodes, private }
|
||||
}
|
||||
|
||||
pub fn format(&self, w: &mut Formatter<'_>) -> FmtResult {
|
||||
self.format_(w, self.doc_nodes, 0)
|
||||
}
|
||||
|
||||
fn format_(
|
||||
&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 {
|
||||
write!(
|
||||
w,
|
||||
"{}",
|
||||
colors::italic_gray(&format!(
|
||||
"Defined in {}:{}:{} \n\n",
|
||||
node.location.filename, node.location.line, node.location.col
|
||||
))
|
||||
)?;
|
||||
|
||||
self.format_signature(w, &node, indent)?;
|
||||
|
||||
let js_doc = &node.js_doc;
|
||||
if let Some(js_doc) = js_doc {
|
||||
self.format_jsdoc(w, js_doc, indent + 1)?;
|
||||
}
|
||||
writeln!(w)?;
|
||||
|
||||
match node.kind {
|
||||
DocNodeKind::Class => self.format_class(w, node)?,
|
||||
DocNodeKind::Enum => self.format_enum(w, node)?,
|
||||
DocNodeKind::Interface => self.format_interface(w, node)?,
|
||||
DocNodeKind::Namespace => self.format_namespace(w, node)?,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn kind_order(&self, kind: &doc::DocNodeKind) -> i64 {
|
||||
match kind {
|
||||
DocNodeKind::Function => 0,
|
||||
DocNodeKind::Variable => 1,
|
||||
DocNodeKind::Class => 2,
|
||||
DocNodeKind::Enum => 3,
|
||||
DocNodeKind::Interface => 4,
|
||||
DocNodeKind::TypeAlias => 5,
|
||||
DocNodeKind::Namespace => 6,
|
||||
DocNodeKind::Import => 7,
|
||||
}
|
||||
}
|
||||
|
||||
fn format_signature(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
indent: i64,
|
||||
) -> FmtResult {
|
||||
match node.kind {
|
||||
DocNodeKind::Function => self.format_function_signature(w, node, indent),
|
||||
DocNodeKind::Variable => self.format_variable_signature(w, node, indent),
|
||||
DocNodeKind::Class => self.format_class_signature(w, node, indent),
|
||||
DocNodeKind::Enum => self.format_enum_signature(w, node, indent),
|
||||
DocNodeKind::Interface => {
|
||||
self.format_interface_signature(w, node, indent)
|
||||
}
|
||||
DocNodeKind::TypeAlias => {
|
||||
self.format_type_alias_signature(w, node, indent)
|
||||
}
|
||||
DocNodeKind::Namespace => {
|
||||
self.format_namespace_signature(w, node, indent)
|
||||
}
|
||||
DocNodeKind::Import => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(SyrupThinker) this should use a JSDoc parser
|
||||
fn format_jsdoc(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
jsdoc: &str,
|
||||
indent: i64,
|
||||
) -> FmtResult {
|
||||
for line in jsdoc.lines() {
|
||||
writeln!(w, "{}{}", Indent(indent), colors::gray(&line))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn format_class(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
) -> FmtResult {
|
||||
let class_def = node.class_def.as_ref().unwrap();
|
||||
for node in &class_def.constructors {
|
||||
writeln!(w, "{}{}", Indent(1), node,)?;
|
||||
if let Some(js_doc) = &node.js_doc {
|
||||
self.format_jsdoc(w, &js_doc, 2)?;
|
||||
}
|
||||
}
|
||||
for node in class_def.properties.iter().filter(|node| {
|
||||
self.private
|
||||
|| node
|
||||
.accessibility
|
||||
.unwrap_or(swc_ecmascript::ast::Accessibility::Public)
|
||||
!= swc_ecmascript::ast::Accessibility::Private
|
||||
}) {
|
||||
writeln!(w, "{}{}", Indent(1), node,)?;
|
||||
if let Some(js_doc) = &node.js_doc {
|
||||
self.format_jsdoc(w, &js_doc, 2)?;
|
||||
}
|
||||
}
|
||||
for index_sign_def in &class_def.index_signatures {
|
||||
writeln!(w, "{}{}", Indent(1), index_sign_def)?;
|
||||
}
|
||||
for node in class_def.methods.iter().filter(|node| {
|
||||
self.private
|
||||
|| node
|
||||
.accessibility
|
||||
.unwrap_or(swc_ecmascript::ast::Accessibility::Public)
|
||||
!= swc_ecmascript::ast::Accessibility::Private
|
||||
}) {
|
||||
writeln!(w, "{}{}", Indent(1), node,)?;
|
||||
if let Some(js_doc) = &node.js_doc {
|
||||
self.format_jsdoc(w, js_doc, 2)?;
|
||||
}
|
||||
}
|
||||
writeln!(w)
|
||||
}
|
||||
|
||||
fn format_enum(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
) -> FmtResult {
|
||||
let enum_def = node.enum_def.as_ref().unwrap();
|
||||
for member in &enum_def.members {
|
||||
writeln!(w, "{}{}", Indent(1), colors::bold(&member.name))?;
|
||||
}
|
||||
writeln!(w)
|
||||
}
|
||||
|
||||
fn format_interface(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
) -> FmtResult {
|
||||
let interface_def = node.interface_def.as_ref().unwrap();
|
||||
|
||||
for property_def in &interface_def.properties {
|
||||
writeln!(w, "{}{}", Indent(1), property_def)?;
|
||||
if let Some(js_doc) = &property_def.js_doc {
|
||||
self.format_jsdoc(w, js_doc, 2)?;
|
||||
}
|
||||
}
|
||||
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)?;
|
||||
}
|
||||
}
|
||||
for index_sign_def in &interface_def.index_signatures {
|
||||
writeln!(w, "{}{}", Indent(1), index_sign_def)?;
|
||||
}
|
||||
writeln!(w)
|
||||
}
|
||||
|
||||
fn format_namespace(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
) -> FmtResult {
|
||||
let elements = &node.namespace_def.as_ref().unwrap().elements;
|
||||
for node in elements {
|
||||
self.format_signature(w, &node, 1)?;
|
||||
if let Some(js_doc) = &node.js_doc {
|
||||
self.format_jsdoc(w, js_doc, 2)?;
|
||||
}
|
||||
}
|
||||
writeln!(w)
|
||||
}
|
||||
|
||||
fn format_class_signature(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
indent: i64,
|
||||
) -> FmtResult {
|
||||
let class_def = node.class_def.as_ref().unwrap();
|
||||
write!(
|
||||
w,
|
||||
"{}{}{} {}",
|
||||
Indent(indent),
|
||||
display_abstract(class_def.is_abstract),
|
||||
colors::magenta("class"),
|
||||
colors::bold(&node.name),
|
||||
)?;
|
||||
if !class_def.type_params.is_empty() {
|
||||
write!(
|
||||
w,
|
||||
"<{}>",
|
||||
SliceDisplayer::new(&class_def.type_params, ", ", false)
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(extends) = &class_def.extends {
|
||||
write!(w, " {} {}", colors::magenta("extends"), extends)?;
|
||||
}
|
||||
if !class_def.super_type_params.is_empty() {
|
||||
write!(
|
||||
w,
|
||||
"<{}>",
|
||||
SliceDisplayer::new(&class_def.super_type_params, ", ", false)
|
||||
)?;
|
||||
}
|
||||
|
||||
if !class_def.implements.is_empty() {
|
||||
write!(
|
||||
w,
|
||||
" {} {}",
|
||||
colors::magenta("implements"),
|
||||
SliceDisplayer::new(&class_def.implements, ", ", false)
|
||||
)?;
|
||||
}
|
||||
|
||||
writeln!(w)
|
||||
}
|
||||
|
||||
fn format_enum_signature(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
indent: i64,
|
||||
) -> FmtResult {
|
||||
writeln!(
|
||||
w,
|
||||
"{}{} {}",
|
||||
Indent(indent),
|
||||
colors::magenta("enum"),
|
||||
colors::bold(&node.name)
|
||||
)
|
||||
}
|
||||
|
||||
fn format_function_signature(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
indent: i64,
|
||||
) -> FmtResult {
|
||||
let function_def = node.function_def.as_ref().unwrap();
|
||||
write!(
|
||||
w,
|
||||
"{}{}{}{} {}",
|
||||
Indent(indent),
|
||||
display_async(function_def.is_async),
|
||||
colors::magenta("function"),
|
||||
display_generator(function_def.is_generator),
|
||||
colors::bold(&node.name)
|
||||
)?;
|
||||
if !function_def.type_params.is_empty() {
|
||||
write!(
|
||||
w,
|
||||
"<{}>",
|
||||
SliceDisplayer::new(&function_def.type_params, ", ", false)
|
||||
)?;
|
||||
}
|
||||
write!(
|
||||
w,
|
||||
"({})",
|
||||
SliceDisplayer::new(&function_def.params, ", ", false)
|
||||
)?;
|
||||
if let Some(return_type) = &function_def.return_type {
|
||||
write!(w, ": {}", return_type)?;
|
||||
}
|
||||
writeln!(w)
|
||||
}
|
||||
|
||||
fn format_interface_signature(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
indent: i64,
|
||||
) -> FmtResult {
|
||||
let interface_def = node.interface_def.as_ref().unwrap();
|
||||
write!(
|
||||
w,
|
||||
"{}{} {}",
|
||||
Indent(indent),
|
||||
colors::magenta("interface"),
|
||||
colors::bold(&node.name)
|
||||
)?;
|
||||
|
||||
if !interface_def.type_params.is_empty() {
|
||||
write!(
|
||||
w,
|
||||
"<{}>",
|
||||
SliceDisplayer::new(&interface_def.type_params, ", ", false)
|
||||
)?;
|
||||
}
|
||||
|
||||
if !interface_def.extends.is_empty() {
|
||||
write!(
|
||||
w,
|
||||
" {} {}",
|
||||
colors::magenta("extends"),
|
||||
SliceDisplayer::new(&interface_def.extends, ", ", false)
|
||||
)?;
|
||||
}
|
||||
|
||||
writeln!(w)
|
||||
}
|
||||
|
||||
fn format_type_alias_signature(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
indent: i64,
|
||||
) -> FmtResult {
|
||||
let type_alias_def = node.type_alias_def.as_ref().unwrap();
|
||||
write!(
|
||||
w,
|
||||
"{}{} {}",
|
||||
Indent(indent),
|
||||
colors::magenta("type"),
|
||||
colors::bold(&node.name),
|
||||
)?;
|
||||
|
||||
if !type_alias_def.type_params.is_empty() {
|
||||
write!(
|
||||
w,
|
||||
"<{}>",
|
||||
SliceDisplayer::new(&type_alias_def.type_params, ", ", false)
|
||||
)?;
|
||||
}
|
||||
|
||||
writeln!(w, " = {}", type_alias_def.ts_type)
|
||||
}
|
||||
|
||||
fn format_namespace_signature(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
indent: i64,
|
||||
) -> FmtResult {
|
||||
writeln!(
|
||||
w,
|
||||
"{}{} {}",
|
||||
Indent(indent),
|
||||
colors::magenta("namespace"),
|
||||
colors::bold(&node.name)
|
||||
)
|
||||
}
|
||||
|
||||
fn format_variable_signature(
|
||||
&self,
|
||||
w: &mut Formatter<'_>,
|
||||
node: &doc::DocNode,
|
||||
indent: i64,
|
||||
) -> FmtResult {
|
||||
let variable_def = node.variable_def.as_ref().unwrap();
|
||||
write!(
|
||||
w,
|
||||
"{}{} {}",
|
||||
Indent(indent),
|
||||
colors::magenta(match variable_def.kind {
|
||||
swc_ecmascript::ast::VarDeclKind::Const => "const",
|
||||
swc_ecmascript::ast::VarDeclKind::Let => "let",
|
||||
swc_ecmascript::ast::VarDeclKind::Var => "var",
|
||||
}),
|
||||
colors::bold(&node.name),
|
||||
)?;
|
||||
if let Some(ts_type) = &variable_def.ts_type {
|
||||
write!(w, ": {}", ts_type)?;
|
||||
}
|
||||
writeln!(w)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Display for DocPrinter<'a> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
2002
cli/doc/tests.rs
2002
cli/doc/tests.rs
File diff suppressed because it is too large
Load diff
|
@ -1,985 +0,0 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
use super::display::{display_readonly, SliceDisplayer};
|
||||
use super::interface::expr_to_name;
|
||||
use super::params::ts_fn_param_to_param_def;
|
||||
use super::ts_type_param::maybe_type_param_decl_to_type_param_defs;
|
||||
use super::ts_type_param::TsTypeParamDef;
|
||||
use super::ParamDef;
|
||||
use crate::colors;
|
||||
use crate::doc;
|
||||
use serde::Serialize;
|
||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||
use swc_ecmascript::ast::{
|
||||
TsArrayType, TsConditionalType, TsExprWithTypeArgs, TsFnOrConstructorType,
|
||||
TsIndexedAccessType, TsKeywordType, TsLit, TsLitType, TsOptionalType,
|
||||
TsParenthesizedType, TsRestType, TsThisType, TsTupleType, TsType, TsTypeAnn,
|
||||
TsTypeLit, TsTypeOperator, TsTypeParamInstantiation, TsTypeQuery, TsTypeRef,
|
||||
TsUnionOrIntersectionType,
|
||||
};
|
||||
|
||||
// pub enum TsType {
|
||||
// * TsKeywordType(TsKeywordType),
|
||||
// * TsThisType(TsThisType),
|
||||
// * TsFnOrConstructorType(TsFnOrConstructorType),
|
||||
// * TsTypeRef(TsTypeRef),
|
||||
// * TsTypeQuery(TsTypeQuery),
|
||||
// * TsTypeLit(TsTypeLit),
|
||||
// * TsArrayType(TsArrayType),
|
||||
// * TsTupleType(TsTupleType),
|
||||
// * TsOptionalType(TsOptionalType),
|
||||
// * TsRestType(TsRestType),
|
||||
// * TsUnionOrIntersectionType(TsUnionOrIntersectionType),
|
||||
// * TsConditionalType(TsConditionalType),
|
||||
// * TsParenthesizedType(TsParenthesizedType),
|
||||
// * TsTypeOperator(TsTypeOperator),
|
||||
// * TsIndexedAccessType(TsIndexedAccessType),
|
||||
// * TsLitType(TsLitType),
|
||||
// TsInferType(TsInferType),
|
||||
// TsMappedType(TsMappedType),
|
||||
// TsTypePredicate(TsTypePredicate),
|
||||
// TsImportType(TsImportType),
|
||||
// }
|
||||
|
||||
impl Into<TsTypeDef> for &TsLitType {
|
||||
fn into(self) -> TsTypeDef {
|
||||
let (repr, lit) = match &self.lit {
|
||||
TsLit::Number(num) => (
|
||||
format!("{}", num.value),
|
||||
LiteralDef {
|
||||
kind: LiteralDefKind::Number,
|
||||
number: Some(num.value),
|
||||
string: None,
|
||||
boolean: None,
|
||||
},
|
||||
),
|
||||
TsLit::Str(str_) => (
|
||||
str_.value.to_string(),
|
||||
LiteralDef {
|
||||
kind: LiteralDefKind::String,
|
||||
number: None,
|
||||
string: Some(str_.value.to_string()),
|
||||
boolean: None,
|
||||
},
|
||||
),
|
||||
TsLit::Tpl(tpl) => {
|
||||
// A template literal in a type is not allowed to have
|
||||
// expressions, so there will only be one quasi.
|
||||
let quasi = tpl.quasis.get(0).expect("Expected tpl to have a quasi.");
|
||||
let text = quasi.raw.value.to_string();
|
||||
(
|
||||
text.clone(),
|
||||
LiteralDef {
|
||||
kind: LiteralDefKind::String, // semantically the same
|
||||
number: None,
|
||||
string: Some(text),
|
||||
boolean: None,
|
||||
},
|
||||
)
|
||||
}
|
||||
TsLit::Bool(bool_) => (
|
||||
bool_.value.to_string(),
|
||||
LiteralDef {
|
||||
kind: LiteralDefKind::Boolean,
|
||||
number: None,
|
||||
string: None,
|
||||
boolean: Some(bool_.value),
|
||||
},
|
||||
),
|
||||
};
|
||||
|
||||
TsTypeDef {
|
||||
repr,
|
||||
kind: Some(TsTypeDefKind::Literal),
|
||||
literal: Some(lit),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<TsTypeDef> for &TsArrayType {
|
||||
fn into(self) -> TsTypeDef {
|
||||
let ts_type_def: TsTypeDef = (&*self.elem_type).into();
|
||||
|
||||
TsTypeDef {
|
||||
array: Some(Box::new(ts_type_def)),
|
||||
kind: Some(TsTypeDefKind::Array),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<TsTypeDef> for &TsTupleType {
|
||||
fn into(self) -> TsTypeDef {
|
||||
let mut type_defs = vec![];
|
||||
|
||||
for type_box in &self.elem_types {
|
||||
let ts_type: &TsType = &type_box.ty;
|
||||
let def: TsTypeDef = ts_type.into();
|
||||
type_defs.push(def)
|
||||
}
|
||||
|
||||
TsTypeDef {
|
||||
tuple: Some(type_defs),
|
||||
kind: Some(TsTypeDefKind::Tuple),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<TsTypeDef> for &TsUnionOrIntersectionType {
|
||||
fn into(self) -> TsTypeDef {
|
||||
use swc_ecmascript::ast::TsUnionOrIntersectionType::*;
|
||||
|
||||
match self {
|
||||
TsUnionType(union_type) => {
|
||||
let mut types_union = vec![];
|
||||
|
||||
for type_box in &union_type.types {
|
||||
let ts_type: &TsType = &(*type_box);
|
||||
let def: TsTypeDef = ts_type.into();
|
||||
types_union.push(def);
|
||||
}
|
||||
|
||||
TsTypeDef {
|
||||
union: Some(types_union),
|
||||
kind: Some(TsTypeDefKind::Union),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
TsIntersectionType(intersection_type) => {
|
||||
let mut types_intersection = vec![];
|
||||
|
||||
for type_box in &intersection_type.types {
|
||||
let ts_type: &TsType = &(*type_box);
|
||||
let def: TsTypeDef = ts_type.into();
|
||||
types_intersection.push(def);
|
||||
}
|
||||
|
||||
TsTypeDef {
|
||||
intersection: Some(types_intersection),
|
||||
kind: Some(TsTypeDefKind::Intersection),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<TsTypeDef> for &TsKeywordType {
|
||||
fn into(self) -> TsTypeDef {
|
||||
use swc_ecmascript::ast::TsKeywordTypeKind::*;
|
||||
|
||||
let keyword_str = match self.kind {
|
||||
TsAnyKeyword => "any",
|
||||
TsUnknownKeyword => "unknown",
|
||||
TsNumberKeyword => "number",
|
||||
TsObjectKeyword => "object",
|
||||
TsBooleanKeyword => "boolean",
|
||||
TsBigIntKeyword => "bigint",
|
||||
TsStringKeyword => "string",
|
||||
TsSymbolKeyword => "symbol",
|
||||
TsVoidKeyword => "void",
|
||||
TsUndefinedKeyword => "undefined",
|
||||
TsNullKeyword => "null",
|
||||
TsNeverKeyword => "never",
|
||||
};
|
||||
|
||||
TsTypeDef {
|
||||
repr: keyword_str.to_string(),
|
||||
kind: Some(TsTypeDefKind::Keyword),
|
||||
keyword: Some(keyword_str.to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<TsTypeDef> for &TsTypeOperator {
|
||||
fn into(self) -> TsTypeDef {
|
||||
let ts_type = (&*self.type_ann).into();
|
||||
let type_operator_def = TsTypeOperatorDef {
|
||||
operator: self.op.as_str().to_string(),
|
||||
ts_type,
|
||||
};
|
||||
|
||||
TsTypeDef {
|
||||
type_operator: Some(Box::new(type_operator_def)),
|
||||
kind: Some(TsTypeDefKind::TypeOperator),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<TsTypeDef> for &TsParenthesizedType {
|
||||
fn into(self) -> TsTypeDef {
|
||||
let ts_type = (&*self.type_ann).into();
|
||||
|
||||
TsTypeDef {
|
||||
parenthesized: Some(Box::new(ts_type)),
|
||||
kind: Some(TsTypeDefKind::Parenthesized),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<TsTypeDef> for &TsRestType {
|
||||
fn into(self) -> TsTypeDef {
|
||||
let ts_type = (&*self.type_ann).into();
|
||||
|
||||
TsTypeDef {
|
||||
rest: Some(Box::new(ts_type)),
|
||||
kind: Some(TsTypeDefKind::Rest),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<TsTypeDef> for &TsOptionalType {
|
||||
fn into(self) -> TsTypeDef {
|
||||
let ts_type = (&*self.type_ann).into();
|
||||
|
||||
TsTypeDef {
|
||||
optional: Some(Box::new(ts_type)),
|
||||
kind: Some(TsTypeDefKind::Optional),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<TsTypeDef> for &TsThisType {
|
||||
fn into(self) -> TsTypeDef {
|
||||
TsTypeDef {
|
||||
repr: "this".to_string(),
|
||||
this: Some(true),
|
||||
kind: Some(TsTypeDefKind::This),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ts_entity_name_to_name(
|
||||
entity_name: &swc_ecmascript::ast::TsEntityName,
|
||||
) -> String {
|
||||
use swc_ecmascript::ast::TsEntityName::*;
|
||||
|
||||
match entity_name {
|
||||
Ident(ident) => ident.sym.to_string(),
|
||||
TsQualifiedName(ts_qualified_name) => {
|
||||
let left = ts_entity_name_to_name(&ts_qualified_name.left);
|
||||
let right = ts_qualified_name.right.sym.to_string();
|
||||
format!("{}.{}", left, right)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<TsTypeDef> for &TsTypeQuery {
|
||||
fn into(self) -> TsTypeDef {
|
||||
use swc_ecmascript::ast::TsTypeQueryExpr::*;
|
||||
|
||||
let type_name = match &self.expr_name {
|
||||
TsEntityName(entity_name) => ts_entity_name_to_name(&*entity_name),
|
||||
Import(import_type) => import_type.arg.value.to_string(),
|
||||
};
|
||||
|
||||
TsTypeDef {
|
||||
repr: type_name.to_string(),
|
||||
type_query: Some(type_name),
|
||||
kind: Some(TsTypeDefKind::TypeQuery),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<TsTypeDef> for &TsTypeRef {
|
||||
fn into(self) -> TsTypeDef {
|
||||
let type_name = ts_entity_name_to_name(&self.type_name);
|
||||
|
||||
let type_params = if let Some(type_params_inst) = &self.type_params {
|
||||
let mut ts_type_defs = vec![];
|
||||
|
||||
for type_box in &type_params_inst.params {
|
||||
let ts_type: &TsType = &(*type_box);
|
||||
let def: TsTypeDef = ts_type.into();
|
||||
ts_type_defs.push(def);
|
||||
}
|
||||
|
||||
Some(ts_type_defs)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
TsTypeDef {
|
||||
repr: type_name.clone(),
|
||||
type_ref: Some(TsTypeRefDef {
|
||||
type_name,
|
||||
type_params,
|
||||
}),
|
||||
kind: Some(TsTypeDefKind::TypeRef),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<TsTypeDef> for &TsExprWithTypeArgs {
|
||||
fn into(self) -> TsTypeDef {
|
||||
let type_name = ts_entity_name_to_name(&self.expr);
|
||||
|
||||
let type_params = if let Some(type_params_inst) = &self.type_args {
|
||||
let mut ts_type_defs = vec![];
|
||||
|
||||
for type_box in &type_params_inst.params {
|
||||
let ts_type: &TsType = &(*type_box);
|
||||
let def: TsTypeDef = ts_type.into();
|
||||
ts_type_defs.push(def);
|
||||
}
|
||||
|
||||
Some(ts_type_defs)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
TsTypeDef {
|
||||
repr: type_name.clone(),
|
||||
type_ref: Some(TsTypeRefDef {
|
||||
type_name,
|
||||
type_params,
|
||||
}),
|
||||
kind: Some(TsTypeDefKind::TypeRef),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<TsTypeDef> for &TsIndexedAccessType {
|
||||
fn into(self) -> TsTypeDef {
|
||||
let indexed_access_def = TsIndexedAccessDef {
|
||||
readonly: self.readonly,
|
||||
obj_type: Box::new((&*self.obj_type).into()),
|
||||
index_type: Box::new((&*self.index_type).into()),
|
||||
};
|
||||
|
||||
TsTypeDef {
|
||||
indexed_access: Some(indexed_access_def),
|
||||
kind: Some(TsTypeDefKind::IndexedAccess),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<TsTypeDef> for &TsTypeLit {
|
||||
fn into(self) -> TsTypeDef {
|
||||
let mut methods = vec![];
|
||||
let mut properties = vec![];
|
||||
let mut call_signatures = vec![];
|
||||
let mut index_signatures = vec![];
|
||||
|
||||
for type_element in &self.members {
|
||||
use swc_ecmascript::ast::TsTypeElement::*;
|
||||
|
||||
match &type_element {
|
||||
TsMethodSignature(ts_method_sig) => {
|
||||
let mut params = vec![];
|
||||
|
||||
for param in &ts_method_sig.params {
|
||||
let param_def = ts_fn_param_to_param_def(param, None);
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
let maybe_return_type = ts_method_sig
|
||||
.type_ann
|
||||
.as_ref()
|
||||
.map(|rt| (&*rt.type_ann).into());
|
||||
|
||||
let type_params = maybe_type_param_decl_to_type_param_defs(
|
||||
ts_method_sig.type_params.as_ref(),
|
||||
);
|
||||
let name = expr_to_name(&*ts_method_sig.key);
|
||||
let method_def = LiteralMethodDef {
|
||||
name,
|
||||
params,
|
||||
return_type: maybe_return_type,
|
||||
type_params,
|
||||
};
|
||||
methods.push(method_def);
|
||||
}
|
||||
TsPropertySignature(ts_prop_sig) => {
|
||||
let name = expr_to_name(&*ts_prop_sig.key);
|
||||
|
||||
let mut params = vec![];
|
||||
|
||||
for param in &ts_prop_sig.params {
|
||||
let param_def = ts_fn_param_to_param_def(param, None);
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
let ts_type = ts_prop_sig
|
||||
.type_ann
|
||||
.as_ref()
|
||||
.map(|rt| (&*rt.type_ann).into());
|
||||
|
||||
let type_params = maybe_type_param_decl_to_type_param_defs(
|
||||
ts_prop_sig.type_params.as_ref(),
|
||||
);
|
||||
let prop_def = LiteralPropertyDef {
|
||||
name,
|
||||
params,
|
||||
ts_type,
|
||||
computed: ts_prop_sig.computed,
|
||||
optional: ts_prop_sig.optional,
|
||||
type_params,
|
||||
};
|
||||
properties.push(prop_def);
|
||||
}
|
||||
TsCallSignatureDecl(ts_call_sig) => {
|
||||
let mut params = vec![];
|
||||
for param in &ts_call_sig.params {
|
||||
let param_def = ts_fn_param_to_param_def(param, None);
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
let ts_type = ts_call_sig
|
||||
.type_ann
|
||||
.as_ref()
|
||||
.map(|rt| (&*rt.type_ann).into());
|
||||
|
||||
let type_params = maybe_type_param_decl_to_type_param_defs(
|
||||
ts_call_sig.type_params.as_ref(),
|
||||
);
|
||||
|
||||
let call_sig_def = LiteralCallSignatureDef {
|
||||
params,
|
||||
ts_type,
|
||||
type_params,
|
||||
};
|
||||
call_signatures.push(call_sig_def);
|
||||
}
|
||||
TsIndexSignature(ts_index_sig) => {
|
||||
let mut params = vec![];
|
||||
for param in &ts_index_sig.params {
|
||||
let param_def = ts_fn_param_to_param_def(param, None);
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
let ts_type = ts_index_sig
|
||||
.type_ann
|
||||
.as_ref()
|
||||
.map(|rt| (&*rt.type_ann).into());
|
||||
|
||||
let index_sig_def = LiteralIndexSignatureDef {
|
||||
readonly: ts_index_sig.readonly,
|
||||
params,
|
||||
ts_type,
|
||||
};
|
||||
index_signatures.push(index_sig_def);
|
||||
}
|
||||
// TODO:
|
||||
TsConstructSignatureDecl(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
let type_literal = TsTypeLiteralDef {
|
||||
methods,
|
||||
properties,
|
||||
call_signatures,
|
||||
index_signatures,
|
||||
};
|
||||
|
||||
TsTypeDef {
|
||||
kind: Some(TsTypeDefKind::TypeLiteral),
|
||||
type_literal: Some(type_literal),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<TsTypeDef> for &TsConditionalType {
|
||||
fn into(self) -> TsTypeDef {
|
||||
let conditional_type_def = TsConditionalDef {
|
||||
check_type: Box::new((&*self.check_type).into()),
|
||||
extends_type: Box::new((&*self.extends_type).into()),
|
||||
true_type: Box::new((&*self.true_type).into()),
|
||||
false_type: Box::new((&*self.false_type).into()),
|
||||
};
|
||||
|
||||
TsTypeDef {
|
||||
kind: Some(TsTypeDefKind::Conditional),
|
||||
conditional_type: Some(conditional_type_def),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<TsTypeDef> for &TsFnOrConstructorType {
|
||||
fn into(self) -> TsTypeDef {
|
||||
use swc_ecmascript::ast::TsFnOrConstructorType::*;
|
||||
|
||||
let fn_def = match self {
|
||||
TsFnType(ts_fn_type) => {
|
||||
let mut params = vec![];
|
||||
|
||||
for param in &ts_fn_type.params {
|
||||
let param_def = ts_fn_param_to_param_def(param, None);
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
let type_params = maybe_type_param_decl_to_type_param_defs(
|
||||
ts_fn_type.type_params.as_ref(),
|
||||
);
|
||||
|
||||
TsFnOrConstructorDef {
|
||||
constructor: false,
|
||||
ts_type: ts_type_ann_to_def(&ts_fn_type.type_ann),
|
||||
params,
|
||||
type_params,
|
||||
}
|
||||
}
|
||||
TsConstructorType(ctor_type) => {
|
||||
let mut params = vec![];
|
||||
|
||||
for param in &ctor_type.params {
|
||||
let param_def = ts_fn_param_to_param_def(param, None);
|
||||
params.push(param_def);
|
||||
}
|
||||
|
||||
let type_params = maybe_type_param_decl_to_type_param_defs(
|
||||
ctor_type.type_params.as_ref(),
|
||||
);
|
||||
TsFnOrConstructorDef {
|
||||
constructor: true,
|
||||
ts_type: ts_type_ann_to_def(&ctor_type.type_ann),
|
||||
params,
|
||||
type_params,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TsTypeDef {
|
||||
kind: Some(TsTypeDefKind::FnOrConstructor),
|
||||
fn_or_constructor: Some(Box::new(fn_def)),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<TsTypeDef> for &TsType {
|
||||
fn into(self) -> TsTypeDef {
|
||||
use swc_ecmascript::ast::TsType::*;
|
||||
|
||||
match self {
|
||||
TsKeywordType(ref keyword_type) => keyword_type.into(),
|
||||
TsLitType(ref lit_type) => lit_type.into(),
|
||||
TsTypeRef(ref type_ref) => type_ref.into(),
|
||||
TsUnionOrIntersectionType(union_or_inter) => union_or_inter.into(),
|
||||
TsArrayType(array_type) => array_type.into(),
|
||||
TsTupleType(tuple_type) => tuple_type.into(),
|
||||
TsTypeOperator(type_op_type) => type_op_type.into(),
|
||||
TsParenthesizedType(paren_type) => paren_type.into(),
|
||||
TsRestType(rest_type) => rest_type.into(),
|
||||
TsOptionalType(optional_type) => optional_type.into(),
|
||||
TsTypeQuery(type_query) => type_query.into(),
|
||||
TsThisType(this_type) => this_type.into(),
|
||||
TsFnOrConstructorType(fn_or_con_type) => fn_or_con_type.into(),
|
||||
TsConditionalType(conditional_type) => conditional_type.into(),
|
||||
TsIndexedAccessType(indexed_access_type) => indexed_access_type.into(),
|
||||
TsTypeLit(type_literal) => type_literal.into(),
|
||||
_ => TsTypeDef {
|
||||
repr: "<UNIMPLEMENTED>".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TsTypeRefDef {
|
||||
pub type_params: Option<Vec<TsTypeDef>>,
|
||||
pub type_name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum LiteralDefKind {
|
||||
Number,
|
||||
String,
|
||||
Boolean,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LiteralDef {
|
||||
pub kind: LiteralDefKind,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub number: Option<f64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub string: Option<String>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub boolean: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TsTypeOperatorDef {
|
||||
pub operator: String,
|
||||
pub ts_type: TsTypeDef,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TsFnOrConstructorDef {
|
||||
pub constructor: bool,
|
||||
pub ts_type: TsTypeDef,
|
||||
pub params: Vec<ParamDef>,
|
||||
pub type_params: Vec<TsTypeParamDef>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TsConditionalDef {
|
||||
pub check_type: Box<TsTypeDef>,
|
||||
pub extends_type: Box<TsTypeDef>,
|
||||
pub true_type: Box<TsTypeDef>,
|
||||
pub false_type: Box<TsTypeDef>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TsIndexedAccessDef {
|
||||
pub readonly: bool,
|
||||
pub obj_type: Box<TsTypeDef>,
|
||||
pub index_type: Box<TsTypeDef>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LiteralMethodDef {
|
||||
pub name: String,
|
||||
pub params: Vec<ParamDef>,
|
||||
pub return_type: Option<TsTypeDef>,
|
||||
pub type_params: Vec<TsTypeParamDef>,
|
||||
}
|
||||
|
||||
impl Display for LiteralMethodDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(
|
||||
f,
|
||||
"{}({})",
|
||||
self.name,
|
||||
SliceDisplayer::new(&self.params, ", ", false)
|
||||
)?;
|
||||
if let Some(return_type) = &self.return_type {
|
||||
write!(f, ": {}", return_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LiteralPropertyDef {
|
||||
pub name: String,
|
||||
pub params: Vec<ParamDef>,
|
||||
pub computed: bool,
|
||||
pub optional: bool,
|
||||
pub ts_type: Option<TsTypeDef>,
|
||||
pub type_params: Vec<TsTypeParamDef>,
|
||||
}
|
||||
|
||||
impl Display for LiteralPropertyDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(f, "{}", self.name)?;
|
||||
if let Some(ts_type) = &self.ts_type {
|
||||
write!(f, ": {}", ts_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LiteralCallSignatureDef {
|
||||
pub params: Vec<ParamDef>,
|
||||
pub ts_type: Option<TsTypeDef>,
|
||||
pub type_params: Vec<TsTypeParamDef>,
|
||||
}
|
||||
|
||||
impl Display for LiteralCallSignatureDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(f, "({})", SliceDisplayer::new(&self.params, ", ", false))?;
|
||||
if let Some(ts_type) = &self.ts_type {
|
||||
write!(f, ": {}", ts_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LiteralIndexSignatureDef {
|
||||
pub readonly: bool,
|
||||
pub params: Vec<ParamDef>,
|
||||
pub ts_type: Option<TsTypeDef>,
|
||||
}
|
||||
|
||||
impl Display for LiteralIndexSignatureDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(
|
||||
f,
|
||||
"{}[{}]",
|
||||
display_readonly(self.readonly),
|
||||
SliceDisplayer::new(&self.params, ", ", false)
|
||||
)?;
|
||||
if let Some(ts_type) = &self.ts_type {
|
||||
write!(f, ": {}", ts_type)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TsTypeLiteralDef {
|
||||
pub methods: Vec<LiteralMethodDef>,
|
||||
pub properties: Vec<LiteralPropertyDef>,
|
||||
pub call_signatures: Vec<LiteralCallSignatureDef>,
|
||||
pub index_signatures: Vec<LiteralIndexSignatureDef>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum TsTypeDefKind {
|
||||
Keyword,
|
||||
Literal,
|
||||
TypeRef,
|
||||
Union,
|
||||
Intersection,
|
||||
Array,
|
||||
Tuple,
|
||||
TypeOperator,
|
||||
Parenthesized,
|
||||
Rest,
|
||||
Optional,
|
||||
TypeQuery,
|
||||
This,
|
||||
FnOrConstructor,
|
||||
Conditional,
|
||||
IndexedAccess,
|
||||
TypeLiteral,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TsTypeDef {
|
||||
pub repr: String,
|
||||
|
||||
pub kind: Option<TsTypeDefKind>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub keyword: Option<String>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub literal: Option<LiteralDef>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub type_ref: Option<TsTypeRefDef>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub union: Option<Vec<TsTypeDef>>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub intersection: Option<Vec<TsTypeDef>>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub array: Option<Box<TsTypeDef>>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tuple: Option<Vec<TsTypeDef>>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub type_operator: Option<Box<TsTypeOperatorDef>>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub parenthesized: Option<Box<TsTypeDef>>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub rest: Option<Box<TsTypeDef>>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub optional: Option<Box<TsTypeDef>>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub type_query: Option<String>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub this: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub fn_or_constructor: Option<Box<TsFnOrConstructorDef>>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub conditional_type: Option<TsConditionalDef>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub indexed_access: Option<TsIndexedAccessDef>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub type_literal: Option<TsTypeLiteralDef>,
|
||||
}
|
||||
|
||||
pub fn ts_type_ann_to_def(type_ann: &TsTypeAnn) -> TsTypeDef {
|
||||
use swc_ecmascript::ast::TsType::*;
|
||||
|
||||
match &*type_ann.type_ann {
|
||||
TsKeywordType(keyword_type) => keyword_type.into(),
|
||||
TsLitType(lit_type) => lit_type.into(),
|
||||
TsTypeRef(type_ref) => type_ref.into(),
|
||||
TsUnionOrIntersectionType(union_or_inter) => union_or_inter.into(),
|
||||
TsArrayType(array_type) => array_type.into(),
|
||||
TsTupleType(tuple_type) => tuple_type.into(),
|
||||
TsTypeOperator(type_op_type) => type_op_type.into(),
|
||||
TsParenthesizedType(paren_type) => paren_type.into(),
|
||||
TsRestType(rest_type) => rest_type.into(),
|
||||
TsOptionalType(optional_type) => optional_type.into(),
|
||||
TsTypeQuery(type_query) => type_query.into(),
|
||||
TsThisType(this_type) => this_type.into(),
|
||||
TsFnOrConstructorType(fn_or_con_type) => fn_or_con_type.into(),
|
||||
TsConditionalType(conditional_type) => conditional_type.into(),
|
||||
TsIndexedAccessType(indexed_access_type) => indexed_access_type.into(),
|
||||
TsTypeLit(type_literal) => type_literal.into(),
|
||||
_ => TsTypeDef {
|
||||
repr: "<TODO>".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
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![]
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
use super::ts_type::TsTypeDef;
|
||||
use serde::Serialize;
|
||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||
use swc_ecmascript::ast::TsTypeParam;
|
||||
use swc_ecmascript::ast::TsTypeParamDecl;
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TsTypeParamDef {
|
||||
pub name: String,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub constraint: Option<TsTypeDef>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub default: Option<TsTypeDef>,
|
||||
}
|
||||
|
||||
impl Display for TsTypeParamDef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(f, "{}", self.name)?;
|
||||
if let Some(constraint) = &self.constraint {
|
||||
write!(f, " extends {}", constraint)?;
|
||||
}
|
||||
if let Some(default) = &self.default {
|
||||
write!(f, " = {}", default)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<TsTypeParamDef> for &TsTypeParam {
|
||||
fn into(self) -> TsTypeParamDef {
|
||||
let name = self.name.sym.to_string();
|
||||
let constraint: Option<TsTypeDef> =
|
||||
if let Some(ts_type) = self.constraint.as_ref() {
|
||||
let type_def: TsTypeDef = (&**ts_type).into();
|
||||
Some(type_def)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let default: Option<TsTypeDef> =
|
||||
if let Some(ts_type) = self.default.as_ref() {
|
||||
let type_def: TsTypeDef = (&**ts_type).into();
|
||||
Some(type_def)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
TsTypeParamDef {
|
||||
name,
|
||||
constraint,
|
||||
default,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maybe_type_param_decl_to_type_param_defs(
|
||||
maybe_type_param_decl: Option<&TsTypeParamDecl>,
|
||||
) -> Vec<TsTypeParamDef> {
|
||||
if let Some(type_params_decl) = maybe_type_param_decl {
|
||||
type_params_decl
|
||||
.params
|
||||
.iter()
|
||||
.map(|type_param| type_param.into())
|
||||
.collect::<Vec<TsTypeParamDef>>()
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
use super::parser::DocParser;
|
||||
use super::ts_type::TsTypeDef;
|
||||
use super::ts_type_param::maybe_type_param_decl_to_type_param_defs;
|
||||
use super::ts_type_param::TsTypeParamDef;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TypeAliasDef {
|
||||
pub ts_type: TsTypeDef,
|
||||
pub type_params: Vec<TsTypeParamDef>,
|
||||
}
|
||||
|
||||
pub fn get_doc_for_ts_type_alias_decl(
|
||||
_doc_parser: &DocParser,
|
||||
type_alias_decl: &swc_ecmascript::ast::TsTypeAliasDecl,
|
||||
) -> (String, TypeAliasDef) {
|
||||
let alias_name = type_alias_decl.id.sym.to_string();
|
||||
let ts_type = type_alias_decl.type_ann.as_ref().into();
|
||||
let type_params = maybe_type_param_decl_to_type_param_defs(
|
||||
type_alias_decl.type_params.as_ref(),
|
||||
);
|
||||
let type_alias_def = TypeAliasDef {
|
||||
ts_type,
|
||||
type_params,
|
||||
};
|
||||
|
||||
(alias_name, type_alias_def)
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
use serde::Serialize;
|
||||
|
||||
use super::ts_type::ts_type_ann_to_def;
|
||||
use super::ts_type::TsTypeDef;
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct VariableDef {
|
||||
pub ts_type: Option<TsTypeDef>,
|
||||
pub kind: swc_ecmascript::ast::VarDeclKind,
|
||||
}
|
||||
|
||||
// TODO: change this function to return Vec<(String, VariableDef)> as single
|
||||
// var declaration can have multiple declarators
|
||||
pub fn get_doc_for_var_decl(
|
||||
var_decl: &swc_ecmascript::ast::VarDecl,
|
||||
) -> (String, VariableDef) {
|
||||
assert!(!var_decl.decls.is_empty());
|
||||
let var_declarator = var_decl.decls.get(0).unwrap();
|
||||
let var_name = match &var_declarator.name {
|
||||
swc_ecmascript::ast::Pat::Ident(ident) => ident.sym.to_string(),
|
||||
_ => "<TODO>".to_string(),
|
||||
};
|
||||
|
||||
let maybe_ts_type = match &var_declarator.name {
|
||||
swc_ecmascript::ast::Pat::Ident(ident) => {
|
||||
ident.type_ann.as_ref().map(|rt| ts_type_ann_to_def(rt))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let variable_def = VariableDef {
|
||||
ts_type: maybe_ts_type,
|
||||
kind: var_decl.kind,
|
||||
};
|
||||
|
||||
(var_name, variable_def)
|
||||
}
|
|
@ -313,8 +313,8 @@ fn thread_safe() {
|
|||
|
||||
#[test]
|
||||
fn test_should_allow_js() {
|
||||
use crate::doc::Location;
|
||||
use crate::module_graph::ImportDescriptor;
|
||||
use crate::swc_util::Location;
|
||||
|
||||
assert!(should_allow_js(&[
|
||||
&ModuleGraphFile {
|
||||
|
|
58
cli/main.rs
58
cli/main.rs
|
@ -29,7 +29,6 @@ pub mod deno_dir;
|
|||
pub mod diagnostics;
|
||||
mod diff;
|
||||
mod disk_cache;
|
||||
mod doc;
|
||||
mod file_fetcher;
|
||||
pub mod flags;
|
||||
mod flags_allow_net;
|
||||
|
@ -69,14 +68,13 @@ pub mod version;
|
|||
mod web_worker;
|
||||
pub mod worker;
|
||||
|
||||
use crate::doc::parser::DocFileLoader;
|
||||
use crate::file_fetcher::map_file_extension;
|
||||
use crate::file_fetcher::SourceFile;
|
||||
use crate::file_fetcher::SourceFileFetcher;
|
||||
use crate::file_fetcher::TextDocument;
|
||||
use crate::fs as deno_fs;
|
||||
use crate::global_state::GlobalState;
|
||||
use crate::msg::MediaType;
|
||||
use crate::op_error::OpError;
|
||||
use crate::permissions::Permissions;
|
||||
use crate::tsc::TargetLib;
|
||||
use crate::worker::MainWorker;
|
||||
|
@ -85,6 +83,8 @@ use deno_core::Deps;
|
|||
use deno_core::ErrBox;
|
||||
use deno_core::EsIsolate;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_doc as doc;
|
||||
use deno_doc::parser::DocFileLoader;
|
||||
use flags::DenoSubcommand;
|
||||
use flags::Flags;
|
||||
use futures::future::FutureExt;
|
||||
|
@ -505,19 +505,39 @@ async fn doc_command(
|
|||
let source_file = source_file.unwrap_or_else(|| "--builtin".to_string());
|
||||
|
||||
impl DocFileLoader for SourceFileFetcher {
|
||||
fn resolve(
|
||||
&self,
|
||||
specifier: &str,
|
||||
referrer: &str,
|
||||
) -> Result<String, doc::DocError> {
|
||||
ModuleSpecifier::resolve_import(specifier, referrer)
|
||||
.map(|specifier| specifier.to_string())
|
||||
.map_err(|e| doc::DocError::Resolve(e.to_string()))
|
||||
}
|
||||
|
||||
fn load_source_code(
|
||||
&self,
|
||||
specifier: &str,
|
||||
) -> Pin<Box<dyn Future<Output = Result<String, OpError>>>> {
|
||||
) -> Pin<Box<dyn Future<Output = Result<String, doc::DocError>>>> {
|
||||
let fetcher = self.clone();
|
||||
let specifier = specifier.to_string();
|
||||
let specifier = ModuleSpecifier::resolve_url_or_path(specifier)
|
||||
.expect("Expected valid specifier");
|
||||
async move {
|
||||
let specifier = ModuleSpecifier::resolve_url_or_path(&specifier)
|
||||
.map_err(OpError::from)?;
|
||||
let source_file = fetcher
|
||||
.fetch_source_file(&specifier, None, Permissions::allow_all())
|
||||
.await?;
|
||||
source_file.source_code.to_string().map_err(OpError::from)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
doc::DocError::Io(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
e.to_string(),
|
||||
))
|
||||
})?;
|
||||
source_file.source_code.to_string().map_err(|e| {
|
||||
doc::DocError::Io(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
e.to_string(),
|
||||
))
|
||||
})
|
||||
}
|
||||
.boxed_local()
|
||||
}
|
||||
|
@ -525,14 +545,20 @@ async fn doc_command(
|
|||
|
||||
let loader = Box::new(global_state.file_fetcher.clone());
|
||||
let doc_parser = doc::DocParser::new(loader, private);
|
||||
let media_type = map_file_extension(&PathBuf::from(&source_file));
|
||||
let syntax = swc_util::get_syntax_for_media_type(media_type);
|
||||
|
||||
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",
|
||||
syntax,
|
||||
get_types(flags.unstable).as_str(),
|
||||
)
|
||||
} else {
|
||||
let module_specifier =
|
||||
ModuleSpecifier::resolve_url_or_path(&source_file).unwrap();
|
||||
doc_parser
|
||||
.parse_with_reexports(&module_specifier.to_string())
|
||||
.parse_with_reexports(&module_specifier.to_string(), syntax)
|
||||
.await
|
||||
};
|
||||
|
||||
|
@ -555,9 +581,15 @@ async fn doc_command(
|
|||
eprintln!("Node {} was not found!", filter);
|
||||
std::process::exit(1);
|
||||
}
|
||||
format!("{}", doc::DocPrinter::new(&nodes, private))
|
||||
format!(
|
||||
"{}",
|
||||
doc::DocPrinter::new(&nodes, colors::use_color(), private)
|
||||
)
|
||||
} else {
|
||||
format!("{}", doc::DocPrinter::new(&doc_nodes, private))
|
||||
format!(
|
||||
"{}",
|
||||
doc::DocPrinter::new(&doc_nodes, colors::use_color(), private)
|
||||
)
|
||||
};
|
||||
|
||||
write_to_stdout_ignore_sigpipe(details.as_bytes()).map_err(ErrBox::from)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
use crate::checksum;
|
||||
use crate::doc::Location;
|
||||
use crate::file_fetcher::map_file_extension;
|
||||
use crate::file_fetcher::SourceFile;
|
||||
use crate::file_fetcher::SourceFileFetcher;
|
||||
|
@ -8,6 +7,7 @@ use crate::import_map::ImportMap;
|
|||
use crate::msg::MediaType;
|
||||
use crate::op_error::OpError;
|
||||
use crate::permissions::Permissions;
|
||||
use crate::swc_util::Location;
|
||||
use crate::tsc::pre_process_file;
|
||||
use crate::tsc::ImportDesc;
|
||||
use crate::tsc::TsReferenceDesc;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
use crate::msg::MediaType;
|
||||
use deno_core::ErrBox;
|
||||
use serde::Serialize;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
|
@ -31,6 +32,31 @@ use swc_ecmascript::transforms::fixer;
|
|||
use swc_ecmascript::transforms::typescript;
|
||||
use swc_ecmascript::visit::FoldWith;
|
||||
|
||||
#[derive(Debug, Serialize, Clone, PartialEq)]
|
||||
pub struct Location {
|
||||
pub filename: String,
|
||||
pub line: usize,
|
||||
pub col: usize,
|
||||
}
|
||||
|
||||
impl Into<Location> for swc_common::Loc {
|
||||
fn into(self) -> Location {
|
||||
use swc_common::FileName::*;
|
||||
|
||||
let filename = match &self.file.name {
|
||||
Real(path_buf) => path_buf.to_string_lossy().to_string(),
|
||||
Custom(str_) => str_.to_string(),
|
||||
_ => panic!("invalid filename"),
|
||||
};
|
||||
|
||||
Location {
|
||||
filename,
|
||||
line: self.line,
|
||||
col: self.col_display,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct DummyHandler;
|
||||
|
||||
impl swc_ecmascript::codegen::Handlers for DummyHandler {}
|
||||
|
|
|
@ -3,7 +3,6 @@ use crate::colors;
|
|||
use crate::diagnostics::Diagnostic;
|
||||
use crate::diagnostics::DiagnosticItem;
|
||||
use crate::disk_cache::DiskCache;
|
||||
use crate::doc::Location;
|
||||
use crate::file_fetcher::SourceFile;
|
||||
use crate::file_fetcher::SourceFileFetcher;
|
||||
use crate::flags::Flags;
|
||||
|
@ -20,6 +19,7 @@ use crate::source_maps::SourceMapGetter;
|
|||
use crate::startup_data;
|
||||
use crate::state::State;
|
||||
use crate::swc_util::AstParser;
|
||||
use crate::swc_util::Location;
|
||||
use crate::swc_util::SwcDiagnosticBuffer;
|
||||
use crate::version;
|
||||
use crate::worker::Worker;
|
||||
|
|
Loading…
Reference in a new issue