Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add fast-check based TypeScript type definition generation #379

Merged
merged 37 commits into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
afa8a93
feat: Add fast-check based TypeScript type definition generation
marvinhagemeister Feb 13, 2024
d6ea3b0
feat: infer more expressions
marvinhagemeister Feb 13, 2024
c4dc7bd
chore: make clippy happy
marvinhagemeister Feb 13, 2024
d18d8a4
chore: reduce diff noise
marvinhagemeister Feb 13, 2024
7247b0f
chore: reduce diff noise more
marvinhagemeister Feb 13, 2024
897d0f1
chore: clippy stuff
marvinhagemeister Feb 13, 2024
0ea6663
chore: add test for dts option
marvinhagemeister Feb 13, 2024
981dfea
chore: add allow unused
marvinhagemeister Feb 13, 2024
710ebbd
fix: remove path handling from transform
marvinhagemeister Feb 13, 2024
f89ce91
chore: remove unused struct
marvinhagemeister Feb 13, 2024
974792c
chore: reduce allocations
marvinhagemeister Feb 13, 2024
5936a38
fix: wrong property error
marvinhagemeister Feb 13, 2024
e14f45d
chore: simplify comments mut
marvinhagemeister Feb 13, 2024
58a6d3b
chore: remove cloning
marvinhagemeister Feb 13, 2024
9dee886
chore: use owned
marvinhagemeister Feb 13, 2024
0854a76
chore: remove clones
marvinhagemeister Feb 13, 2024
6224427
chore: reduce DUMMY_SPAN usage
marvinhagemeister Feb 13, 2024
5fc358d
chore: add todo comment
marvinhagemeister Feb 13, 2024
5bf01d6
feat: add diagnostics support in dts transform
marvinhagemeister Feb 14, 2024
a8bcd4d
chore: make clippy happy
marvinhagemeister Feb 14, 2024
d71b720
chore: update test
marvinhagemeister Feb 14, 2024
f09b96e
chore: integrate dts with test snapshots
marvinhagemeister Feb 14, 2024
659fe16
fix: track overloads
marvinhagemeister Feb 14, 2024
7b985ab
fix: arrow function expression type inference
marvinhagemeister Feb 14, 2024
f02750b
chore: add more tests
marvinhagemeister Feb 14, 2024
87e1b3f
WIP
marvinhagemeister Feb 14, 2024
bba3e96
fix: improve pattern inference
marvinhagemeister Feb 14, 2024
812c8ed
fix: more cases
marvinhagemeister Feb 14, 2024
9d1ea36
chore: make dts code conditional
marvinhagemeister Feb 15, 2024
379f85f
fix: add declare to enums
marvinhagemeister Feb 15, 2024
03bcc2e
chore: update snapshots
marvinhagemeister Feb 15, 2024
ea153b6
chore: add as const snapshot test
marvinhagemeister Feb 15, 2024
255f463
chore: remove clone
marvinhagemeister Feb 16, 2024
a2a5bcd
feat: support ts enums
marvinhagemeister Feb 16, 2024
7eacad2
chore: simplify code
marvinhagemeister Feb 16, 2024
b8b4029
feat: support TypeScript module declarations
marvinhagemeister Feb 16, 2024
91d29e4
chore: update snapshots
marvinhagemeister Feb 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ pub async fn js_create_graph(
reporter: None,
workspace_fast_check: false,
workspace_members: Vec::new(),
fast_check_dts: false,
},
)
.await;
Expand Down
4 changes: 4 additions & 0 deletions src/fast_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ mod range_finder;
mod swc_helpers;
#[cfg(feature = "fast_check")]
mod transform;
#[cfg(feature = "fast_check")]
mod transform_dts;

use deno_ast::diagnostics::DiagnosticLevel;
use deno_ast::diagnostics::DiagnosticLocation;
Expand All @@ -22,6 +24,8 @@ use deno_ast::diagnostics::DiagnosticSourceRange;
use deno_ast::SourceRange;
use deno_ast::SourceTextInfo;
#[cfg(feature = "fast_check")]
pub use transform::FastCheckDtsModule;
#[cfg(feature = "fast_check")]
pub use transform::FastCheckModule;
#[cfg(feature = "fast_check")]
pub use transform::TransformOptions;
Expand Down
80 changes: 80 additions & 0 deletions src/fast_check/swc_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,17 @@ use deno_ast::swc::ast::PropName;
use deno_ast::swc::ast::PropOrSpread;
use deno_ast::swc::ast::ReturnStmt;
use deno_ast::swc::ast::Stmt;
use deno_ast::swc::ast::TsEntityName;
use deno_ast::swc::ast::TsKeywordType;
use deno_ast::swc::ast::TsKeywordTypeKind;
use deno_ast::swc::ast::TsLit;
use deno_ast::swc::ast::TsLitType;
use deno_ast::swc::ast::TsTupleElement;
use deno_ast::swc::ast::TsType;
use deno_ast::swc::ast::TsTypeAnn;
use deno_ast::swc::ast::TsTypeOperator;
use deno_ast::swc::ast::TsTypeOperatorOp;
use deno_ast::swc::ast::TsTypeRef;
use deno_ast::swc::common::DUMMY_SP;

