Skip to content

Commit

Permalink
feat: Add "deno doc" subcommand (denoland#4500)
Browse files Browse the repository at this point in the history
  • Loading branch information
bartlomieju committed Mar 28, 2020
1 parent bced525 commit 3fac487
Show file tree
Hide file tree
Showing 18 changed files with 3,233 additions and 4 deletions.
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,14 @@ webpki-roots = "0.19.0"
walkdir = "2.3.1"
warp = "0.2.2"
semver-parser = "0.9.0"
# TODO(bartlomieju): make sure we're using exactly same versions
# of "swc_*" as dprint-plugin-typescript
swc_common = "=0.5.9"
swc_ecma_ast = "=0.18.1"
swc_ecma_parser = "=0.21.8"
swc_ecma_parser_macros = "=0.4.1"
uuid = { version = "0.8", features = ["v4"] }


[target.'cfg(windows)'.dependencies]
winapi = "0.3.8"
fwdansi = "1.1.0"
Expand Down
207 changes: 207 additions & 0 deletions cli/doc/class.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use serde::Serialize;
use swc_common;
use swc_common::SourceMap;
use swc_common::Spanned;
use swc_ecma_ast;

use super::function::function_to_function_def;
use super::function::FunctionDef;
use super::parser::DocParser;
use super::ts_type::ts_type_ann_to_def;
use super::ts_type::TsTypeDef;
use super::Location;
use super::ParamDef;

#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ClassConstructorDef {
pub js_doc: Option<String>,
pub accessibility: Option<swc_ecma_ast::Accessibility>,
pub name: String,
pub params: Vec<ParamDef>,
pub location: Location,
}

#[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_ecma_ast::Accessibility>,
pub is_abstract: bool,
pub is_static: bool,
pub name: String,
pub location: Location,
}

#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ClassMethodDef {
pub js_doc: Option<String>,
// pub ts_type: Option<TsTypeDef>,
// pub readonly: bool,
pub accessibility: Option<swc_ecma_ast::Accessibility>,
pub is_abstract: bool,
pub is_static: bool,
pub name: String,
pub kind: swc_ecma_ast::MethodKind,
pub function_def: FunctionDef,
pub location: Location,
}

#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ClassDef {
// TODO: decorators, super_class, implements,
// type_params, super_type_params
pub is_abstract: bool,
pub constructors: Vec<ClassConstructorDef>,
pub properties: Vec<ClassPropertyDef>,
pub methods: Vec<ClassMethodDef>,
}

fn prop_name_to_string(
source_map: &SourceMap,
prop_name: &swc_ecma_ast::PropName,
) -> String {
use swc_ecma_ast::PropName;
match prop_name {
PropName::Ident(ident) => ident.sym.to_string(),
PropName::Str(str_) => str_.value.to_string(),
PropName::Num(num) => num.value.to_string(),
PropName::Computed(comp_prop_name) => {
source_map.span_to_snippet(comp_prop_name.span).unwrap()
}
}
}

pub fn get_doc_for_class_decl(
doc_parser: &DocParser,
class_decl: &swc_ecma_ast::ClassDecl,
) -> (String, ClassDef) {
let mut constructors = vec![];
let mut methods = vec![];
let mut properties = vec![];

for member in &class_decl.class.body {
use swc_ecma_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(&doc_parser.source_map, &ctor.key);

let mut params = vec![];

for param in &ctor.params {
use swc_ecma_ast::Pat;
use swc_ecma_ast::PatOrTsParamProp::*;

let param_def = match param {
Pat(pat) => match pat {
Pat::Ident(ident) => {
let ts_type = ident
.type_ann
.as_ref()
.map(|rt| ts_type_ann_to_def(&doc_parser.source_map, rt));

ParamDef {
name: ident.sym.to_string(),
ts_type,
}
}
_ => ParamDef {
name: "<TODO>".to_string(),
ts_type: None,
},
},
TsParamProp(_) => ParamDef {
name: "<TODO>".to_string(),
ts_type: None,
},
};
params.push(param_def);
}

let constructor_def = ClassConstructorDef {
js_doc: ctor_js_doc,
accessibility: ctor.accessibility,
name: constructor_name,
params,
location: doc_parser
.source_map
.lookup_char_pos(ctor.span.lo())
.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(&doc_parser.source_map, &class_method.key);
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,
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
.source_map
.lookup_char_pos(class_method.span.lo())
.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(&doc_parser.source_map, rt));

use swc_ecma_ast::Expr;
let prop_name = match &*class_prop.key {
Expr::Ident(ident) => ident.sym.to_string(),
_ => "<TODO>".to_string(),
};

let prop_def = ClassPropertyDef {
js_doc: prop_js_doc,
ts_type,
readonly: class_prop.readonly,
is_abstract: class_prop.is_abstract,
is_static: class_prop.is_static,
accessibility: class_prop.accessibility,
name: prop_name,
location: doc_parser
.source_map
.lookup_char_pos(class_prop.span.lo())
.into(),
};
properties.push(prop_def);
}
// TODO:
TsIndexSignature(_) => {}
PrivateMethod(_) => {}
PrivateProp(_) => {}
}
}

let class_name = class_decl.ident.sym.to_string();
let class_def = ClassDef {
is_abstract: class_decl.class.is_abstract,
constructors,
properties,
methods,
};

(class_name, class_def)
}
41 changes: 41 additions & 0 deletions cli/doc/enum.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use serde::Serialize;
use swc_ecma_ast;

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_ecma_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_ecma_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)
}
70 changes: 70 additions & 0 deletions cli/doc/function.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use serde::Serialize;
use swc_ecma_ast;

use super::parser::DocParser;
use super::ts_type::ts_type_ann_to_def;
use super::ts_type::TsTypeDef;
use super::ParamDef;

#[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,
// TODO: type_params, decorators
}

pub fn function_to_function_def(
doc_parser: &DocParser,
function: &swc_ecma_ast::Function,
) -> FunctionDef {
let mut params = vec![];

for param in &function.params {
use swc_ecma_ast::Pat;

let param_def = match param {
Pat::Ident(ident) => {
let ts_type = ident
.type_ann
.as_ref()
.map(|rt| ts_type_ann_to_def(&doc_parser.source_map, rt));

ParamDef {
name: ident.sym.to_string(),
ts_type,
}
}
_ => ParamDef {
name: "<TODO>".to_string(),
ts_type: None,
},
};

params.push(param_def);
}

let maybe_return_type = function
.return_type
.as_ref()
.map(|rt| ts_type_ann_to_def(&doc_parser.source_map, rt));

FunctionDef {
params,
return_type: maybe_return_type,
is_async: function.is_async,
is_generator: function.is_generator,
}
}

pub fn get_doc_for_fn_decl(
doc_parser: &DocParser,
fn_decl: &swc_ecma_ast::FnDecl,
) -> (String, FunctionDef) {
let name = fn_decl.ident.sym.to_string();
let fn_def = function_to_function_def(doc_parser, &fn_decl.function);
(name, fn_def)
}
Loading

0 comments on commit 3fac487

Please sign in to comment.