1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-11 08:33:43 -05:00

refactor: move cli/doc/ to separate crate (#7103)

This commit is contained in:
Bartek Iwańczuk 2020-08-19 19:13:43 +02:00 committed by GitHub
parent 1507a8cf2d
commit be1e7ab532
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 93 additions and 5683 deletions

18
Cargo.lock generated
View file

@ -329,6 +329,7 @@ dependencies = [
"bytes", "bytes",
"clap", "clap",
"deno_core", "deno_core",
"deno_doc",
"deno_lint", "deno_lint",
"deno_web", "deno_web",
"dissimilar", "dissimilar",
@ -392,6 +393,23 @@ dependencies = [
"url", "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]] [[package]]
name = "deno_lint" name = "deno_lint"
version = "0.1.23" version = "0.1.23"

View file

@ -24,9 +24,9 @@ winapi = "0.3.9"
[dependencies] [dependencies]
deno_core = { path = "../core", version = "0.53.0" } deno_core = { path = "../core", version = "0.53.0" }
deno_doc = { version = "0.1.0" }
deno_lint = { version = "0.1.23", features = ["json"] } deno_lint = { version = "0.1.23", features = ["json"] }
atty = "0.2.14" atty = "0.2.14"
base64 = "0.12.3" base64 = "0.12.3"
bytes = "0.5.6" bytes = "0.5.6"

View file

@ -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(
&param.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)
}

View file

@ -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 { "" })
}

View file

@ -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)
}

View file

@ -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(&param.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)
}

View file

@ -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)
}

View file

@ -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![],
}
}

View file

@ -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)
}
}
}

View file

@ -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)
}

View file

@ -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),
}
}
}

View file

@ -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()),
}
}

View file

@ -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)
}
}

View file

@ -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)
}
}

File diff suppressed because it is too large Load diff

View file

@ -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![]
}
}

View file

@ -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![]
}
}

View file

@ -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)
}

View file

@ -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)
}

View file