pub fn ident(name: String) -> Ident {
Expand Down Expand Up @@ -187,3 +195,75 @@ fn is_keyword_type(return_type: &TsType, kind: TsKeywordTypeKind) -> bool {
_ => false,
}
}

pub fn any_type_ann() -> Box<TsTypeAnn> {
type_ann(ts_keyword_type(TsKeywordTypeKind::TsAnyKeyword))
}

pub fn ts_readonly(ann: TsType) -> TsType {
TsType::TsTypeOperator(TsTypeOperator {
span: DUMMY_SP,
op: TsTypeOperatorOp::ReadOnly,
type_ann: Box::new(ann),
})
}

pub fn type_ann(ts_type: TsType) -> Box<TsTypeAnn> {
Box::new(TsTypeAnn {
span: DUMMY_SP,
type_ann: Box::new(ts_type),
})
}

pub fn type_ref(name: String) -> TsTypeRef {
TsTypeRef {
span: DUMMY_SP,
type_name: TsEntityName::Ident(Ident::new(name.into(), DUMMY_SP)),
type_params: None,
}
}

pub fn ts_lit_type(lit: TsLit) -> TsType {
TsType::TsLitType(TsLitType {
lit,
span: DUMMY_SP,
})
}

pub fn regex_type() -> TsType {
TsType::TsTypeRef(type_ref("RegExp".to_string()))
}

pub fn ts_tuple_element(ts_type: TsType) -> TsTupleElement {
TsTupleElement {
label: None,
span: DUMMY_SP,
ty: Box::new(ts_type),
}
}

pub fn maybe_lit_to_ts_type_const(lit: &Lit) -> Option<TsType> {
match lit {
Lit::Str(lit_str) => Some(ts_lit_type(TsLit::Str(lit_str.clone()))),
Lit::Bool(lit_bool) => Some(ts_lit_type(TsLit::Bool(*lit_bool))),
Lit::Null(_) => Some(ts_keyword_type(TsKeywordTypeKind::TsNullKeyword)),
Lit::Num(lit_num) => Some(ts_lit_type(TsLit::Number(lit_num.clone()))),
Lit::BigInt(lit_bigint) => {
Some(ts_lit_type(TsLit::BigInt(lit_bigint.clone())))
}
Lit::Regex(_) => Some(regex_type()),
Lit::JSXText(_) => None,
}
}

pub fn maybe_lit_to_ts_type(lit: &Lit) -> Option<TsType> {
match lit {
Lit::Str(_) => Some(ts_keyword_type(TsKeywordTypeKind::TsStringKeyword)),
Lit::Bool(_) => Some(ts_keyword_type(TsKeywordTypeKind::TsBooleanKeyword)),
Lit::Null(_) => Some(ts_keyword_type(TsKeywordTypeKind::TsNullKeyword)),
Lit::Num(_) => Some(ts_keyword_type(TsKeywordTypeKind::TsNumberKeyword)),
Lit::BigInt(_) => Some(ts_keyword_type(TsKeywordTypeKind::TsBigIntKeyword)),
Lit::Regex(_) => Some(regex_type()),
Lit::JSXText(_) => None,
}
}
74 changes: 42 additions & 32 deletions src/fast_check/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,19 @@ use crate::ModuleInfo;
use crate::WorkspaceMember;

use super::range_finder::ModulePublicRanges;
use super::swc_helpers::any_type_ann;
use super::swc_helpers::get_return_stmts_with_arg_from_function_body;
use super::swc_helpers::ident;
use super::swc_helpers::is_never_type;
use super::swc_helpers::is_void_type;
use super::swc_helpers::maybe_lit_to_ts_type;
use super::swc_helpers::ts_keyword_type;
use super::transform_dts::FastCheckDtsDiagnostic;
use super::transform_dts::FastCheckDtsTransformer;
use super::FastCheckDiagnostic;
use super::FastCheckDiagnosticRange;

