feat(transformer-dts): report error for invalid signature property key (#3698)

This commit is contained in:
Dunqing 2024-06-16 16:10:14 +08:00 committed by GitHub
parent d65c652700
commit af5009a591
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 78 additions and 35 deletions

View file

@ -2,25 +2,31 @@
use oxc_ast::ast::*;
use oxc_allocator::Box;
use oxc_diagnostics::OxcDiagnostic;
use oxc_span::{GetSpan, SPAN};
use crate::TransformerDts;
use crate::{diagnostics::computed_property_name, TransformerDts};
impl<'a> TransformerDts<'a> {
pub fn is_literal_key(&self, key: &PropertyKey<'a>) -> bool {
match key {
PropertyKey::StringLiteral(_)
| PropertyKey::NumericLiteral(_)
| PropertyKey::BigintLiteral(_) => true,
PropertyKey::TemplateLiteral(l) => l.expressions.is_empty(),
PropertyKey::UnaryExpression(expr) => {
expr.operator.is_arithmetic()
&& matches!(
expr.argument,
Expression::NumericLiteral(_) | Expression::BigintLiteral(_)
)
}
_ => false,
}
}
pub fn report_property_key(&self, key: &PropertyKey<'a>, computed: bool) -> bool {
if computed
&& !matches!(
key,
PropertyKey::StringLiteral(_)
| PropertyKey::NumericLiteral(_)
| PropertyKey::BigintLiteral(_)
)
{
self.ctx.error(
OxcDiagnostic::error("Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.")
.with_label(key.span())
);
if computed && self.is_literal_key(key) {
computed_property_name(key.span());
true
} else {
false

View file

@ -7,7 +7,7 @@ use oxc_diagnostics::OxcDiagnostic;
use oxc_span::{GetSpan, SPAN};
use oxc_syntax::scope::ScopeFlags;
use crate::TransformerDts;
use crate::{diagnostics::signature_computed_property_name, TransformerDts};
impl<'a> TransformerDts<'a> {
pub fn transform_variable_declaration(
@ -195,23 +195,25 @@ impl<'a> TransformerDts<'a> {
None
}
}
Declaration::TSTypeAliasDeclaration(decl) => {
if !check_binding || self.scope.has_reference(&decl.id.name) {
Some(Declaration::TSTypeAliasDeclaration(self.ctx.ast.copy(decl)))
Declaration::TSTypeAliasDeclaration(alias_decl) => {
self.visit_ts_type_alias_declaration(alias_decl);
if !check_binding || self.scope.has_reference(&alias_decl.id.name) {
Some(self.ctx.ast.copy(decl))
} else {
None
}
}
Declaration::TSInterfaceDeclaration(decl) => {
if !check_binding || self.scope.has_reference(&decl.id.name) {
Some(Declaration::TSInterfaceDeclaration(self.ctx.ast.copy(decl)))
Declaration::TSInterfaceDeclaration(interface_decl) => {
self.visit_ts_interface_declaration(interface_decl);
if !check_binding || self.scope.has_reference(&interface_decl.id.name) {
Some(self.ctx.ast.copy(decl))
} else {
None
}
}
Declaration::TSEnumDeclaration(decl) => {
if !check_binding || self.scope.has_reference(&decl.id.name) {
Some(Declaration::TSEnumDeclaration(self.ctx.ast.copy(decl)))
Declaration::TSEnumDeclaration(enum_decl) => {
if !check_binding || self.scope.has_reference(&enum_decl.id.name) {
Some(self.ctx.ast.copy(decl))
} else {
None
}
@ -240,4 +242,35 @@ impl<'a> TransformerDts<'a> {
}
}
}
fn report_signature_property_key(&self, key: &PropertyKey<'a>, computed: bool) {
if !computed {
return;
}
let is_not_allowed = match key {
PropertyKey::StaticIdentifier(_) | PropertyKey::Identifier(_) => false,
PropertyKey::StaticMemberExpression(expr) => {
let mut object = &expr.object;
while let Expression::StaticMemberExpression(expr) = &object {
object = &expr.object;
}
!object.is_identifier_reference()
}
key => !self.is_literal_key(key),
};
if is_not_allowed {
self.ctx.error(signature_computed_property_name(key.span()));
}
}
}
impl<'a> Visit<'a> for TransformerDts<'a> {
fn visit_ts_method_signature(&mut self, signature: &TSMethodSignature<'a>) {
self.report_signature_property_key(&signature.key, signature.computed);
}
fn visit_ts_property_signature(&mut self, signature: &TSPropertySignature<'a>) {
self.report_signature_property_key(&signature.key, signature.computed);
}
}

View file

@ -21,3 +21,13 @@ pub fn type_containing_private_name(name: &Atom<'_>, span: Span) -> OxcDiagnosti
))
.with_label(span)
}
pub fn computed_property_name(span: Span) -> OxcDiagnostic {
OxcDiagnostic::error("Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.")
.with_label(span)
}
pub fn signature_computed_property_name(span: Span) -> OxcDiagnostic {
OxcDiagnostic::error("Computed properties must be number or string literals, variables or dotted expressions with --isolatedDeclarations.")
.with_label(span)
}

View file

@ -2,6 +2,7 @@
use oxc_ast::ast::*;
use oxc_allocator::Box;
use oxc_ast::Visit;
use oxc_span::{GetSpan, SPAN};
use crate::TransformerDts;
@ -34,12 +35,9 @@ impl<'a> TransformerDts<'a> {
ExportDefaultDeclarationKind::ClassDeclaration(decl) => self
.transform_class(decl)
.map(|d| (None, ExportDefaultDeclarationKind::ClassDeclaration(d))),
ExportDefaultDeclarationKind::TSInterfaceDeclaration(decl) => {
// TODO: need to transform TSInterfaceDeclaration
Some((
None,
ExportDefaultDeclarationKind::TSInterfaceDeclaration(self.ctx.ast.copy(decl)),
))
ExportDefaultDeclarationKind::TSInterfaceDeclaration(interface_decl) => {
self.visit_ts_interface_declaration(interface_decl);
Some((None, self.ctx.ast.copy(&decl.declaration)))
}
expr @ match_expression!(ExportDefaultDeclarationKind) => {
let expr = expr.to_expression();

View file

@ -62,11 +62,7 @@ impl<'a> TransformerDts<'a> {
let members =
self.ctx.ast.new_vec_from_iter(expr.properties.iter().filter_map(|property| match property {
ObjectPropertyKind::ObjectProperty(object) => {
if object.computed {
self.ctx.error(
OxcDiagnostic::error("Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.")
.with_label(object.span)
);
if self.report_property_key(&object.key, object.computed) {
return None;
}