@ -313,8 +313,8 @@ fn thread_safe() {
#[test] #[test]
fn test_should_allow_js() { fn test_should_allow_js() {
use crate::doc::Location;
use crate::module_graph::ImportDescriptor; use crate::module_graph::ImportDescriptor;
use crate::swc_util::Location;
assert!(should_allow_js(&[ assert!(should_allow_js(&[
&ModuleGraphFile { &ModuleGraphFile {

View file

@ -29,7 +29,6 @@ pub mod deno_dir;
pub mod diagnostics; pub mod diagnostics;
mod diff; mod diff;
mod disk_cache; mod disk_cache;
mod doc;
mod file_fetcher; mod file_fetcher;
pub mod flags; pub mod flags;
mod flags_allow_net; mod flags_allow_net;
@ -69,14 +68,13 @@ pub mod version;
mod web_worker; mod web_worker;
pub mod 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::SourceFile;
use crate::file_fetcher::SourceFileFetcher; use crate::file_fetcher::SourceFileFetcher;
use crate::file_fetcher::TextDocument; use crate::file_fetcher::TextDocument;
use crate::fs as deno_fs; use crate::fs as deno_fs;
use crate::global_state::GlobalState; use crate::global_state::GlobalState;
use crate::msg::MediaType; use crate::msg::MediaType;
use crate::op_error::OpError;
use crate::permissions::Permissions; use crate::permissions::Permissions;
use crate::tsc::TargetLib; use crate::tsc::TargetLib;
use crate::worker::MainWorker; use crate::worker::MainWorker;
@ -85,6 +83,8 @@ use deno_core::Deps;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::EsIsolate; use deno_core::EsIsolate;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
use deno_doc as doc;
use deno_doc::parser::DocFileLoader;
use flags::DenoSubcommand; use flags::DenoSubcommand;
use flags::Flags; use flags::Flags;
use futures::future::FutureExt; use futures::future::FutureExt;
@ -505,19 +505,39 @@ async fn doc_command(
let source_file = source_file.unwrap_or_else(|| "--builtin".to_string()); let source_file = source_file.unwrap_or_else(|| "--builtin".to_string());
impl DocFileLoader for SourceFileFetcher { 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( fn load_source_code(
&self, &self,
specifier: &str, specifier: &str,
) -> Pin<Box<dyn Future<Output = Result<String, OpError>>>> { ) -> Pin<Box<dyn Future<Output = Result<String, doc::DocError>>>> {
let fetcher = self.clone(); let fetcher = self.clone();
let specifier = specifier.to_string(); let specifier = ModuleSpecifier::resolve_url_or_path(specifier)
.expect("Expected valid specifier");
async move { async move {
let specifier = ModuleSpecifier::resolve_url_or_path(&specifier)
.map_err(OpError::from)?;
let source_file = fetcher let source_file = fetcher
.fetch_source_file(&specifier, None, Permissions::allow_all()) .fetch_source_file(&specifier, None, Permissions::allow_all())
.await?; .await
source_file.source_code.to_string().map_err(OpError::from) .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() .boxed_local()
} }
@ -525,14 +545,20 @@ async fn doc_command(
let loader = Box::new(global_state.file_fetcher.clone()); let loader = Box::new(global_state.file_fetcher.clone());
let doc_parser = doc::DocParser::new(loader, private); 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" { 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 { } else {
let module_specifier = let module_specifier =
ModuleSpecifier::resolve_url_or_path(&source_file).unwrap(); ModuleSpecifier::resolve_url_or_path(&source_file).unwrap();
doc_parser doc_parser
.parse_with_reexports(&module_specifier.to_string()) .parse_with_reexports(&module_specifier.to_string(), syntax)
.await .await
}; };
@ -555,9 +581,15 @@ async fn doc_command(
eprintln!("Node {} was not found!", filter); eprintln!("Node {} was not found!", filter);
std::process::exit(1); std::process::exit(1);
} }
format!("{}", doc::DocPrinter::new(&nodes, private)) format!(
"{}",
doc::DocPrinter::new(&nodes, colors::use_color(), private)
)
} else { } 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) write_to_stdout_ignore_sigpipe(details.as_bytes()).map_err(ErrBox::from)

View file

@ -1,6 +1,5 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::checksum; use crate::checksum;
use crate::doc::Location;
use crate::file_fetcher::map_file_extension; use crate::file_fetcher::map_file_extension;
use crate::file_fetcher::SourceFile; use crate::file_fetcher::SourceFile;
use crate::file_fetcher::SourceFileFetcher; use crate::file_fetcher::SourceFileFetcher;
@ -8,6 +7,7 @@ use crate::import_map::ImportMap;
use crate::msg::MediaType; use crate::msg::MediaType;
use crate::op_error::OpError; use crate::op_error::OpError;
use crate::permissions::Permissions; use crate::permissions::Permissions;
use crate::swc_util::Location;
use crate::tsc::pre_process_file; use crate::tsc::pre_process_file;
use crate::tsc::ImportDesc; use crate::tsc::ImportDesc;
use crate::tsc::TsReferenceDesc; use crate::tsc::TsReferenceDesc;

View file

@ -1,6 +1,7 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::msg::MediaType; use crate::msg::MediaType;
use deno_core::ErrBox; use deno_core::ErrBox;
use serde::Serialize;
use std::error::Error; use std::error::Error;
use std::fmt; use std::fmt;
use std::rc::Rc; use std::rc::Rc;
@ -31,6 +32,31 @@ use swc_ecmascript::transforms::fixer;
use swc_ecmascript::transforms::typescript; use swc_ecmascript::transforms::typescript;
use swc_ecmascript::visit::FoldWith; 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; struct DummyHandler;
impl swc_ecmascript::codegen::Handlers for DummyHandler {} impl swc_ecmascript::codegen::Handlers for DummyHandler {}

View file

@ -3,7 +3,6 @@ use crate::colors;
use crate::diagnostics::Diagnostic; use crate::diagnostics::Diagnostic;
use crate::diagnostics::DiagnosticItem; use crate::diagnostics::DiagnosticItem;
use crate::disk_cache::DiskCache; use crate::disk_cache::DiskCache;
use crate::doc::Location;
use crate::file_fetcher::SourceFile; use crate::file_fetcher::SourceFile;
use crate::file_fetcher::SourceFileFetcher; use crate::file_fetcher::SourceFileFetcher;
use crate::flags::Flags; use crate::flags::Flags;
@ -20,6 +19,7 @@ use crate::source_maps::SourceMapGetter;
use crate::startup_data; use crate::startup_data;
use crate::state::State; use crate::state::State;
use crate::swc_util::AstParser; use crate::swc_util::AstParser;
use crate::swc_util::Location;
use crate::swc_util::SwcDiagnosticBuffer; use crate::swc_util::SwcDiagnosticBuffer;
use crate::version; use crate::version;
use crate::worker::Worker; use crate::worker::Worker;