struct CommentsMut {
pub struct CommentsMut {
leading: SingleThreadedCommentsMapInner,
trailing: SingleThreadedCommentsMapInner,
}
Expand Down Expand Up @@ -139,15 +143,23 @@ impl CommentsMut {
}
}

#[derive(Debug, Clone)]
pub struct FastCheckDtsModule {
pub text: String,
pub diagnostics: Vec<FastCheckDtsDiagnostic>,
}

pub struct FastCheckModule {
pub module_info: ModuleInfo,
pub text: String,
pub dts: Option<FastCheckDtsModule>,
pub source_map: Vec<u8>,
}

pub struct TransformOptions<'a> {
pub workspace_members: &'a [WorkspaceMember],
pub should_error_on_first_diagnostic: bool,
pub dts: bool,
}

pub fn transform(
Expand Down Expand Up @@ -175,8 +187,9 @@ pub fn transform(
&comments,
);

// now emit
let comments = comments.into_single_threaded();

// now emit
let (text, source_map) =
emit(specifier, &comments, parsed_source.text_info(), &module).map_err(
|e| {
Expand All @@ -187,9 +200,33 @@ pub fn transform(
},
)?;

let dts = if options.dts {
let mut dts_transformer =
FastCheckDtsTransformer::new(parsed_source, specifier);

let module = dts_transformer.transform(module)?;
let (text, _source_map) =
emit(specifier, &comments, parsed_source.text_info(), &module).map_err(
|e| {
vec![FastCheckDiagnostic::Emit {
specifier: specifier.clone(),
inner: Arc::new(e),
}]
},
)?;

Some(FastCheckDtsModule {
text,
diagnostics: dts_transformer.diagnostics,
})
} else {
None
};

Ok(FastCheckModule {
module_info,
text,
dts,
source_map,
})
}
Expand Down Expand Up @@ -1361,27 +1398,7 @@ impl<'a> FastCheckTransformer<'a> {
match expr {
Expr::TsTypeAssertion(n) => infer_simple_type_from_type(&n.type_ann),
Expr::TsAs(n) => infer_simple_type_from_type(&n.type_ann),
Expr::Lit(lit) => match lit {
Lit::Str(_) => {
Some(ts_keyword_type(TsKeywordTypeKind::TsStringKeyword))
}
Lit::Bool(_) => {
Some(ts_keyword_type(TsKeywordTypeKind::TsBooleanKeyword))
}
Lit::Null(_) => Some(ts_keyword_type(TsKeywordTypeKind::TsNullKeyword)),
Lit::Num(_) => {
Some(ts_keyword_type(TsKeywordTypeKind::TsNumberKeyword))
}
Lit::BigInt(_) => {
Some(ts_keyword_type(TsKeywordTypeKind::TsBigIntKeyword))
}
Lit::Regex(_) => Some(TsType::TsTypeRef(TsTypeRef {
span: DUMMY_SP,
type_name: TsEntityName::Ident(Ident::new("RegExp".into(), DUMMY_SP)),
type_params: None,
})),
Lit::JSXText(_) => None,
},
Expr::Lit(lit) => maybe_lit_to_ts_type(lit),
Expr::Call(call_expr) => {
if self.is_call_expr_symbol_create(call_expr) {
Some(TsType::TsTypeOperator(TsTypeOperator {
Expand Down Expand Up @@ -1497,7 +1514,7 @@ fn void_or_promise_void(is_async: bool) -> Box<TsType> {
if is_async {
Box::new(TsType::TsTypeRef(TsTypeRef {
span: DUMMY_SP,
type_name: TsEntityName::Ident(ident("Promise".into())),
type_name: TsEntityName::Ident(Ident::new("Promise".into(), DUMMY_SP)),
type_params: Some(Box::new(TsTypeParamInstantiation {
span: DUMMY_SP,
params: vec![void_type],
Expand Down Expand Up @@ -1561,7 +1578,7 @@ fn prefix_idents_in_pat(pat: &mut Pat, prefix: &str) {
}
}

fn emit(
pub fn emit(
specifier: &ModuleSpecifier,
comments: &SingleThreadedComments,
text_info: &SourceTextInfo,
Expand Down Expand Up @@ -1786,13 +1803,6 @@ fn paren_expr(expr: Box<Expr>) -> Expr {
})
}

fn any_type_ann() -> Box<TsTypeAnn> {
Box::new(TsTypeAnn {
span: DUMMY_SP,
type_ann: Box::new(ts_keyword_type(TsKeywordTypeKind::TsAnyKeyword)),
})
}

fn unknown_type_ann() -> Box<TsTypeAnn> {
Box::new(TsTypeAnn {
span: DUMMY_SP,
Expand Down
Loading
Loading