mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
feat(isolated-declarations): report errors that are consistent with typescript. (#3720)
This commit is contained in:
parent
3c597356e4
commit
77d553364d
7 changed files with 152 additions and 44 deletions
|
|
@ -5,7 +5,10 @@ use oxc_allocator::Box;
|
|||
use oxc_span::{GetSpan, SPAN};
|
||||
|
||||
use crate::{
|
||||
diagnostics::{computed_property_name, extends_clause_expression},
|
||||
diagnostics::{
|
||||
accessor_must_have_explicit_return_type, computed_property_name, extends_clause_expression,
|
||||
method_must_have_explicit_return_type, property_must_have_explicit_type,
|
||||
},
|
||||
IsolatedDeclarations,
|
||||
};
|
||||
|
||||
|
|
@ -59,16 +62,17 @@ impl<'a> IsolatedDeclarations<'a> {
|
|||
.as_ref()
|
||||
.map(|type_annotation| self.ast.copy(type_annotation))
|
||||
.or_else(|| {
|
||||
let new_type = property
|
||||
property
|
||||
.value
|
||||
.as_ref()
|
||||
.and_then(|expr| self.infer_type_from_expression(expr))
|
||||
.unwrap_or_else(|| {
|
||||
// report error for has no type annotation
|
||||
self.ast.ts_unknown_keyword(property.span)
|
||||
});
|
||||
|
||||
Some(self.ast.ts_type_annotation(SPAN, new_type))
|
||||
.and_then(|expr| {
|
||||
let ts_type = self.infer_type_from_expression(expr);
|
||||
if ts_type.is_none() {
|
||||
self.error(property_must_have_explicit_type(property.key.span()));
|
||||
}
|
||||
ts_type
|
||||
})
|
||||
.map(|ts_type| self.ast.ts_type_annotation(SPAN, ts_type))
|
||||
})
|
||||
};
|
||||
|
||||
|
|
@ -115,6 +119,20 @@ impl<'a> IsolatedDeclarations<'a> {
|
|||
|
||||
let type_annotation = self.infer_function_return_type(function);
|
||||
|
||||
if type_annotation.is_none() {
|
||||
match definition.kind {
|
||||
MethodDefinitionKind::Method => {
|
||||
self.error(method_must_have_explicit_return_type(definition.key.span()));
|
||||
}
|
||||
MethodDefinitionKind::Get => {
|
||||
self.error(accessor_must_have_explicit_return_type(definition.key.span()));
|
||||
}
|
||||
MethodDefinitionKind::Constructor | MethodDefinitionKind::Set => {}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Infer the parameter type of the `set` method from the `get` method
|
||||
|
||||
let value = self.ast.function(
|
||||
FunctionType::TSEmptyBodyFunctionExpression,
|
||||
function.span,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,10 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_span::{GetSpan, SPAN};
|
||||
use oxc_syntax::scope::ScopeFlags;
|
||||
|
||||
use crate::{diagnostics::signature_computed_property_name, IsolatedDeclarations};
|
||||
use crate::{
|
||||
diagnostics::{inferred_type_of_expression, signature_computed_property_name},
|
||||
IsolatedDeclarations,
|
||||
};
|
||||
|
||||
impl<'a> IsolatedDeclarations<'a> {
|
||||
pub fn transform_variable_declaration(
|
||||
|
|
@ -264,6 +267,9 @@ impl<'a> IsolatedDeclarations<'a> {
|
|||
|
||||
impl<'a> Visit<'a> for IsolatedDeclarations<'a> {
|
||||
fn visit_ts_method_signature(&mut self, signature: &TSMethodSignature<'a>) {
|
||||
if signature.return_type.is_none() {
|
||||
self.error(inferred_type_of_expression(signature.span));
|
||||
}
|
||||
self.report_signature_property_key(&signature.key, signature.computed);
|
||||
}
|
||||
fn visit_ts_property_signature(&mut self, signature: &TSPropertySignature<'a>) {
|
||||
|
|
|
|||
|
|
@ -1,18 +1,32 @@
|
|||
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 {
|
||||
pub fn method_must_have_explicit_return_type(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::error(
|
||||
"Method must have an explicit return type annotation with --isolatedDeclarations.",
|
||||
)
|
||||
.with_label(span)
|
||||
}
|
||||
|
||||
pub fn function_must_have_explicit_return_type(span: Span) -> 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,
|
||||
))
|
||||
.with_label(span)
|
||||
}
|
||||
|
||||
pub fn accessor_must_have_explicit_return_type(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::error(
|
||||
"At least one accessor must have an explicit return type annotation with --isolatedDeclarations.",
|
||||
)
|
||||
.with_label(span)
|
||||
}
|
||||
|
||||
pub fn property_must_have_explicit_type(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::error(
|
||||
"Property must have an explicit type annotation with --isolatedDeclarations.",
|
||||
)
|
||||
.with_label(span)
|
||||
}
|
||||
|
||||
pub fn type_containing_private_name(name: &Atom<'_>, span: Span) -> OxcDiagnostic {
|
||||
|
|
@ -41,3 +55,31 @@ pub fn extends_clause_expression(span: Span) -> OxcDiagnostic {
|
|||
OxcDiagnostic::error("Extends clause can't contain an expression with --isolatedDeclarations.")
|
||||
.with_label(span)
|
||||
}
|
||||
|
||||
pub fn default_export_inferred(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::error("Default exports can't be inferred with --isolatedDeclarations.")
|
||||
.with_label(span)
|
||||
}
|
||||
|
||||
pub fn array_inferred(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::error("Arrays can't be inferred with --isolatedDeclarations.").with_label(span)
|
||||
}
|
||||
|
||||
pub fn shorthand_property(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::error(
|
||||
"Objects that contain shorthand properties can't be inferred with --isolatedDeclarations.",
|
||||
)
|
||||
.with_label(span)
|
||||
}
|
||||
|
||||
pub fn inferred_type_of_expression(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::error("Expression type can't be inferred with --isolatedDeclarations.")
|
||||
.with_label(span)
|
||||
}
|
||||
|
||||
// Inference from class expressions is not supported with --isolatedDeclarations.
|
||||
|
||||
pub fn inferred_type_of_class_expression(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::error("Class expression type can't be inferred with --isolatedDeclarations.")
|
||||
.with_label(span)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ use oxc_ast::ast::*;
|
|||
use oxc_allocator::Box;
|
||||
use oxc_ast::ast::Function;
|
||||
use oxc_diagnostics::OxcDiagnostic;
|
||||
use oxc_span::SPAN;
|
||||
use oxc_span::{Span, SPAN};
|
||||
|
||||
use crate::IsolatedDeclarations;
|
||||
use crate::{diagnostics::function_must_have_explicit_return_type, IsolatedDeclarations};
|
||||
|
||||
impl<'a> IsolatedDeclarations<'a> {
|
||||
pub fn transform_function(&mut self, func: &Function<'a>) -> Option<Box<'a, Function<'a>>> {
|
||||
|
|
@ -14,6 +14,9 @@ impl<'a> IsolatedDeclarations<'a> {
|
|||
None
|
||||
} else {
|
||||
let return_type = self.infer_function_return_type(func);
|
||||
if return_type.is_none() {
|
||||
self.error(function_must_have_explicit_return_type(get_function_span(func)));
|
||||
}
|
||||
let params = self.transform_formal_parameters(&func.params);
|
||||
Some(self.ast.function(
|
||||
func.r#type,
|
||||
|
|
@ -126,3 +129,13 @@ impl<'a> IsolatedDeclarations<'a> {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_function_span(func: &Function<'_>) -> Span {
|
||||
func.id.as_ref().map_or_else(
|
||||
|| {
|
||||
let start = func.params.span.start;
|
||||
Span::new(start, start)
|
||||
},
|
||||
|id| id.span,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_span::{GetSpan, SPAN};
|
||||
|
||||
use crate::{
|
||||
diagnostics::function_must_have_explicit_return_type, return_type::FunctionReturnType,
|
||||
diagnostics::{array_inferred, inferred_type_of_class_expression},
|
||||
return_type::FunctionReturnType,
|
||||
IsolatedDeclarations,
|
||||
};
|
||||
|
||||
|
|
@ -35,6 +36,10 @@ impl<'a> IsolatedDeclarations<'a> {
|
|||
Expression::ObjectExpression(expr) => {
|
||||
Some(self.transform_object_expression_to_ts_type(expr, false))
|
||||
}
|
||||
Expression::ArrayExpression(expr) => {
|
||||
self.error(array_inferred(expr.span));
|
||||
Some(self.ast.ts_unknown_keyword(expr.span))
|
||||
}
|
||||
Expression::TSAsExpression(expr) => {
|
||||
if expr.type_annotation.is_const_type_reference() {
|
||||
Some(self.transform_expression_to_ts_type(&expr.expression))
|
||||
|
|
@ -43,14 +48,7 @@ impl<'a> IsolatedDeclarations<'a> {
|
|||
}
|
||||
}
|
||||
Expression::ClassExpression(expr) => {
|
||||
self.error(
|
||||
OxcDiagnostic::error(
|
||||
"
|
||||
Inference from class expressions is not supported with --isolatedDeclarations.
|
||||
",
|
||||
)
|
||||
.with_label(expr.span),
|
||||
);
|
||||
self.error(inferred_type_of_class_expression(expr.span));
|
||||
Some(self.ast.ts_unknown_keyword(SPAN))
|
||||
}
|
||||
Expression::TSNonNullExpression(expr) => {
|
||||
|
|
@ -104,25 +102,17 @@ impl<'a> IsolatedDeclarations<'a> {
|
|||
}
|
||||
|
||||
if function.r#async || function.generator {
|
||||
self.error(function_must_have_explicit_return_type(function));
|
||||
return None;
|
||||
}
|
||||
|
||||
let return_type = FunctionReturnType::infer(
|
||||
FunctionReturnType::infer(
|
||||
self,
|
||||
function
|
||||
.body
|
||||
.as_ref()
|
||||
.unwrap_or_else(|| unreachable!("Only declare function can have no body")),
|
||||
)
|
||||
.map(|type_annotation| self.ast.ts_type_annotation(SPAN, type_annotation));
|
||||
|
||||
if return_type.is_none() {
|
||||
self.error(function_must_have_explicit_return_type(function));
|
||||
|
||||
Some(self.ast.ts_type_annotation(SPAN, self.ast.ts_unknown_keyword(SPAN)))
|
||||
} else {
|
||||
return_type
|
||||
}
|
||||
.map(|type_annotation| self.ast.ts_type_annotation(SPAN, type_annotation))
|
||||
}
|
||||
|
||||
pub fn infer_arrow_function_return_type(
|
||||
|
|
@ -133,6 +123,14 @@ impl<'a> IsolatedDeclarations<'a> {
|
|||
return self.ast.copy(&function.return_type);
|
||||
}
|
||||
|
||||
if function.r#async {
|
||||
return None;
|
||||
}
|
||||
|
||||
if function.r#async {
|
||||
return None;
|
||||
}
|
||||
|
||||
if function.expression {
|
||||
if let Some(Statement::ExpressionStatement(stmt)) = function.body.statements.first() {
|
||||
return self
|
||||
|
|
@ -140,6 +138,7 @@ impl<'a> IsolatedDeclarations<'a> {
|
|||
.map(|type_annotation| self.ast.ts_type_annotation(SPAN, type_annotation));
|
||||
}
|
||||
}
|
||||
|
||||
FunctionReturnType::infer(self, &function.body)
|
||||
.map(|type_annotation| self.ast.ts_type_annotation(SPAN, type_annotation))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use oxc_allocator::Box;
|
|||
use oxc_ast::Visit;
|
||||
use oxc_span::{GetSpan, SPAN};
|
||||
|
||||
use crate::IsolatedDeclarations;
|
||||
use crate::{diagnostics::default_export_inferred, IsolatedDeclarations};
|
||||
|
||||
impl<'a> IsolatedDeclarations<'a> {
|
||||
pub fn transform_export_named_declaration(
|
||||
|
|
@ -46,6 +46,7 @@ impl<'a> IsolatedDeclarations<'a> {
|
|||
} else {
|
||||
// declare const _default: Type
|
||||
let kind = VariableDeclarationKind::Const;
|
||||
// TODO: create unique name for this
|
||||
let name = self.ast.new_atom("_default");
|
||||
let id = self
|
||||
.ast
|
||||
|
|
@ -54,6 +55,10 @@ impl<'a> IsolatedDeclarations<'a> {
|
|||
.infer_type_from_expression(expr)
|
||||
.map(|ts_type| self.ast.ts_type_annotation(SPAN, ts_type));
|
||||
|
||||
if type_annotation.is_none() {
|
||||
self.error(default_export_inferred(expr.span()));
|
||||
}
|
||||
|
||||
let id = BindingPattern { kind: id, type_annotation, optional: false };
|
||||
let declarations = self
|
||||
.ast
|
||||
|
|
|
|||
|
|
@ -4,13 +4,23 @@ use oxc_ast::ast::{
|
|||
TSTypeOperatorOperator,
|
||||
};
|
||||
use oxc_diagnostics::OxcDiagnostic;
|
||||
use oxc_span::SPAN;
|
||||
use oxc_span::{GetSpan, SPAN};
|
||||
|
||||
use crate::IsolatedDeclarations;
|
||||
use crate::{
|
||||
diagnostics::{
|
||||
function_must_have_explicit_return_type, inferred_type_of_expression, shorthand_property,
|
||||
},
|
||||
function::get_function_span,
|
||||
IsolatedDeclarations,
|
||||
};
|
||||
|
||||
impl<'a> IsolatedDeclarations<'a> {
|
||||
pub fn transform_function_to_ts_type(&self, func: &Function<'a>) -> Option<TSType<'a>> {
|
||||
let return_type = self.infer_function_return_type(func);
|
||||
if return_type.is_none() {
|
||||
self.error(function_must_have_explicit_return_type(get_function_span(func)));
|
||||
}
|
||||
|
||||
let params = self.transform_formal_parameters(&func.params);
|
||||
|
||||
return_type.map(|return_type| {
|
||||
|
|
@ -29,6 +39,11 @@ impl<'a> IsolatedDeclarations<'a> {
|
|||
func: &ArrowFunctionExpression<'a>,
|
||||
) -> Option<TSType<'a>> {
|
||||
let return_type = self.infer_arrow_function_return_type(func);
|
||||
|
||||
if return_type.is_none() {
|
||||
self.error(function_must_have_explicit_return_type(func.span));
|
||||
}
|
||||
|
||||
let params = self.transform_formal_parameters(&func.params);
|
||||
|
||||
return_type.map(|return_type| {
|
||||
|
|
@ -66,6 +81,11 @@ impl<'a> IsolatedDeclarations<'a> {
|
|||
return None;
|
||||
}
|
||||
|
||||
if object.shorthand {
|
||||
self.error(shorthand_property(object.span));
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Expression::FunctionExpression(function) = &object.value {
|
||||
if !is_const && object.method {
|
||||
let return_type = self.infer_function_return_type(function);
|
||||
|
|
@ -86,6 +106,11 @@ impl<'a> IsolatedDeclarations<'a> {
|
|||
|
||||
let type_annotation = self.infer_type_from_expression(&object.value);
|
||||
|
||||
if type_annotation.is_none() {
|
||||
self.error(inferred_type_of_expression(object.value.span()));
|
||||
return None;
|
||||
}
|
||||
|
||||
let property_signature = self.ast.ts_property_signature(
|
||||
object.span,
|
||||
false,
|
||||
|
|
|
|||
Loading…
Reference in a new issue