use swc_common::Span;
use swc_ecma_ast::*;
pub(super) fn is_ts_ambient_initializer(expr: &Expr) -> bool {
match expr {
Expr::Lit(Lit::Bool(_) | Lit::BigInt(_)) => true,
Expr::Unary(UnaryExpr {
op: UnaryOp::Minus,
arg,
..
}) if matches!(&**arg, Expr::Lit(Lit::BigInt(_))) => true,
Expr::Member(member) => {
let mut object = &*member.obj;
while let Expr::Member(MemberExpr {
obj,
prop: MemberProp::Ident(_),
..
}) = object
{
object = obj;
}
if !matches!(object, Expr::Ident(_)) {
return false;
}
match &member.prop {
MemberProp::Ident(_) => true,
MemberProp::Computed(key) => is_ts_ambient_string_or_number(&key.expr),
_ => false,
}
}
_ => is_ts_ambient_string_or_number(expr),
}
}
fn is_ts_ambient_string_or_number(expr: &Expr) -> bool {
match expr {
Expr::Lit(Lit::Str(_) | Lit::Num(_)) => true,
Expr::Tpl(template) => template.exprs.is_empty(),
Expr::Unary(UnaryExpr {
op: UnaryOp::Minus,
arg,
..
}) => matches!(&**arg, Expr::Lit(Lit::Num(_))),
_ => false,
}
}
pub trait IsSimpleParameterList {
fn is_simple_parameter_list(&self) -> bool;
}
impl IsSimpleParameterList for Vec<Param> {
fn is_simple_parameter_list(&self) -> bool {
self.iter().all(|param| matches!(param.pat, Pat::Ident(_)))
}
}
impl IsSimpleParameterList for Vec<Pat> {
fn is_simple_parameter_list(&self) -> bool {
self.iter().all(|pat| matches!(pat, Pat::Ident(_)))
}
}
impl IsSimpleParameterList for Vec<ParamOrTsParamProp> {
fn is_simple_parameter_list(&self) -> bool {
self.iter().all(|param| {
matches!(
param,
ParamOrTsParamProp::TsParamProp(..)
| ParamOrTsParamProp::Param(Param {
pat: Pat::Ident(_),
..
})
)
})
}
}
pub trait IsInvalidClassName {
fn invalid_class_name(&self) -> Option<Span>;
}
impl IsInvalidClassName for Ident {
fn invalid_class_name(&self) -> Option<Span> {
match &*self.sym {
"string" | "null" | "number" | "object" | "any" | "unknown" | "boolean" | "bigint"
| "symbol" | "void" | "never" | "intrinsic" => Some(self.span),
_ => None,
}
}
}
impl IsInvalidClassName for Option<Ident> {
fn invalid_class_name(&self) -> Option<Span> {
self.as_ref().and_then(|i| i.invalid_class_name())
}
}
pub trait ExprExt {
fn as_expr(&self) -> &Expr;
fn is_valid_simple_assignment_target(&self, strict: bool) -> bool {
match self.as_expr() {
Expr::Ident(ident) => {
if strict && ident.is_reserved_in_strict_bind() {
return false;
}
true
}
Expr::This(..)
| Expr::Lit(..)
| Expr::Array(..)
| Expr::Object(..)
| Expr::Fn(..)
| Expr::Class(..)
| Expr::Tpl(..)
| Expr::TaggedTpl(..) => false,
Expr::Paren(ParenExpr { expr, .. }) => expr.is_valid_simple_assignment_target(strict),
Expr::Member(MemberExpr { obj, .. }) => match obj.as_ref() {
Expr::Member(..) => obj.is_valid_simple_assignment_target(strict),
Expr::OptChain(..) => false,
_ => true,
},
Expr::SuperProp(..) => true,
Expr::New(..) | Expr::Call(..) => false,
Expr::MetaProp(..) => false,
Expr::Update(..) => false,
Expr::Unary(..) | Expr::Await(..) => false,
Expr::Bin(..) => false,
Expr::Cond(..) => false,
Expr::Yield(..) | Expr::Arrow(..) | Expr::Assign(..) => false,
Expr::Seq(..) => false,
Expr::OptChain(..) => false,
Expr::PrivateName(..) => false,
Expr::JSXMember(..)
| Expr::JSXNamespacedName(..)
| Expr::JSXEmpty(..)
| Expr::JSXElement(..)
| Expr::JSXFragment(..) => false,
Expr::TsNonNull(TsNonNullExpr { ref expr, .. })
| Expr::TsTypeAssertion(TsTypeAssertion { ref expr, .. })
| Expr::TsAs(TsAsExpr { ref expr, .. })
| Expr::TsInstantiation(TsInstantiation { ref expr, .. })
| Expr::TsSatisfies(TsSatisfiesExpr { ref expr, .. }) => {
expr.is_valid_simple_assignment_target(strict)
}
Expr::TsConstAssertion(..) => false,
Expr::Invalid(..) => false,
#[cfg(swc_ast_unknown)]
_ => unreachable!(),
}
}
}
impl ExprExt for Box<Expr> {
#[inline(always)]
fn as_expr(&self) -> &Expr {
self
}
}
impl ExprExt for Expr {
#[inline(always)]
fn as_expr(&self) -> &Expr {
self
}
}