Skip to content

Commit

Permalink
feat(transformer/typescript): typescript syntax within SimpleAssignme…
Browse files Browse the repository at this point in the history
…ntTarget with MemberExpressions is not stripped
  • Loading branch information
Dunqing committed Aug 16, 2024
1 parent 508644a commit 2549549
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 7 deletions.
22 changes: 22 additions & 0 deletions crates/oxc_ast/src/ast_builder_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,35 @@ impl<'a> AstBuilder<'a> {
unsafe { std::mem::transmute_copy(src) }
}

/// Moves the identifier reference out by replacing it with a dummy identifier reference.
#[inline]
pub fn move_identifier_reference(
self,
expr: &mut IdentifierReference<'a>,
) -> IdentifierReference<'a> {
let dummy = self.identifier_reference(expr.span(), "");
mem::replace(expr, dummy)
}

/// Moves the expression out by replacing it with a null expression.
#[inline]
pub fn move_expression(self, expr: &mut Expression<'a>) -> Expression<'a> {
let null_expr = self.expression_null_literal(expr.span());
mem::replace(expr, null_expr)
}

/// Moves the member expression out by replacing it with a dummy expression.
#[inline]
pub fn move_member_expression(self, expr: &mut MemberExpression<'a>) -> MemberExpression<'a> {
let dummy = self.member_expression_computed(
expr.span(),
self.expression_null_literal(expr.span()),
self.expression_null_literal(expr.span()),
false,
);
mem::replace(expr, dummy)
}

#[inline]
pub fn move_statement(self, stmt: &mut Statement<'a>) -> Statement<'a> {
let empty_stmt = self.empty_statement(stmt.span());
Expand Down
25 changes: 25 additions & 0 deletions crates/oxc_ast/src/ast_impl/js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,20 @@ impl<'a> Expression<'a> {
}
}

pub fn get_inner_expression_mut(&mut self) -> &mut Expression<'a> {
match self {
Expression::ParenthesizedExpression(expr) => expr.expression.get_inner_expression_mut(),
Expression::TSAsExpression(expr) => expr.expression.get_inner_expression_mut(),
Expression::TSSatisfiesExpression(expr) => expr.expression.get_inner_expression_mut(),
Expression::TSInstantiationExpression(expr) => {
expr.expression.get_inner_expression_mut()
}
Expression::TSNonNullExpression(expr) => expr.expression.get_inner_expression_mut(),
Expression::TSTypeAssertion(expr) => expr.expression.get_inner_expression_mut(),
_ => self,
}
}

pub fn is_identifier_reference(&self) -> bool {
matches!(self, Expression::Identifier(_))
}
Expand Down Expand Up @@ -632,6 +646,17 @@ impl<'a> SimpleAssignmentTarget<'a> {
_ => None,
}
}

pub fn get_expression_mut(&mut self) -> Option<&mut Expression<'a>> {
match self {
Self::TSAsExpression(expr) => Some(&mut expr.expression),
Self::TSSatisfiesExpression(expr) => Some(&mut expr.expression),
Self::TSNonNullExpression(expr) => Some(&mut expr.expression),
Self::TSTypeAssertion(expr) => Some(&mut expr.expression),
Self::TSInstantiationExpression(expr) => Some(&mut expr.expression),
_ => None,
}
}
}

impl<'a> ArrayAssignmentTarget<'a> {
Expand Down
24 changes: 19 additions & 5 deletions crates/oxc_transformer/src/typescript/annotations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::{cell::Cell, rc::Rc};

use oxc_allocator::Vec as ArenaVec;
use oxc_ast::ast::*;
use oxc_diagnostics::OxcDiagnostic;
use oxc_semantic::SymbolFlags;
use oxc_span::{Atom, GetSpan, Span, SPAN};
use oxc_syntax::{
Expand Down Expand Up @@ -222,11 +223,24 @@ impl<'a> TypeScriptAnnotations<'a> {
}

pub fn transform_simple_assignment_target(&mut self, target: &mut SimpleAssignmentTarget<'a>) {
if let Some(expr) = target.get_expression() {
if let Expression::Identifier(ident) = expr.get_inner_expression() {
// SAFETY: `ast.copy` is unsound! We need to fix.
let ident = unsafe { self.ctx.ast.copy(ident) };
*target = SimpleAssignmentTarget::AssignmentTargetIdentifier(ident);
if let Some(expr) = target.get_expression_mut() {
match expr.get_inner_expression_mut() {
// `foo!++` to `foo++`
Expression::Identifier(ident) => {
*target = self.ctx.ast.simple_assignment_target_from_identifier_reference(
self.ctx.ast.move_identifier_reference(ident),
);
}
// `foo.bar!++` to `foo.bar++`
inner_expr @ match_member_expression!(Expression) => {
*target = SimpleAssignmentTarget::from(
self.ctx.ast.move_member_expression(inner_expr.to_member_expression_mut()),
);
}
_ => {
// This should be never hit until more syntax is added to the JavaScript/TypeScrips
self.ctx.error(OxcDiagnostic::error("Cannot strip out typescript syntax if SimpleAssignmentTarget is not an IdentifierReference or MemberExpression"));
}
}
}
}
Expand Down
3 changes: 1 addition & 2 deletions tasks/coverage/transformer_typescript.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ commit: d8086f14

transformer_typescript Summary:
AST Parsed : 6456/6456 (100.00%)
Positive Passed: 6452/6456 (99.94%)
Positive Passed: 6453/6456 (99.95%)
Mismatch: "compiler/constEnumNamespaceReferenceCausesNoImport2.ts"
Mismatch: "compiler/incrementOnNullAssertion.ts"
Mismatch: "conformance/externalModules/typeOnly/exportDeclaration.ts"
Mismatch: "conformance/jsx/inline/inlineJsxAndJsxFragPragmaOverridesCompilerOptions.tsx"

0 comments on commit 2549549

Please sign in to comment.