mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
feat(transformer-dts): report error for async function and generator (#3688)
feat(transformer-dts): report error for async function and generator fix(transformer-dts): correct span for type containing private name error fix(transformer-dts): should add reference for export specifiers
This commit is contained in:
parent
fa7a6babce
commit
0e6d3ceee5
7 changed files with 63 additions and 22 deletions
|
|
@ -237,6 +237,20 @@ macro_rules! match_ts_type {
|
||||||
pub use match_ts_type;
|
pub use match_ts_type;
|
||||||
|
|
||||||
impl<'a> TSType<'a> {
|
impl<'a> TSType<'a> {
|
||||||
|
pub fn get_identifier_reference(&self) -> Option<IdentifierReference<'a>> {
|
||||||
|
match self {
|
||||||
|
TSType::TSTypeReference(reference) => {
|
||||||
|
Some(TSTypeName::get_first_name(&reference.type_name))
|
||||||
|
}
|
||||||
|
TSType::TSQualifiedName(qualified) => Some(TSTypeName::get_first_name(&qualified.left)),
|
||||||
|
TSType::TSTypeQuery(query) => match &query.expr_name {
|
||||||
|
TSTypeQueryExprName::IdentifierReference(ident) => Some((*ident).clone()),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_const_type_reference(&self) -> bool {
|
pub fn is_const_type_reference(&self) -> bool {
|
||||||
matches!(self, TSType::TSTypeReference(reference) if reference.type_name.is_const())
|
matches!(self, TSType::TSTypeReference(reference) if reference.type_name.is_const())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
23
crates/oxc_transformer_dts/src/diagnostics.rs
Normal file
23
crates/oxc_transformer_dts/src/diagnostics.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
use oxc_ast::ast::Function;
|
||||||
|
use oxc_diagnostics::OxcDiagnostic;
|
||||||
|
use oxc_span::{Atom, Span};
|
||||||
|
|
||||||
|
pub fn function_must_have_explicit_return_type(func: &Function<'_>) -> OxcDiagnostic {
|
||||||
|
OxcDiagnostic::error(
|
||||||
|
"Function must have an explicit return type annotation with --isolatedDeclarations.",
|
||||||
|
)
|
||||||
|
.with_label(func.id.as_ref().map_or_else(
|
||||||
|
|| {
|
||||||
|
let start = func.params.span.start;
|
||||||
|
Span::new(start, start)
|
||||||
|
},
|
||||||
|
|id| id.span,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_containing_private_name(name: &Atom<'_>, span: Span) -> OxcDiagnostic {
|
||||||
|
OxcDiagnostic::error(format!(
|
||||||
|
"Type containing private name '{name}' can't be used with --isolatedDeclarations."
|
||||||
|
))
|
||||||
|
.with_label(span)
|
||||||
|
}
|
||||||
|
|
@ -6,7 +6,10 @@ use oxc_ast::ast::{
|
||||||
use oxc_diagnostics::OxcDiagnostic;
|
use oxc_diagnostics::OxcDiagnostic;
|
||||||
use oxc_span::{GetSpan, SPAN};
|
use oxc_span::{GetSpan, SPAN};
|
||||||
|
|
||||||
use crate::{return_type::FunctionReturnType, TransformerDts};
|
use crate::{
|
||||||
|
diagnostics::function_must_have_explicit_return_type, return_type::FunctionReturnType,
|
||||||
|
TransformerDts,
|
||||||
|
};
|
||||||
|
|
||||||
impl<'a> TransformerDts<'a> {
|
impl<'a> TransformerDts<'a> {
|
||||||
pub fn infer_type_from_expression(&self, expr: &Expression<'a>) -> Option<TSType<'a>> {
|
pub fn infer_type_from_expression(&self, expr: &Expression<'a>) -> Option<TSType<'a>> {
|
||||||
|
|
@ -100,19 +103,21 @@ impl<'a> TransformerDts<'a> {
|
||||||
return self.ctx.ast.copy(&function.return_type);
|
return self.ctx.ast.copy(&function.return_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if function.r#async || function.generator {
|
||||||
|
self.ctx.error(function_must_have_explicit_return_type(function));
|
||||||
|
}
|
||||||
|
|
||||||
let return_type = FunctionReturnType::infer(
|
let return_type = FunctionReturnType::infer(
|
||||||
self,
|
self,
|
||||||
function
|
function
|
||||||
.body
|
.body
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap_or_else(|| unreachable!("declare function can not have body")),
|
.unwrap_or_else(|| unreachable!("Only declare function can have no body")),
|
||||||
)
|
)
|
||||||
.map(|type_annotation| self.ctx.ast.ts_type_annotation(SPAN, type_annotation));
|
.map(|type_annotation| self.ctx.ast.ts_type_annotation(SPAN, type_annotation));
|
||||||
|
|
||||||
if return_type.is_none() {
|
if return_type.is_none() {
|
||||||
self.ctx.error(OxcDiagnostic::error(
|
self.ctx.error(function_must_have_explicit_return_type(function));
|
||||||
"Function must have an explicit return type annotation with --isolatedDeclarations.",
|
|
||||||
).with_label(function.span));
|
|
||||||
|
|
||||||
Some(self.ctx.ast.ts_type_annotation(SPAN, self.ctx.ast.ts_unknown_keyword(SPAN)))
|
Some(self.ctx.ast.ts_type_annotation(SPAN, self.ctx.ast.ts_unknown_keyword(SPAN)))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
mod class;
|
mod class;
|
||||||
mod context;
|
mod context;
|
||||||
mod declaration;
|
mod declaration;
|
||||||
|
mod diagnostics;
|
||||||
mod function;
|
mod function;
|
||||||
mod inferrer;
|
mod inferrer;
|
||||||
mod module;
|
mod module;
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,10 @@ use oxc_ast::{
|
||||||
},
|
},
|
||||||
Visit,
|
Visit,
|
||||||
};
|
};
|
||||||
use oxc_diagnostics::OxcDiagnostic;
|
|
||||||
use oxc_span::{Atom, GetSpan};
|
use oxc_span::{Atom, GetSpan};
|
||||||
use oxc_syntax::scope::ScopeFlags;
|
use oxc_syntax::scope::ScopeFlags;
|
||||||
|
|
||||||
use crate::{context::Ctx, TransformerDts};
|
use crate::{context::Ctx, diagnostics::type_containing_private_name, TransformerDts};
|
||||||
|
|
||||||
/// Infer return type from return statement. Does not support multiple return statements.
|
/// Infer return type from return statement. Does not support multiple return statements.
|
||||||
pub struct FunctionReturnType<'a> {
|
pub struct FunctionReturnType<'a> {
|
||||||
|
|
@ -67,11 +66,12 @@ impl<'a> FunctionReturnType<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if is_defined_in_current_scope {
|
if is_defined_in_current_scope {
|
||||||
transformer.ctx.error(
|
transformer.ctx.error(type_containing_private_name(
|
||||||
OxcDiagnostic::error(format!("Type containing private name '{reference_name}' can't be used with --isolatedDeclarations.")).with_label(
|
&reference_name,
|
||||||
expr.span()
|
expr_type
|
||||||
)
|
.get_identifier_reference()
|
||||||
);
|
.map_or_else(|| expr_type.span(), |ident| ident.span),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,11 +51,11 @@ impl<'a> ScopeTree<'a> {
|
||||||
self.type_bindings.last_mut().unwrap().insert(ident.clone());
|
self.type_bindings.last_mut().unwrap().insert(ident.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_unresolved_value_reference(&mut self, ident: &Atom<'a>) {
|
fn add_value_reference(&mut self, ident: &Atom<'a>) {
|
||||||
self.value_references.last_mut().unwrap().insert(ident.clone());
|
self.value_references.last_mut().unwrap().insert(ident.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_unresolved_type_reference(&mut self, ident: &Atom<'a>) {
|
fn add_type_reference(&mut self, ident: &Atom<'a>) {
|
||||||
self.type_references.last_mut().unwrap().insert(ident.clone());
|
self.type_references.last_mut().unwrap().insert(ident.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,7 +65,6 @@ impl<'a> ScopeTree<'a> {
|
||||||
fn resolve_references(&mut self) {
|
fn resolve_references(&mut self) {
|
||||||
let current_value_bindings = self.value_bindings.pop().unwrap_or_default();
|
let current_value_bindings = self.value_bindings.pop().unwrap_or_default();
|
||||||
let current_value_references = self.value_references.pop().unwrap_or_default();
|
let current_value_references = self.value_references.pop().unwrap_or_default();
|
||||||
|
|
||||||
self.type_references
|
self.type_references
|
||||||
.last_mut()
|
.last_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
@ -95,7 +94,7 @@ impl<'a> Visit<'a> for ScopeTree<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_identifier_reference(&mut self, ident: &IdentifierReference<'a>) {
|
fn visit_identifier_reference(&mut self, ident: &IdentifierReference<'a>) {
|
||||||
self.add_unresolved_value_reference(&ident.name);
|
self.add_value_reference(&ident.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_binding_pattern(&mut self, pattern: &BindingPattern<'a>) {
|
fn visit_binding_pattern(&mut self, pattern: &BindingPattern<'a>) {
|
||||||
|
|
@ -107,7 +106,7 @@ impl<'a> Visit<'a> for ScopeTree<'a> {
|
||||||
|
|
||||||
fn visit_ts_type_name(&mut self, name: &TSTypeName<'a>) {
|
fn visit_ts_type_name(&mut self, name: &TSTypeName<'a>) {
|
||||||
if let TSTypeName::IdentifierReference(ident) = name {
|
if let TSTypeName::IdentifierReference(ident) = name {
|
||||||
self.add_unresolved_type_reference(&ident.name);
|
self.add_type_reference(&ident.name);
|
||||||
} else {
|
} else {
|
||||||
walk_ts_type_name(self, name);
|
walk_ts_type_name(self, name);
|
||||||
}
|
}
|
||||||
|
|
@ -116,7 +115,7 @@ impl<'a> Visit<'a> for ScopeTree<'a> {
|
||||||
fn visit_ts_type_query(&mut self, ty: &TSTypeQuery<'a>) {
|
fn visit_ts_type_query(&mut self, ty: &TSTypeQuery<'a>) {
|
||||||
if let Some(type_name) = ty.expr_name.as_ts_type_name() {
|
if let Some(type_name) = ty.expr_name.as_ts_type_name() {
|
||||||
let ident = TSTypeName::get_first_name(type_name);
|
let ident = TSTypeName::get_first_name(type_name);
|
||||||
self.add_unresolved_value_reference(&ident.name);
|
self.add_value_reference(&ident.name);
|
||||||
} else {
|
} else {
|
||||||
walk_ts_type_query(self, ty);
|
walk_ts_type_query(self, ty);
|
||||||
}
|
}
|
||||||
|
|
@ -125,8 +124,8 @@ impl<'a> Visit<'a> for ScopeTree<'a> {
|
||||||
fn visit_export_named_declaration(&mut self, decl: &ExportNamedDeclaration<'a>) {
|
fn visit_export_named_declaration(&mut self, decl: &ExportNamedDeclaration<'a>) {
|
||||||
for specifier in &decl.specifiers {
|
for specifier in &decl.specifiers {
|
||||||
if let ModuleExportName::Identifier(ident) = &specifier.local {
|
if let ModuleExportName::Identifier(ident) = &specifier.local {
|
||||||
self.add_type_binding(&ident.name);
|
self.add_type_reference(&ident.name);
|
||||||
self.add_value_binding(&ident.name);
|
self.add_value_reference(&ident.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,13 @@ commit: d8086f14
|
||||||
|
|
||||||
transpile Summary:
|
transpile Summary:
|
||||||
AST Parsed : 20/20 (100.00%)
|
AST Parsed : 20/20 (100.00%)
|
||||||
Positive Passed: 7/20 (35.00%)
|
Positive Passed: 8/20 (40.00%)
|
||||||
Mismatch: "declarationAsyncAndGeneratorFunctions.ts"
|
Mismatch: "declarationAsyncAndGeneratorFunctions.ts"
|
||||||
Mismatch: "declarationBasicSyntax.ts"
|
Mismatch: "declarationBasicSyntax.ts"
|
||||||
Mismatch: "declarationComputedPropertyNames.ts"
|
Mismatch: "declarationComputedPropertyNames.ts"
|
||||||
Mismatch: "declarationCrossFileInferences.ts"
|
Mismatch: "declarationCrossFileInferences.ts"
|
||||||
Mismatch: "declarationEmitPartialNodeReuse.ts"
|
Mismatch: "declarationEmitPartialNodeReuse.ts"
|
||||||
Mismatch: "declarationFunctionDeclarations.ts"
|
Mismatch: "declarationFunctionDeclarations.ts"
|
||||||
Mismatch: "declarationLinkedAliases.ts"
|
|
||||||
Mismatch: "declarationNotInScopeTypes.ts"
|
Mismatch: "declarationNotInScopeTypes.ts"
|
||||||
Mismatch: "declarationPartialNodeReuseTypeOf.ts"
|
Mismatch: "declarationPartialNodeReuseTypeOf.ts"
|
||||||
Mismatch: "declarationRestParameters.ts"
|
Mismatch: "declarationRestParameters.ts"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue