Skip to content

Commit

Permalink
fix(typescript): Collect usages in extend clauses of classes and inte…
Browse files Browse the repository at this point in the history
…rfaces (#9893)

fixes #9875
  • Loading branch information
CPunisher authored Jan 17, 2025
1 parent aee2780 commit ef29ef6
Show file tree
Hide file tree
Showing 10 changed files with 77 additions and 40 deletions.
5 changes: 5 additions & 0 deletions .changeset/calm-pumpkins-explain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
swc_typescript: patch
---

fix(typescript): Collect usages in extend clauses of classes and interfaces
9 changes: 2 additions & 7 deletions crates/swc_typescript/src/fast_dts/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,14 @@ use swc_ecma_ast::{

use super::{
type_ann,
util::ast_ext::{MemberExprExt, PatExt, PropNameExit},
util::ast_ext::{ExprExit, PatExt, PropNameExit},
FastDts,
};

impl FastDts {
pub(crate) fn transform_class(&mut self, class: &mut Class) {
if let Some(super_class) = &class.super_class {
let is_not_allowed = match super_class.as_ref() {
Expr::Ident(_) => false,
Expr::Member(member_expr) => !member_expr.get_first_object().is_ident(),
_ => true,
};

let is_not_allowed = super_class.get_root_ident().is_none();
if is_not_allowed {
self.extends_clause_expression(super_class.span());
}
Expand Down
10 changes: 10 additions & 0 deletions crates/swc_typescript/src/fast_dts/enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,16 @@ impl FastDts {
None
}
}
Expr::OptChain(opt_chain) => {
let member = opt_chain.base.as_member()?;
let ident = member.obj.as_ident()?;
if &ident.sym == enum_name {
let name = member.prop.static_name()?;
prev_members.get(name).cloned()
} else {
None
}
}
_ => None,
}
}
Expand Down
5 changes: 2 additions & 3 deletions crates/swc_typescript/src/fast_dts/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use super::{
inferrer::ReturnTypeInferrer,
type_ann,
util::{
ast_ext::{MemberExprExt, PatExt},
ast_ext::{ExprExit, PatExt},
types::{ts_keyword_type, ts_lit_type},
},
FastDts,
Expand Down Expand Up @@ -351,8 +351,7 @@ impl FastDts {
}

let is_not_allowed = match key {
Expr::Ident(_) => false,
Expr::Member(member) => !member.get_first_object().is_ident(),
Expr::Ident(_) | Expr::Member(_) | Expr::OptChain(_) => key.get_root_ident().is_none(),
_ => !Self::is_literal(key),
};

Expand Down
46 changes: 19 additions & 27 deletions crates/swc_typescript/src/fast_dts/util/ast_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,27 @@ use std::borrow::Cow;

use swc_atoms::Atom;
use swc_ecma_ast::{
BindingIdent, Expr, Lit, MemberExpr, MemberProp, ObjectPatProp, Pat, PropName, TsTypeAnn,
BindingIdent, Expr, Ident, Lit, MemberProp, ObjectPatProp, Pat, PropName, TsTypeAnn,
};

pub trait ExprExit {
fn get_root_ident(&self) -> Option<&Ident>;
}

impl ExprExit for Expr {
fn get_root_ident(&self) -> Option<&Ident> {
match self {
Expr::Member(member_expr) => member_expr.obj.get_root_ident(),
Expr::Ident(ident) => Some(ident),
Expr::OptChain(opt_chain_expr) => opt_chain_expr
.base
.as_member()
.and_then(|member_expr| member_expr.obj.get_root_ident()),
_ => None,
}
}
}

pub trait PatExt {
fn get_type_ann(&self) -> &Option<Box<TsTypeAnn>>;
fn set_type_ann(&mut self, type_anno: Option<Box<TsTypeAnn>>);
Expand Down Expand Up @@ -119,29 +137,3 @@ impl MemberPropExt for MemberProp {
}
}
}

pub trait MemberExprExt {
fn get_first_object(&self) -> &Expr;
}

impl MemberExprExt for MemberExpr {
fn get_first_object(&self) -> &Expr {
let mut object = &self.obj;
loop {
match object.as_ref() {
Expr::Member(member_expr) => {
object = &member_expr.obj;
continue;
}
Expr::OptChain(opt_chain) => {
if let Some(member_expr) = opt_chain.base.as_member() {
object = &member_expr.obj;
continue;
}
}
_ => {}
}
break object;
}
}
}
8 changes: 5 additions & 3 deletions crates/swc_typescript/src/fast_dts/visitors/type_usage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use swc_ecma_ast::{
};
use swc_ecma_visit::{Visit, VisitWith};

use crate::fast_dts::util::ast_ext::ExprExit;

pub struct TypeUsageAnalyzer<'a> {
graph: DiGraph<Id, ()>,
nodes: FxHashMap<Id, NodeIndex>,
Expand Down Expand Up @@ -99,14 +101,14 @@ impl TypeUsageAnalyzer<'_> {

impl Visit for TypeUsageAnalyzer<'_> {
fn visit_ts_property_signature(&mut self, node: &TsPropertySignature) {
if let Some(ident) = node.key.as_ident() {
if let Some(ident) = node.key.get_root_ident() {
self.add_edge(ident.to_id(), true);
}
node.visit_children_with(self);
}

fn visit_ts_expr_with_type_args(&mut self, node: &TsExprWithTypeArgs) {
if let Some(ident) = node.expr.as_ident() {
if let Some(ident) = node.expr.get_root_ident() {
self.add_edge(ident.to_id(), true);
}
node.visit_children_with(self);
Expand Down Expand Up @@ -238,7 +240,7 @@ impl Visit for TypeUsageAnalyzer<'_> {

fn visit_class(&mut self, node: &Class) {
if let Some(super_class) = &node.super_class {
if let Some(ident) = super_class.as_ident() {
if let Some(ident) = super_class.get_root_ident() {
self.add_edge(ident.to_id(), true);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ export type B = {
["foo" as string]: number;
["bar" as string](a: number): string;
};
export type C = {
[D?.b]: number;
};
==================== Errors ====================
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ export type B = {
["foo" as string]: number;
["bar" as string](a: number): string;
};

export type C = {
[D?.b]: number;
};
16 changes: 16 additions & 0 deletions crates/swc_typescript/tests/fixture/type-usage.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
```==================== .D.TS ====================
import type * as Member from "some-path/my_module";
export interface IMember extends Member.C<"SimpleEntity"> {
}
import type * as Ident from "some-path/my_module";
export interface IIdent extends Ident {
}
import * as Paren from "some-path/my_module";
export declare class CParen extends Paren {
}
import * as OptChain from "some-path/my_module";
export declare class COptChain extends OptChain?.C<"SimpleEntity"> {
}
11 changes: 11 additions & 0 deletions crates/swc_typescript/tests/fixture/type-usage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type * as Member from "some-path/my_module";
export interface IMember extends Member.C<"SimpleEntity"> {}

import type * as Ident from "some-path/my_module";
export interface IIdent extends Ident {}

import * as Paren from "some-path/my_module";
export class CParen extends Paren {}

import * as OptChain from "some-path/my_module";
export class COptChain extends OptChain?.C<"SimpleEntity"> {}

0 comments on commit ef29ef6

Please sign in to comment.