feat(es/parser): Implement explicit resource management (#7322)

**Description:**

 - Add `UsingDecl`.
 - Add `UsingDecl` to `Decl`.
 - Rename `VarDeclOrPat` to `ForHead`.
 - Add `UsingDecl` to `ForHead`.
 - Implement parser for using declarations.

**Related issue:**

 - #7316.
This commit is contained in:
Donny/강동윤 2023-05-10 13:16:44 +09:00 committed by GitHub
parent 6432e1f5c5
commit 041b491466
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
99 changed files with 2057 additions and 125 deletions

View File

@ -870,8 +870,8 @@ XPathExpression
XPathResult
XSLTProcessor
__proto__
_define_property
_defineProperty
_define_property
_extends
_toConsumableArray
a
@ -2374,6 +2374,7 @@ url
use
usemap
user-select
using
values
var
vb

View File

@ -892,7 +892,8 @@ where
Decl::TsInterface(_)
| Decl::TsTypeAlias(_)
| Decl::TsEnum(_)
| Decl::TsModule(_) => continue,
| Decl::TsModule(_)
| Decl::Using(..) => continue,
};
tracing::trace!(

View File

@ -540,6 +540,7 @@ fn mark(item: &mut ModuleItem, ctxt: SyntaxContext) {
Decl::Class(ClassDecl { class: v, .. }) => v.span.ctxt = ctxt,
Decl::Fn(FnDecl { function: v, .. }) => v.span.ctxt = ctxt,
Decl::Var(v) => v.span.ctxt = ctxt,
Decl::Using(u) => u.span.ctxt = ctxt,
Decl::TsInterface(v) => v.span.ctxt = ctxt,
Decl::TsTypeAlias(v) => v.span.ctxt = ctxt,
Decl::TsEnum(v) => v.span.ctxt = ctxt,

View File

@ -22,6 +22,9 @@ pub enum Decl {
Fn(FnDecl),
#[tag("VariableDeclaration")]
Var(Box<VarDecl>),
#[tag("UsingDeclaration")]
Using(Box<UsingDecl>),
#[tag("TsInterfaceDeclaration")]
TsInterface(Box<TsInterfaceDecl>),
#[tag("TsTypeAliasDeclaration")]
@ -33,6 +36,7 @@ pub enum Decl {
}
bridge_decl_from!(Box<VarDecl>, VarDecl);
bridge_decl_from!(Box<UsingDecl>, UsingDecl);
bridge_decl_from!(Box<TsInterfaceDecl>, TsInterfaceDecl);
bridge_decl_from!(Box<TsTypeAliasDecl>, TsTypeAliasDecl);
bridge_decl_from!(Box<TsEnumDecl>, TsEnumDecl);
@ -166,3 +170,21 @@ impl Take for VarDeclarator {
}
}
}
#[ast_node("UsingDeclaration")]
#[derive(Eq, Hash, EqIgnoreSpan)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct UsingDecl {
pub span: Span,
pub decls: Vec<VarDeclarator>,
}
impl Take for UsingDecl {
fn dummy() -> Self {
Self {
span: DUMMY_SP,
decls: Take::dummy(),
}
}
}

View File

@ -18,7 +18,7 @@ pub use self::{
AutoAccessor, Class, ClassMember, ClassMethod, ClassProp, Constructor, Decorator, Key,
MethodKind, PrivateMethod, PrivateProp, StaticBlock,
},
decl::{ClassDecl, Decl, FnDecl, VarDecl, VarDeclKind, VarDeclarator},
decl::{ClassDecl, Decl, FnDecl, UsingDecl, VarDecl, VarDeclKind, VarDeclarator},
expr::{
ArrayLit, ArrowExpr, AssignExpr, AwaitExpr, BinExpr, BlockStmtOrExpr, CallExpr, Callee,
ClassExpr, CondExpr, Expr, ExprOrSpread, FnExpr, Import, MemberExpr, MemberProp,
@ -54,8 +54,8 @@ pub use self::{
source_map::{SourceMapperExt, SpanExt},
stmt::{
BlockStmt, BreakStmt, CatchClause, ContinueStmt, DebuggerStmt, DoWhileStmt, EmptyStmt,
ExprStmt, ForInStmt, ForOfStmt, ForStmt, IfStmt, LabeledStmt, ReturnStmt, Stmt, SwitchCase,
SwitchStmt, ThrowStmt, TryStmt, VarDeclOrExpr, VarDeclOrPat, WhileStmt, WithStmt,
ExprStmt, ForHead, ForInStmt, ForOfStmt, ForStmt, IfStmt, LabeledStmt, ReturnStmt, Stmt,
SwitchCase, SwitchStmt, ThrowStmt, TryStmt, VarDeclOrExpr, WhileStmt, WithStmt,
},
typescript::{
Accessibility, TruePlusMinus, TsArrayType, TsAsExpr, TsCallSignatureDecl,

View File

@ -6,6 +6,7 @@ use crate::{
expr::Expr,
ident::Ident,
pat::Pat,
UsingDecl,
};
/// Use when only block statements are allowed.
@ -303,7 +304,7 @@ pub struct ForStmt {
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct ForInStmt {
pub span: Span,
pub left: VarDeclOrPat,
pub left: ForHead,
pub right: Box<Expr>,
pub body: Box<Stmt>,
}
@ -320,7 +321,7 @@ pub struct ForOfStmt {
/// for-await-of statements, e.g., `for await (const x of xs) {`
#[cfg_attr(feature = "serde-impl", serde(default, rename = "await"))]
pub is_await: bool,
pub left: VarDeclOrPat,
pub left: ForHead,
pub right: Box<Expr>,
pub body: Box<Stmt>,
}
@ -376,23 +377,27 @@ pub struct CatchClause {
pub body: BlockStmt,
}
/// A head for for-in and for-of loop.
#[ast_node]
#[derive(Eq, Hash, Is, EqIgnoreSpan)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum VarDeclOrPat {
pub enum ForHead {
#[tag("VariableDeclaration")]
VarDecl(Box<VarDecl>),
#[tag("UsingDeclaration")]
UsingDecl(Box<UsingDecl>),
#[tag("*")]
Pat(Box<Pat>),
}
bridge_from!(VarDeclOrPat, Box<VarDecl>, VarDecl);
bridge_from!(VarDeclOrPat, Box<Pat>, Pat);
bridge_from!(ForHead, Box<VarDecl>, VarDecl);
bridge_from!(ForHead, Box<Pat>, Pat);
impl Take for VarDeclOrPat {
impl Take for ForHead {
fn dummy() -> Self {
VarDeclOrPat::Pat(Take::dummy())
ForHead::Pat(Take::dummy())
}
}

View File

@ -12,7 +12,7 @@ where
{
#[emitter]
fn emit_decl(&mut self, node: &Decl) -> Result {
match *node {
match node {
Decl::Class(ref n) => emit!(n),
Decl::Fn(ref n) => emit!(n),
@ -21,6 +21,7 @@ where
formatting_semi!();
srcmap!(n, false);
}
Decl::Using(n) => emit!(n),
Decl::TsEnum(ref n) => emit!(n),
Decl::TsInterface(ref n) => emit!(n),
Decl::TsModule(ref n) => emit!(n),
@ -33,6 +34,20 @@ where
self.emit_class_decl_inner(node, false)?;
}
#[emitter]
fn emit_using_decl(&mut self, node: &UsingDecl) -> Result {
self.emit_leading_comments_of_span(node.span(), false)?;
keyword!("using");
space!();
self.emit_list(
node.span,
Some(&node.decls),
ListFormat::VariableDeclarationList,
)?;
}
pub(super) fn emit_class_decl_inner(
&mut self,
node: &ClassDecl,

View File

@ -2676,10 +2676,11 @@ where
}
#[emitter]
fn emit_var_decl_or_pat(&mut self, node: &VarDeclOrPat) -> Result {
match *node {
VarDeclOrPat::Pat(ref n) => emit!(n),
VarDeclOrPat::VarDecl(ref n) => emit!(n),
fn emit_for_head(&mut self, node: &ForHead) -> Result {
match node {
ForHead::Pat(n) => emit!(n),
ForHead::VarDecl(n) => emit!(n),
ForHead::UsingDecl(n) => emit!(n),
}
}
}

View File

@ -4,11 +4,12 @@ pub trait EndsWithAlphaNum {
fn ends_with_alpha_num(&self) -> bool;
}
impl EndsWithAlphaNum for VarDeclOrPat {
impl EndsWithAlphaNum for ForHead {
fn ends_with_alpha_num(&self) -> bool {
match self {
VarDeclOrPat::VarDecl(n) => n.ends_with_alpha_num(),
VarDeclOrPat::Pat(n) => n.ends_with_alpha_num(),
ForHead::VarDecl(n) => n.ends_with_alpha_num(),
ForHead::Pat(n) => n.ends_with_alpha_num(),
ForHead::UsingDecl(n) => n.ends_with_alpha_num(),
}
}
}
@ -37,6 +38,18 @@ impl EndsWithAlphaNum for VarDecl {
}
}
impl EndsWithAlphaNum for UsingDecl {
fn ends_with_alpha_num(&self) -> bool {
match self.decls.last() {
None => true,
Some(d) => match d.init.as_deref() {
Some(e) => e.ends_with_alpha_num(),
None => d.name.ends_with_alpha_num(),
},
}
}
}
impl EndsWithAlphaNum for Expr {
fn ends_with_alpha_num(&self) -> bool {
!matches!(
@ -230,7 +243,8 @@ impl StartsWithAlphaNum for Decl {
| Decl::TsEnum(..)
| Decl::TsInterface(..)
| Decl::TsModule(..)
| Decl::TsTypeAlias(..) => true,
| Decl::TsTypeAlias(..)
| Decl::Using(..) => true,
}
}
}

View File

@ -255,7 +255,7 @@ impl Visit for NoParamReassign {
}
fn visit_for_of_stmt(&mut self, for_of_stmt: &ForOfStmt) {
if let VarDeclOrPat::Pat(pat) = &for_of_stmt.left {
if let ForHead::Pat(pat) = &for_of_stmt.left {
self.check_pat(pat);
}
@ -263,7 +263,7 @@ impl Visit for NoParamReassign {
}
fn visit_for_in_stmt(&mut self, for_in_stmt: &ForInStmt) {
if let VarDeclOrPat::Pat(pat) = &for_in_stmt.left {
if let ForHead::Pat(pat) = &for_in_stmt.left {
self.check_pat(pat);
}

View File

@ -563,6 +563,10 @@ where
// Variable declarations are handled by other functions.
}
Decl::Using(..) => {
// TODO: Optimize
}
Decl::TsInterface(_) | Decl::TsTypeAlias(_) | Decl::TsEnum(_) | Decl::TsModule(_) => {
// Nothing to do. We might change this to unreachable!()
}

View File

@ -355,7 +355,7 @@ impl Visit for VarWithOutInitCounter {
n.visit_children_with(self);
}
fn visit_var_decl_or_pat(&mut self, _: &VarDeclOrPat) {}
fn visit_for_head(&mut self, _: &ForHead) {}
}
/// Moves all variable without initializer.
@ -425,7 +425,7 @@ impl VisitMut for VarMover {
self.var_decl_kind = old;
}
fn visit_mut_var_decl_or_pat(&mut self, _: &mut VarDeclOrPat) {}
fn visit_mut_for_head(&mut self, _: &mut ForHead) {}
fn visit_mut_var_declarators(&mut self, d: &mut Vec<VarDeclarator>) {
d.visit_mut_children_with(self);

View File

@ -1651,8 +1651,8 @@ impl Visit for Shower<'_> {
n.visit_children_with(self)
}
fn visit_var_decl_or_pat(&mut self, n: &VarDeclOrPat) {
self.show("VarDeclOrPat", n);
fn visit_for_head(&mut self, n: &ForHead) {
self.show("ForHead", n);
n.visit_children_with(self)
}

View File

@ -45,6 +45,12 @@ pub enum SyntaxError {
Eof,
DeclNotAllowed,
UsingDeclNotAllowed,
UsingDeclNotAllowedForForInLoop,
UsingDeclNotEnabled,
InvalidNameInUsingDecl,
InitRequiredForUsingDecl,
PrivateNameInInterface,
InvalidSuperCall,
@ -523,6 +529,19 @@ impl SyntaxError {
"The operand of a delete operator must be a property reference.".into()
}
SyntaxError::DeclNotAllowed => "Declaration is not allowed".into(),
SyntaxError::UsingDeclNotAllowed => "Using declaration is not allowed".into(),
SyntaxError::UsingDeclNotAllowedForForInLoop => {
"Using declaration is not allowed in for-in loop".into()
}
SyntaxError::UsingDeclNotEnabled => {
"Using declaration is not enabled. Set jsc.parser.usingDecl to true".into()
}
SyntaxError::InvalidNameInUsingDecl => {
"Using declaration only allows identifiers".into()
}
SyntaxError::InitRequiredForUsingDecl => {
"Using declaration requires initializer".into()
}
SyntaxError::InvalidSuperCall => "Invalid `super()`".into(),
SyntaxError::InvalidSuper => "Invalid access to super".into(),
SyntaxError::InvalidSuperPrivateName => {

View File

@ -281,6 +281,13 @@ impl Syntax {
_ => false,
}
}
fn using_decl(&self) -> bool {
match self {
Syntax::Es(EsConfig { using_decl, .. }) => *using_decl,
Syntax::Typescript(_) => true,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
@ -345,6 +352,9 @@ pub struct EsConfig {
#[serde(default)]
pub auto_accessors: bool,
#[serde(default)]
pub using_decl: bool,
}
/// Syntactic context.
@ -403,6 +413,8 @@ pub struct Context {
ignore_else_clause: bool,
disallow_conditional_types: bool,
allow_using_decl: bool,
}
#[derive(Debug, Clone, Copy, Default)]

View File

@ -417,6 +417,9 @@ macro_rules! tok {
("protected") => {
crate::token::Token::Word(crate::token::Word::Ident(swc_atoms::js_word!("protected")))
};
("using") => {
crate::token::Token::Word(crate::token::Word::Ident(swc_atoms::js_word!("using")))
};
}
macro_rules! token_including_semi {

View File

@ -1618,7 +1618,7 @@ impl<I: Tokens> Parser<I> {
Ok(callee)
}
pub(super) fn parse_expr_or_pat(&mut self) -> PResult<Box<Expr>> {
pub(super) fn parse_for_head_prefix(&mut self) -> PResult<Box<Expr>> {
self.parse_expr()
}

View File

@ -301,6 +301,13 @@ impl<'a, I: Tokens> Parser<I> {
}
}
tok!("using") if include_decl => {
let v = self.parse_using_decl()?;
if let Some(v) = v {
return Ok(Stmt::Decl(Decl::Using(v)));
}
}
tok!("interface") => {
if is_typescript
&& peeked_is!(self, IdentName)
@ -328,7 +335,11 @@ impl<'a, I: Tokens> Parser<I> {
}
tok!('{') => {
return self.parse_block(false).map(Stmt::Block);
let ctx = Context {
allow_using_decl: true,
..self.ctx()
};
return self.with_ctx(ctx).parse_block(false).map(Stmt::Block);
}
_ => {}
@ -751,6 +762,70 @@ impl<'a, I: Tokens> Parser<I> {
}
}
pub(super) fn parse_using_decl(&mut self) -> PResult<Option<Box<UsingDecl>>> {
// using
// reader = init()
// is two statements
let _ = cur!(self, false);
if self.input.has_linebreak_between_cur_and_peeked() {
return Ok(None);
}
if !peeked_is!(self, BindingIdent) {
return Ok(None);
}
let start = cur_pos!(self);
assert_and_bump!(self, "using");
let mut decls = vec![];
let mut first = true;
while first || eat!(self, ',') {
if first {
first = false;
}
// Handle
// var a,;
//
// NewLine is ok
if is_exact!(self, ';') || eof!(self) {
let span = self.input.prev_span();
self.emit_err(span, SyntaxError::TS1009);
break;
}
decls.push(self.parse_var_declarator(false, VarDeclKind::Var)?);
}
if !self.syntax().using_decl() {
self.emit_err(span!(self, start), SyntaxError::UsingDeclNotEnabled);
}
if !self.ctx().allow_using_decl {
self.emit_err(span!(self, start), SyntaxError::UsingDeclNotAllowed);
}
for decl in &decls {
match decl.name {
Pat::Ident(..) => {}
_ => {
self.emit_err(span!(self, start), SyntaxError::InvalidNameInUsingDecl);
}
}
if decl.init.is_none() {
self.emit_err(span!(self, start), SyntaxError::InitRequiredForUsingDecl);
}
}
Ok(Some(Box::new(UsingDecl {
span: span!(self, start),
decls,
})))
}
pub(super) fn parse_var_stmt(&mut self, for_loop: bool) -> PResult<Box<VarDecl>> {
let start = cur_pos!(self);
let kind = match bump!(self) {
@ -1024,6 +1099,7 @@ impl<'a, I: Tokens> Parser<I> {
fn parse_labelled_stmt(&mut self, l: Ident) -> PResult<Stmt> {
let ctx = Context {
is_break_allowed: true,
allow_using_decl: false,
..self.ctx()
};
self.with_ctx(ctx).parse_with(|p| {
@ -1094,7 +1170,7 @@ impl<'a, I: Tokens> Parser<I> {
let span = span!(self, start);
Ok(match head {
ForHead::For { init, test, update } => {
TempForHead::For { init, test, update } => {
if let Some(await_token) = await_token {
syntax_error!(self, await_token, SyntaxError::AwaitForStmt);
}
@ -1107,7 +1183,7 @@ impl<'a, I: Tokens> Parser<I> {
body,
})
}
ForHead::ForIn { left, right } => {
TempForHead::ForIn { left, right } => {
if let Some(await_token) = await_token {
syntax_error!(self, await_token, SyntaxError::AwaitForStmt);
}
@ -1119,7 +1195,7 @@ impl<'a, I: Tokens> Parser<I> {
body,
})
}
ForHead::ForOf { left, right } => Stmt::ForOf(ForOfStmt {
TempForHead::ForOf { left, right } => Stmt::ForOf(ForOfStmt {
span,
is_await: await_token.is_some(),
left,
@ -1129,7 +1205,7 @@ impl<'a, I: Tokens> Parser<I> {
})
}
fn parse_for_head(&mut self) -> PResult<ForHead> {
fn parse_for_head(&mut self) -> PResult<TempForHead> {
let strict = self.ctx().strict;
if is_one_of!(self, "const", "var")
@ -1168,18 +1244,51 @@ impl<'a, I: Tokens> Parser<I> {
}
}
return self.parse_for_each_head(VarDeclOrPat::VarDecl(decl));
return self.parse_for_each_head(ForHead::VarDecl(decl));
}
expect_exact!(self, ';');
return self.parse_normal_for_head(Some(VarDeclOrExpr::VarDecl(decl)));
}
let init = if eat_exact!(self, ';') {
if eat_exact!(self, ';') {
return self.parse_normal_for_head(None);
} else {
self.include_in_expr(false).parse_expr_or_pat()?
};
}
let start = cur_pos!(self);
let init = self.include_in_expr(false).parse_for_head_prefix()?;
let is_using_decl = self.input.syntax().using_decl()
&& match *init {
Expr::Ident(Ident {
sym: js_word!("using"),
..
}) => {
is!(self, BindingIdent)
&& !is!(self, "of")
&& (peeked_is!(self, "of") || peeked_is!(self, "in"))
}
_ => false,
};
if is_using_decl {
let name = self.parse_binding_ident()?;
let decl = VarDeclarator {
name: Pat::Ident(name),
span: span!(self, start),
init: None,
definite: false,
};
let pat = Box::new(UsingDecl {
span: span!(self, start),
decls: vec![decl],
});
cur!(self, true)?;
return self.parse_for_each_head(ForHead::UsingDecl(pat));
}
// for (a of b)
if is_one_of!(self, "of", "in") {
@ -1196,7 +1305,7 @@ impl<'a, I: Tokens> Parser<I> {
}
}
return self.parse_for_each_head(VarDeclOrPat::Pat(Box::new(pat)));
return self.parse_for_each_head(ForHead::Pat(Box::new(pat)));
}
expect_exact!(self, ';');
@ -1205,18 +1314,22 @@ impl<'a, I: Tokens> Parser<I> {
self.parse_normal_for_head(Some(VarDeclOrExpr::Expr(init)))
}
fn parse_for_each_head(&mut self, left: VarDeclOrPat) -> PResult<ForHead> {
let of = bump!(self) == tok!("of");
if of {
fn parse_for_each_head(&mut self, left: ForHead) -> PResult<TempForHead> {
let is_of = bump!(self) == tok!("of");
if is_of {
let right = self.include_in_expr(true).parse_assignment_expr()?;
Ok(ForHead::ForOf { left, right })
Ok(TempForHead::ForOf { left, right })
} else {
if let ForHead::UsingDecl(d) = &left {
self.emit_err(d.span, SyntaxError::UsingDeclNotAllowedForForInLoop)
}
let right = self.include_in_expr(true).parse_expr()?;
Ok(ForHead::ForIn { left, right })
Ok(TempForHead::ForIn { left, right })
}
}
fn parse_normal_for_head(&mut self, init: Option<VarDeclOrExpr>) -> PResult<ForHead> {
fn parse_normal_for_head(&mut self, init: Option<VarDeclOrExpr>) -> PResult<TempForHead> {
let test = if eat_exact!(self, ';') {
None
} else {
@ -1231,23 +1344,23 @@ impl<'a, I: Tokens> Parser<I> {
self.include_in_expr(true).parse_expr().map(Some)?
};
Ok(ForHead::For { init, test, update })
Ok(TempForHead::For { init, test, update })
}
}
#[allow(clippy::enum_variant_names)]
enum ForHead {
enum TempForHead {
For {
init: Option<VarDeclOrExpr>,
test: Option<Box<Expr>>,
update: Option<Box<Expr>>,
},
ForIn {
left: VarDeclOrPat,
left: ForHead,
right: Box<Expr>,
},
ForOf {
left: VarDeclOrPat,
left: ForHead,
right: Box<Expr>,
},
}
@ -1417,7 +1530,7 @@ mod tests {
Stmt::ForOf(ForOfStmt {
span,
is_await: true,
left: VarDeclOrPat::VarDecl(Box::new(VarDecl {
left: ForHead::VarDecl(Box::new(VarDecl {
span,
kind: VarDeclKind::Const,
decls: vec![VarDeclarator {
@ -1894,14 +2007,14 @@ export default function waitUntil(callback, options = {}) {
assert!(trailing.borrow().is_empty());
assert_eq!(leading.borrow().len(), 1);
}
fn parse_for_head(str: &'static str) -> ForHead {
fn parse_for_head(str: &'static str) -> TempForHead {
test_parser(str, Syntax::default(), |p| p.parse_for_head())
}
#[test]
fn for_array_binding_pattern() {
match parse_for_head("let [, , t] = simple_array; t < 10; t++") {
ForHead::For { init: Some(v), .. } => assert_eq_ignore_span!(
TempForHead::For { init: Some(v), .. } => assert_eq_ignore_span!(
v,
VarDeclOrExpr::VarDecl(Box::new(VarDecl {
span,
@ -1933,7 +2046,7 @@ export default function waitUntil(callback, options = {}) {
#[test]
fn for_object_binding_pattern() {
match parse_for_head("let {num} = obj; num < 11; num++") {
ForHead::For { init: Some(v), .. } => assert_eq_ignore_span!(
TempForHead::For { init: Some(v), .. } => assert_eq_ignore_span!(
v,
VarDeclOrExpr::VarDecl(Box::new(VarDecl {
span,

View File

@ -2328,17 +2328,8 @@ impl<I: Tokens> Parser<I> {
match &*expr.sym {
"declare" => {
let decl = self.try_parse_ts_declare(start, decorators)?;
if let Some(mut decl) = decl {
match &mut decl {
Decl::Class(ClassDecl { declare, .. })
| Decl::Fn(FnDecl { declare, .. }) => *declare = true,
Decl::Var(v) => v.declare = true,
Decl::TsInterface(v) => v.declare = true,
Decl::TsTypeAlias(v) => v.declare = true,
Decl::TsEnum(v) => v.declare = true,
Decl::TsModule(v) => v.declare = true,
}
Ok(Some(decl))
if let Some(decl) = decl {
Ok(Some(make_decl_declare(decl)))
} else {
Ok(None)
}
@ -2824,6 +2815,7 @@ fn make_decl_declare(mut decl: Decl) -> Decl {
Decl::TsTypeAlias(ref mut a) => a.declare = true,
Decl::TsEnum(ref mut e) => e.declare = true,
Decl::TsModule(ref mut m) => m.declare = true,
Decl::Using(..) => unreachable!("Using is not a valid declaration for `declare` keyword"),
}
decl

View File

@ -47,6 +47,7 @@ where
} else {
::swc_ecma_parser::Syntax::Es(::swc_ecma_parser::EsConfig {
jsx: is_jsx,
using_decl: true,
..Default::default()
})
};
@ -64,6 +65,7 @@ where
#[cfg(feature = "verify")]
#[testing::fixture("tests/errors/**/*.js")]
#[testing::fixture("tests/errors/**/*.mjs")]
#[testing::fixture("tests/errors/**/*.ts")]
#[testing::fixture("tests/errors/**/*.tsx")]
fn error(entry: PathBuf) {

View File

@ -0,0 +1,7 @@
{
using f, f = foo();
}
{
using g = foo();
using g = foo();
}

View File

@ -0,0 +1,8 @@
x Using declaration requires initializer
,-[$DIR/tests/errors/explicit-resource-management/invalid-duplicate-using-bindings/input.js:1:1]
1 | {
2 | using f, f = foo();
: ^^^^^^^^^^^^^^^^^^
3 | }
`----

View File

@ -0,0 +1,6 @@
x Using declaration is not allowed in for-in loop
,-[$DIR/tests/errors/explicit-resource-management/invalid-for-using-binding-in/input.js:1:1]
1 | for (using foo in {});
: ^^^^^^^^^
`----

View File

@ -0,0 +1,6 @@
x Expression expected
,-[$DIR/tests/errors/explicit-resource-management/invalid-for-using-binding-of-in/input.js:1:1]
1 | for (using of in []);
: ^^
`----

View File

@ -0,0 +1,8 @@
{
while (1) using a;
for (;;) using b;
do using c; while (1);
if (1) using d;
with (1) using e;
label: using f;
}

View File

@ -0,0 +1,9 @@
x Expected ';', '}' or <eof>
,-[$DIR/tests/errors/explicit-resource-management/invalid-in-single-statement-context/input.js:1:1]
1 | {
2 | while (1) using a;
: ^^|^^ ^
: `-- This is the expression part of an expression statement
3 | for (;;) using b;
`----

View File

@ -0,0 +1,3 @@
{
label: using x = bar();
}

View File

@ -0,0 +1,9 @@
x Expected ';', '}' or <eof>
,-[$DIR/tests/errors/explicit-resource-management/invalid-labeled-using-binding/input.js:1:1]
1 | {
2 | label: using x = bar();
: ^^|^^ ^
: `-- This is the expression part of an expression statement
3 | }
`----

View File

@ -0,0 +1,7 @@
x Expected ';', '}' or <eof>
,-[$DIR/tests/errors/explicit-resource-management/invalid-script-top-level-labeled-using-binding/input.js:1:1]
1 | label: using x = bar();
: ^^|^^ ^
: `-- This is the expression part of an expression statement
`----

View File

@ -0,0 +1,6 @@
x Using declaration is not allowed
,-[$DIR/tests/errors/explicit-resource-management/invalid-script-top-level-using-binding/input.js:1:1]
1 | using x = bar();
: ^^^^^^^^^^^^^^^
`----

View File

@ -0,0 +1,12 @@
{
using await = h();
}
{
using \u0061wait = h();
}
{
using x, await = h();
}
{
for (using await of []);
}

View File

@ -0,0 +1,9 @@
x Expected ';', '}' or <eof>
,-[$DIR/tests/errors/explicit-resource-management/invalid-using-binding-await-module/input.js:1:1]
1 | {
2 | using await = h();
: ^^|^^ ^^^^^
: `-- This is the expression part of an expression statement
3 | }
`----

View File

@ -0,0 +1,12 @@
{
using await = h();
}
{
using \u0061wait = h();
}
{
using x, await = h();
}
{
for (using await of []);
}

View File

@ -0,0 +1,9 @@
x Expected ';', '}' or <eof>
,-[$DIR/tests/errors/explicit-resource-management/invalid-using-binding-await-script/input.js:1:1]
1 | {
2 | using await = h();
: ^^|^^ ^^^^^
: `-- This is the expression part of an expression statement
3 | }
`----

View File

@ -0,0 +1,9 @@
x Expected ';', '}' or <eof>
,-[$DIR/tests/errors/explicit-resource-management/invalid-using-binding-let/input.js:1:1]
1 | {
2 | using let = h();
: ^^|^^ ^^^
: `-- This is the expression part of an expression statement
3 | }
`----

View File

@ -0,0 +1,9 @@
x Expected ';', '}' or <eof>
,-[$DIR/tests/errors/explicit-resource-management/invalid-using-binding-pattern-declaration/input.js:1:1]
1 | {
2 | using { foo } = f();
: ^^|^^ ^
: `-- This is the expression part of an expression statement
3 | }
`----

View File

@ -0,0 +1,3 @@
{
for (using { qux } of h());
}

View File

@ -0,0 +1,8 @@
x Expected ';', got '{'
,-[$DIR/tests/errors/explicit-resource-management/invalid-using-binding-pattern-for-lhs/input.js:1:1]
1 | {
2 | for (using { qux } of h());
: ^
3 | }
`----

View File

@ -8,7 +8,7 @@ use std::{
use swc_common::{comments::SingleThreadedComments, FileName};
use swc_ecma_ast::*;
use swc_ecma_parser::{lexer::Lexer, PResult, Parser, Syntax};
use swc_ecma_parser::{lexer::Lexer, EsConfig, PResult, Parser, Syntax};
use swc_ecma_visit::FoldWith;
use testing::StdErr;
@ -90,7 +90,10 @@ where
.unwrap_or_else(|e| panic!("failed to load {}: {}", file_name.display(), e));
let lexer = Lexer::new(
Syntax::Es(Default::default()),
Syntax::Es(EsConfig {
using_decl: true,
..Default::default()
}),
EsVersion::Es2015,
(&*fm).into(),
Some(&comments),

View File

@ -0,0 +1,53 @@
{
"type": "Script",
"span": {
"start": 1,
"end": 11,
"ctxt": 0
},
"body": [
{
"type": "ExpressionStatement",
"span": {
"start": 1,
"end": 11,
"ctxt": 0
},
"expression": {
"type": "CallExpression",
"span": {
"start": 1,
"end": 10,
"ctxt": 0
},
"callee": {
"type": "Identifier",
"span": {
"start": 1,
"end": 6,
"ctxt": 0
},
"value": "using",
"optional": false
},
"arguments": [
{
"spread": null,
"expression": {
"type": "Identifier",
"span": {
"start": 8,
"end": 9,
"ctxt": 0
},
"value": "x",
"optional": false
}
}
],
"typeArguments": null
}
}
],
"interpreter": null
}

View File

@ -0,0 +1,136 @@
{
"type": "Script",
"span": {
"start": 1,
"end": 38,
"ctxt": 0
},
"body": [
{
"type": "ExpressionStatement",
"span": {
"start": 1,
"end": 15,
"ctxt": 0
},
"expression": {
"type": "AssignmentExpression",
"span": {
"start": 1,
"end": 14,
"ctxt": 0
},
"operator": "=",
"left": {
"type": "MemberExpression",
"span": {
"start": 1,
"end": 10,
"ctxt": 0
},
"object": {
"type": "Identifier",
"span": {
"start": 1,
"end": 6,
"ctxt": 0
},
"value": "using",
"optional": false
},
"property": {
"type": "Computed",
"span": {
"start": 7,
"end": 10,
"ctxt": 0
},
"expression": {
"type": "Identifier",
"span": {
"start": 8,
"end": 9,
"ctxt": 0
},
"value": "x",
"optional": false
}
}
},
"right": {
"type": "NumericLiteral",
"span": {
"start": 13,
"end": 14,
"ctxt": 0
},
"value": 0.0,
"raw": "0"
}
}
},
{
"type": "ForOfStatement",
"span": {
"start": 16,
"end": 38,
"ctxt": 0
},
"await": false,
"left": {
"type": "MemberExpression",
"span": {
"start": 21,
"end": 30,
"ctxt": 0
},
"object": {
"type": "Identifier",
"span": {
"start": 21,
"end": 26,
"ctxt": 0
},
"value": "using",
"optional": false
},
"property": {
"type": "Computed",
"span": {
"start": 27,
"end": 30,
"ctxt": 0
},
"expression": {
"type": "Identifier",
"span": {
"start": 28,
"end": 29,
"ctxt": 0
},
"value": "x",
"optional": false
}
}
},
"right": {
"type": "ArrayExpression",
"span": {
"start": 34,
"end": 36,
"ctxt": 0
},
"elements": []
},
"body": {
"type": "EmptyStatement",
"span": {
"start": 37,
"end": 38,
"ctxt": 0
}
}
}
],
"interpreter": null
}

View File

@ -0,0 +1,2 @@
using [x] = 0;
for (using [x] of []);

View File

@ -0,0 +1,136 @@
{
"type": "Script",
"span": {
"start": 1,
"end": 38,
"ctxt": 0
},
"body": [
{
"type": "ExpressionStatement",
"span": {
"start": 1,
"end": 15,
"ctxt": 0
},
"expression": {
"type": "AssignmentExpression",
"span": {
"start": 1,
"end": 14,
"ctxt": 0
},
"operator": "=",
"left": {
"type": "MemberExpression",
"span": {
"start": 1,
"end": 10,
"ctxt": 0
},
"object": {
"type": "Identifier",
"span": {
"start": 1,
"end": 6,
"ctxt": 0
},
"value": "using",
"optional": false
},
"property": {
"type": "Computed",
"span": {
"start": 7,
"end": 10,
"ctxt": 0
},
"expression": {
"type": "Identifier",
"span": {
"start": 8,
"end": 9,
"ctxt": 0
},
"value": "x",
"optional": false
}
}
},
"right": {
"type": "NumericLiteral",
"span": {
"start": 13,
"end": 14,
"ctxt": 0
},
"value": 0.0,
"raw": "0"
}
}
},
{
"type": "ForOfStatement",
"span": {
"start": 16,
"end": 38,
"ctxt": 0
},
"await": false,
"left": {
"type": "MemberExpression",
"span": {
"start": 21,
"end": 30,
"ctxt": 0
},
"object": {
"type": "Identifier",
"span": {
"start": 21,
"end": 26,
"ctxt": 0
},
"value": "using",
"optional": false
},
"property": {
"type": "Computed",
"span": {
"start": 27,
"end": 30,
"ctxt": 0
},
"expression": {
"type": "Identifier",
"span": {
"start": 28,
"end": 29,
"ctxt": 0
},
"value": "x",
"optional": false
}
}
},
"right": {
"type": "ArrayExpression",
"span": {
"start": 34,
"end": 36,
"ctxt": 0
},
"elements": []
},
"body": {
"type": "EmptyStatement",
"span": {
"start": 37,
"end": 38,
"ctxt": 0
}
}
}
],
"interpreter": null
}

View File

@ -0,0 +1,77 @@
{
"type": "Script",
"span": {
"start": 1,
"end": 27,
"ctxt": 0
},
"body": [
{
"type": "ExpressionStatement",
"span": {
"start": 1,
"end": 6,
"ctxt": 0
},
"expression": {
"type": "Identifier",
"span": {
"start": 1,
"end": 6,
"ctxt": 0
},
"value": "using",
"optional": false
}
},
{
"type": "ExpressionStatement",
"span": {
"start": 7,
"end": 27,
"ctxt": 0
},
"expression": {
"type": "AssignmentExpression",
"span": {
"start": 7,
"end": 27,
"ctxt": 0
},
"operator": "=",
"left": {
"type": "Identifier",
"span": {
"start": 7,
"end": 13,
"ctxt": 0
},
"value": "reader",
"optional": false,
"typeAnnotation": null
},
"right": {
"type": "CallExpression",
"span": {
"start": 16,
"end": 27,
"ctxt": 0
},
"callee": {
"type": "Identifier",
"span": {
"start": 16,
"end": 25,
"ctxt": 0
},
"value": "getReader",
"optional": false
},
"arguments": [],
"typeArguments": null
}
}
}
],
"interpreter": null
}

View File

@ -0,0 +1,49 @@
{
"type": "Script",
"span": {
"start": 1,
"end": 25,
"ctxt": 0
},
"body": [
{
"type": "ForOfStatement",
"span": {
"start": 1,
"end": 25,
"ctxt": 0
},
"await": true,
"left": {
"type": "Identifier",
"span": {
"start": 12,
"end": 17,
"ctxt": 0
},
"value": "using",
"optional": false,
"typeAnnotation": null
},
"right": {
"type": "Identifier",
"span": {
"start": 21,
"end": 23,
"ctxt": 0
},
"value": "of",
"optional": false
},
"body": {
"type": "EmptyStatement",
"span": {
"start": 24,
"end": 25,
"ctxt": 0
}
}
}
],
"interpreter": null
}

View File

@ -0,0 +1,4 @@
for (using in []);
for (using.foo in []);
for (using().foo in []);
for (using``.foo in []);

View File

@ -0,0 +1,247 @@
{
"type": "Script",
"span": {
"start": 1,
"end": 92,
"ctxt": 0
},
"body": [
{
"type": "ForInStatement",
"span": {
"start": 1,
"end": 19,
"ctxt": 0
},
"left": {
"type": "Identifier",
"span": {
"start": 6,
"end": 11,
"ctxt": 0
},
"value": "using",
"optional": false,
"typeAnnotation": null
},
"right": {
"type": "ArrayExpression",
"span": {
"start": 15,
"end": 17,
"ctxt": 0
},
"elements": []
},
"body": {
"type": "EmptyStatement",
"span": {
"start": 18,
"end": 19,
"ctxt": 0
}
}
},
{
"type": "ForInStatement",
"span": {
"start": 20,
"end": 42,
"ctxt": 0
},
"left": {
"type": "MemberExpression",
"span": {
"start": 25,
"end": 34,
"ctxt": 0
},
"object": {
"type": "Identifier",
"span": {
"start": 25,
"end": 30,
"ctxt": 0
},
"value": "using",
"optional": false
},
"property": {
"type": "Identifier",
"span": {
"start": 31,
"end": 34,
"ctxt": 0
},
"value": "foo",
"optional": false
}
},
"right": {
"type": "ArrayExpression",
"span": {
"start": 38,
"end": 40,
"ctxt": 0
},
"elements": []
},
"body": {
"type": "EmptyStatement",
"span": {
"start": 41,
"end": 42,
"ctxt": 0
}
}
},
{
"type": "ForInStatement",
"span": {
"start": 43,
"end": 67,
"ctxt": 0
},
"left": {
"type": "MemberExpression",
"span": {
"start": 48,
"end": 59,
"ctxt": 0
},
"object": {
"type": "CallExpression",
"span": {
"start": 48,
"end": 55,
"ctxt": 0
},
"callee": {
"type": "Identifier",
"span": {
"start": 48,
"end": 53,
"ctxt": 0
},
"value": "using",
"optional": false
},
"arguments": [],
"typeArguments": null
},
"property": {
"type": "Identifier",
"span": {
"start": 56,
"end": 59,
"ctxt": 0
},
"value": "foo",
"optional": false
}
},
"right": {
"type": "ArrayExpression",
"span": {
"start": 63,
"end": 65,
"ctxt": 0
},
"elements": []
},
"body": {
"type": "EmptyStatement",
"span": {
"start": 66,
"end": 67,
"ctxt": 0
}
}
},
{
"type": "ForInStatement",
"span": {
"start": 68,
"end": 92,
"ctxt": 0
},
"left": {
"type": "MemberExpression",
"span": {
"start": 73,
"end": 84,
"ctxt": 0
},
"object": {
"type": "TaggedTemplateExpression",
"span": {
"start": 73,
"end": 80,
"ctxt": 0
},
"tag": {
"type": "Identifier",
"span": {
"start": 73,
"end": 78,
"ctxt": 0
},
"value": "using",
"optional": false
},
"typeParameters": null,
"template": {
"type": "TemplateLiteral",
"span": {
"start": 78,
"end": 80,
"ctxt": 0
},
"expressions": [],
"quasis": [
{
"type": "TemplateElement",
"span": {
"start": 79,
"end": 79,
"ctxt": 0
},
"tail": true,
"cooked": "",
"raw": ""
}
]
}
},
"property": {
"type": "Identifier",
"span": {
"start": 81,
"end": 84,
"ctxt": 0
},
"value": "foo",
"optional": false
}
},
"right": {
"type": "ArrayExpression",
"span": {
"start": 88,
"end": 90,
"ctxt": 0
},
"elements": []
},
"body": {
"type": "EmptyStatement",
"span": {
"start": 91,
"end": 92,
"ctxt": 0
}
}
}
],
"interpreter": null
}

View File

@ -0,0 +1,3 @@
for (
using;
reader = getReader(););

View File

@ -0,0 +1,78 @@
{
"type": "Script",
"span": {
"start": 1,
"end": 41,
"ctxt": 0
},
"body": [
{
"type": "ForStatement",
"span": {
"start": 1,
"end": 41,
"ctxt": 0
},
"init": {
"type": "Identifier",
"span": {
"start": 9,
"end": 14,
"ctxt": 0
},
"value": "using",
"optional": false
},
"test": {
"type": "AssignmentExpression",
"span": {
"start": 18,
"end": 38,
"ctxt": 0
},
"operator": "=",
"left": {
"type": "Identifier",
"span": {
"start": 18,
"end": 24,
"ctxt": 0
},
"value": "reader",
"optional": false,
"typeAnnotation": null
},
"right": {
"type": "CallExpression",
"span": {
"start": 27,
"end": 38,
"ctxt": 0
},
"callee": {
"type": "Identifier",
"span": {
"start": 27,
"end": 36,
"ctxt": 0
},
"value": "getReader",
"optional": false
},
"arguments": [],
"typeArguments": null
}
},
"update": null,
"body": {
"type": "EmptyStatement",
"span": {
"start": 40,
"end": 41,
"ctxt": 0
}
}
}
],
"interpreter": null
}

View File

@ -0,0 +1,4 @@
for (using of of);
for (using.foo of of);
for (using().foo of of);
for (using``.foo of of);

View File

@ -0,0 +1,255 @@
{
"type": "Script",
"span": {
"start": 1,
"end": 92,
"ctxt": 0
},
"body": [
{
"type": "ForOfStatement",
"span": {
"start": 1,
"end": 19,
"ctxt": 0
},
"await": false,
"left": {
"type": "Identifier",
"span": {
"start": 6,
"end": 11,
"ctxt": 0
},
"value": "using",
"optional": false,
"typeAnnotation": null
},
"right": {
"type": "Identifier",
"span": {
"start": 15,
"end": 17,
"ctxt": 0
},
"value": "of",
"optional": false
},
"body": {
"type": "EmptyStatement",
"span": {
"start": 18,
"end": 19,
"ctxt": 0
}
}
},
{
"type": "ForOfStatement",
"span": {
"start": 20,
"end": 42,
"ctxt": 0
},
"await": false,
"left": {
"type": "MemberExpression",
"span": {
"start": 25,
"end": 34,
"ctxt": 0
},
"object": {
"type": "Identifier",
"span": {
"start": 25,
"end": 30,
"ctxt": 0
},
"value": "using",
"optional": false
},
"property": {
"type": "Identifier",
"span": {
"start": 31,
"end": 34,
"ctxt": 0
},
"value": "foo",
"optional": false
}
},
"right": {
"type": "Identifier",
"span": {
"start": 38,
"end": 40,
"ctxt": 0
},
"value": "of",
"optional": false
},
"body": {
"type": "EmptyStatement",
"span": {
"start": 41,
"end": 42,
"ctxt": 0
}
}
},
{
"type": "ForOfStatement",
"span": {
"start": 43,
"end": 67,
"ctxt": 0
},
"await": false,
"left": {
"type": "MemberExpression",
"span": {
"start": 48,
"end": 59,
"ctxt": 0
},
"object": {
"type": "CallExpression",
"span": {
"start": 48,
"end": 55,
"ctxt": 0
},
"callee": {
"type": "Identifier",
"span": {
"start": 48,
"end": 53,
"ctxt": 0
},
"value": "using",
"optional": false
},
"arguments": [],
"typeArguments": null
},
"property": {
"type": "Identifier",
"span": {
"start": 56,
"end": 59,
"ctxt": 0
},
"value": "foo",
"optional": false
}
},
"right": {
"type": "Identifier",
"span": {
"start": 63,
"end": 65,
"ctxt": 0
},
"value": "of",
"optional": false
},
"body": {
"type": "EmptyStatement",
"span": {
"start": 66,
"end": 67,
"ctxt": 0
}
}
},
{
"type": "ForOfStatement",
"span": {
"start": 68,
"end": 92,
"ctxt": 0
},
"await": false,
"left": {
"type": "MemberExpression",
"span": {
"start": 73,
"end": 84,
"ctxt": 0
},
"object": {
"type": "TaggedTemplateExpression",
"span": {
"start": 73,
"end": 80,
"ctxt": 0
},
"tag": {
"type": "Identifier",
"span": {
"start": 73,
"end": 78,
"ctxt": 0
},
"value": "using",
"optional": false
},
"typeParameters": null,
"template": {
"type": "TemplateLiteral",
"span": {
"start": 78,
"end": 80,
"ctxt": 0
},
"expressions": [],
"quasis": [
{
"type": "TemplateElement",
"span": {
"start": 79,
"end": 79,
"ctxt": 0
},
"tail": true,
"cooked": "",
"raw": ""
}
]
}
},
"property": {
"type": "Identifier",
"span": {
"start": 81,
"end": 84,
"ctxt": 0
},
"value": "foo",
"optional": false
}
},
"right": {
"type": "Identifier",
"span": {
"start": 88,
"end": 90,
"ctxt": 0
},
"value": "of",
"optional": false
},
"body": {
"type": "EmptyStatement",
"span": {
"start": 91,
"end": 92,
"ctxt": 0
}
}
}
],
"interpreter": null
}

View File

@ -0,0 +1 @@
using in using instanceof using;

View File

@ -0,0 +1,67 @@
{
"type": "Script",
"span": {
"start": 1,
"end": 33,
"ctxt": 0
},
"body": [
{
"type": "ExpressionStatement",
"span": {
"start": 1,
"end": 33,
"ctxt": 0
},
"expression": {
"type": "BinaryExpression",
"span": {
"start": 1,
"end": 32,
"ctxt": 0
},
"operator": "instanceof",
"left": {
"type": "BinaryExpression",
"span": {
"start": 1,
"end": 15,
"ctxt": 0
},
"operator": "in",
"left": {
"type": "Identifier",
"span": {
"start": 1,
"end": 6,
"ctxt": 0
},
"value": "using",
"optional": false
},
"right": {
"type": "Identifier",
"span": {
"start": 10,
"end": 15,
"ctxt": 0
},
"value": "using",
"optional": false
}
},
"right": {
"type": "Identifier",
"span": {
"start": 27,
"end": 32,
"ctxt": 0
},
"value": "using",
"optional": false
}
}
}
],
"interpreter": null
}

View File

@ -0,0 +1,3 @@
{
using basic = getReader();
}

View File

@ -0,0 +1,79 @@
{
"type": "Script",
"span": {
"start": 1,
"end": 33,
"ctxt": 0
},
"body": [
{
"type": "BlockStatement",
"span": {
"start": 1,
"end": 33,
"ctxt": 0
},
"stmts": [
{
"type": "UsingDeclaration",
"span": {
"start": 5,
"end": 30,
"ctxt": 0
},
"decls": [
{
"type": "VariableDeclarator",
"span": {
"start": 11,
"end": 30,
"ctxt": 0
},
"id": {
"type": "Identifier",
"span": {
"start": 11,
"end": 16,
"ctxt": 0
},
"value": "basic",
"optional": false,
"typeAnnotation": null
},
"init": {
"type": "CallExpression",
"span": {
"start": 19,
"end": 30,
"ctxt": 0
},
"callee": {
"type": "Identifier",
"span": {
"start": 19,
"end": 28,
"ctxt": 0
},
"value": "getReader",
"optional": false
},
"arguments": [],
"typeArguments": null
},
"definite": false
}
]
},
{
"type": "EmptyStatement",
"span": {
"start": 30,
"end": 31,
"ctxt": 0
}
}
]
}
],
"interpreter": null
}

View File

@ -0,0 +1,69 @@
{
"type": "Script",
"span": {
"start": 1,
"end": 23,
"ctxt": 0
},
"body": [
{
"type": "BlockStatement",
"span": {
"start": 1,
"end": 23,
"ctxt": 0
},
"stmts": [
{
"type": "UsingDeclaration",
"span": {
"start": 3,
"end": 20,
"ctxt": 0
},
"decls": [
{
"type": "VariableDeclarator",
"span": {
"start": 9,
"end": 20,
"ctxt": 0
},
"id": {
"type": "Identifier",
"span": {
"start": 9,
"end": 16,
"ctxt": 0
},
"value": "ab",
"optional": false,
"typeAnnotation": null
},
"init": {
"type": "Identifier",
"span": {
"start": 19,
"end": 20,
"ctxt": 0
},
"value": "c",
"optional": false
},
"definite": false
}
]
},
{
"type": "EmptyStatement",
"span": {
"start": 20,
"end": 21,
"ctxt": 0
}
}
]
}
],
"interpreter": null
}

View File

@ -0,0 +1,79 @@
{
"type": "Script",
"span": {
"start": 1,
"end": 24,
"ctxt": 0
},
"body": [
{
"type": "BlockStatement",
"span": {
"start": 1,
"end": 24,
"ctxt": 0
},
"stmts": [
{
"type": "UsingDeclaration",
"span": {
"start": 3,
"end": 21,
"ctxt": 0
},
"decls": [
{
"type": "VariableDeclarator",
"span": {
"start": 9,
"end": 21,
"ctxt": 0
},
"id": {
"type": "Identifier",
"span": {
"start": 9,
"end": 13,
"ctxt": 0
},
"value": "𠮷",
"optional": false,
"typeAnnotation": null
},
"init": {
"type": "CallExpression",
"span": {
"start": 16,
"end": 21,
"ctxt": 0
},
"callee": {
"type": "Identifier",
"span": {
"start": 16,
"end": 19,
"ctxt": 0
},
"value": "foo",
"optional": false
},
"arguments": [],
"typeArguments": null
},
"definite": false
}
]
},
{
"type": "EmptyStatement",
"span": {
"start": 21,
"end": 22,
"ctxt": 0
}
}
]
}
],
"interpreter": null
}

View File

@ -0,0 +1,4 @@
{
using using = of;
for (using using of of);
}

View File

@ -0,0 +1,127 @@
{
"type": "Script",
"span": {
"start": 1,
"end": 51,
"ctxt": 0
},
"body": [
{
"type": "BlockStatement",
"span": {
"start": 1,
"end": 51,
"ctxt": 0
},
"stmts": [
{
"type": "UsingDeclaration",
"span": {
"start": 5,
"end": 21,
"ctxt": 0
},
"decls": [
{
"type": "VariableDeclarator",
"span": {
"start": 11,
"end": 21,
"ctxt": 0
},
"id": {
"type": "Identifier",
"span": {
"start": 11,
"end": 16,
"ctxt": 0
},
"value": "using",
"optional": false,
"typeAnnotation": null
},
"init": {
"type": "Identifier",
"span": {
"start": 19,
"end": 21,
"ctxt": 0
},
"value": "of",
"optional": false
},
"definite": false
}
]
},
{
"type": "EmptyStatement",
"span": {
"start": 21,
"end": 22,
"ctxt": 0
}
},
{
"type": "ForOfStatement",
"span": {
"start": 25,
"end": 49,
"ctxt": 0
},
"await": false,
"left": {
"type": "UsingDeclaration",
"span": {
"start": 30,
"end": 41,
"ctxt": 0
},
"decls": [
{
"type": "VariableDeclarator",
"span": {
"start": 30,
"end": 41,
"ctxt": 0
},
"id": {
"type": "Identifier",
"span": {
"start": 36,
"end": 41,
"ctxt": 0
},
"value": "using",
"optional": false,
"typeAnnotation": null
},
"init": null,
"definite": false
}
]
},
"right": {
"type": "Identifier",
"span": {
"start": 45,
"end": 47,
"ctxt": 0
},
"value": "of",
"optional": false
},
"body": {
"type": "EmptyStatement",
"span": {
"start": 48,
"end": 49,
"ctxt": 0
}
}
}
]
}
],
"interpreter": null
}

View File

@ -1056,8 +1056,8 @@ impl Visit for Shower<'_> {
n.visit_children_with(self)
}
fn visit_var_decl_or_pat(&mut self, n: &VarDeclOrPat) {
self.show("VarDeclOrPat", n);
fn visit_for_head(&mut self, n: &ForHead) {
self.show("ForHead", n);
n.visit_children_with(self)
}

View File

@ -39,7 +39,7 @@
6 | `-> }
`----
x VarDeclOrPat
x ForHead
,-[$DIR/tests/span/js/stmt/for-in.js:1:1]
1 | for (const a in [1, 2, 3]) {
: ^^^^^^^

View File

@ -27,7 +27,7 @@
3 | `-> }
`----
x VarDeclOrPat
x ForHead
,-[$DIR/tests/span/js/stmt/for-of.js:1:1]
1 | for await (const a of foo) {
: ^^^^^^^

View File

@ -2,10 +2,20 @@ use swc_ecma_ast::*;
impl_enum!(
Decl,
[Class, Fn, Var, TsInterface, TsTypeAlias, TsEnum, TsModule]
[
Class,
Fn,
Var,
TsInterface,
TsTypeAlias,
TsEnum,
TsModule,
Using
]
);
impl_struct!(ClassDecl, [ident, class]);
impl_struct!(FnDecl, [ident, function]);
impl_struct!(VarDecl, [span, kind, declare, decls]);
impl_struct!(VarDeclarator, [span, name, init, definite]);
impl_struct!(UsingDecl, [span, decls]);

View File

@ -28,7 +28,7 @@ impl_struct!(ReturnStmt, [span, arg]);
impl_struct!(ExprStmt, [span, expr]);
impl_enum!(VarDeclOrExpr, [VarDecl, Expr]);
impl_enum!(VarDeclOrPat, [VarDecl, Pat]);
impl_enum!(ForHead, [VarDecl, UsingDecl, Pat]);
impl_struct!(SwitchCase, [span, test, cons]);

View File

@ -496,7 +496,7 @@ impl VisitMut for Fixer<'_> {
if !s.is_await {
match &s.left {
VarDeclOrPat::Pat(p)
ForHead::Pat(p)
if matches!(
&**p,
Pat::Ident(BindingIdent {
@ -509,12 +509,12 @@ impl VisitMut for Fixer<'_> {
) =>
{
let expr = Expr::Ident(p.clone().expect_ident().id);
s.left = VarDeclOrPat::Pat(Pat::Expr(Box::new(expr)).into());
s.left = ForHead::Pat(Pat::Expr(Box::new(expr)).into());
}
_ => (),
}
if let VarDeclOrPat::Pat(e) = &mut s.left {
if let ForHead::Pat(e) = &mut s.left {
if let Pat::Expr(expr) = &mut **e {
if let Expr::Ident(Ident {
sym: js_word!("async"),

View File

@ -1855,9 +1855,9 @@ impl VisitMut for Hoister<'_, '_> {
}
}
fn visit_mut_var_decl_or_pat(&mut self, n: &mut VarDeclOrPat) {
fn visit_mut_for_head(&mut self, n: &mut ForHead) {
match n {
VarDeclOrPat::VarDecl(v)
ForHead::VarDecl(v)
if matches!(
&**v,
VarDecl {
@ -1874,7 +1874,7 @@ impl VisitMut for Hoister<'_, '_> {
// console.log(a);
// }
// }
VarDeclOrPat::Pat(..) => {}
ForHead::Pat(..) => {}
_ => {
n.visit_mut_children_with(self);
}

View File

@ -438,7 +438,7 @@ impl VisitMut for BlockScoping {
fn visit_mut_for_in_stmt(&mut self, node: &mut ForInStmt) {
let blockifyed = self.blockify_for_stmt_body(&mut node.body);
let lexical_var = if let VarDeclOrPat::VarDecl(decl) = &node.left {
let lexical_var = if let ForHead::VarDecl(decl) = &node.left {
find_lexical_vars(decl)
} else {
Vec::new()
@ -463,7 +463,7 @@ impl VisitMut for BlockScoping {
fn visit_mut_for_of_stmt(&mut self, node: &mut ForOfStmt) {
let blockifyed = self.blockify_for_stmt_body(&mut node.body);
let vars = if let VarDeclOrPat::VarDecl(decl) = &node.left {
let vars = if let ForHead::VarDecl(decl) = &node.left {
find_lexical_vars(decl)
} else {
Vec::new()

View File

@ -311,7 +311,7 @@ impl VisitMut for BlockScopedVars {
n.right.visit_mut_with(self);
match &n.left {
VarDeclOrPat::VarDecl(v)
ForHead::VarDecl(v)
if matches!(
&**v,
VarDecl {
@ -336,7 +336,7 @@ impl VisitMut for BlockScopedVars {
n.right.visit_mut_with(self);
match &n.left {
VarDeclOrPat::VarDecl(v)
ForHead::VarDecl(v)
if matches!(
&**v,
VarDecl {

View File

@ -54,7 +54,7 @@ macro_rules! impl_for_for_stmt {
($name:ident, $T:tt) => {
fn $name(&mut self, for_stmt: &mut $T) {
let (left, stmt) = match &mut for_stmt.left {
VarDeclOrPat::VarDecl(var_decl) => {
ForHead::VarDecl(var_decl) => {
let has_complex = var_decl.decls.iter().any(|d| match d.name {
Pat::Ident(_) => false,
_ => true,
@ -99,13 +99,13 @@ macro_rules! impl_for_for_stmt {
.into();
(left, stmt)
}
VarDeclOrPat::Pat(pat) => match **pat {
ForHead::Pat(pat) => match **pat {
Pat::Ident(..) => {
return;
}
_ => {
let left_ident = make_ref_ident_for_for_stmt();
let left = VarDeclOrPat::Pat(left_ident.clone().into());
let left = ForHead::Pat(left_ident.clone().into());
// Unpack variables
let stmt = AssignExpr {
span: DUMMY_SP,
@ -117,6 +117,10 @@ macro_rules! impl_for_for_stmt {
(left, stmt)
}
},
ForHead::UsingDecl(..) => {
unreachable!("using declaration must be removed by previous pass")
}
};
for_stmt.left = left;

View File

@ -140,7 +140,7 @@ impl ForOf {
};
match left {
VarDeclOrPat::VarDecl(var) => {
ForHead::VarDecl(var) => {
assert_eq!(
var.decls.len(),
1,
@ -163,7 +163,7 @@ impl ForOf {
)
}
VarDeclOrPat::Pat(pat) => prepend_stmt(
ForHead::Pat(pat) => prepend_stmt(
&mut body.stmts,
AssignExpr {
span: DUMMY_SP,
@ -173,6 +173,10 @@ impl ForOf {
}
.into_stmt(),
),
ForHead::UsingDecl(..) => {
unreachable!("using declaration must be removed by previous pass")
}
}
let stmt = Stmt::For(ForStmt {
@ -236,7 +240,7 @@ impl ForOf {
};
match left {
VarDeclOrPat::VarDecl(var) => {
ForHead::VarDecl(var) => {
assert_eq!(
var.decls.len(),
1,
@ -259,7 +263,7 @@ impl ForOf {
)
}
VarDeclOrPat::Pat(pat) => prepend_stmt(
ForHead::Pat(pat) => prepend_stmt(
&mut body.stmts,
AssignExpr {
span: DUMMY_SP,
@ -269,6 +273,10 @@ impl ForOf {
}
.into_stmt(),
),
ForHead::UsingDecl(..) => {
unreachable!("using declaration must be removed by previous pass")
}
}
// !(_step = _iterator()).done;
@ -332,7 +340,7 @@ impl ForOf {
body.stmts.insert(
0,
match left {
VarDeclOrPat::VarDecl(mut var) => {
ForHead::VarDecl(mut var) => {
assert_eq!(var.decls.len(), 1);
VarDecl {
span: var.span,
@ -345,13 +353,17 @@ impl ForOf {
}
.into()
}
VarDeclOrPat::Pat(pat) => AssignExpr {
ForHead::Pat(pat) => AssignExpr {
span: DUMMY_SP,
left: PatOrExpr::Pat(pat),
op: op!("="),
right: step_value,
}
.into_stmt(),
ForHead::UsingDecl(..) => {
unreachable!("using declaration must be removed by previous pass")
}
},
);

View File

@ -949,7 +949,7 @@ impl VisitMut for Generator {
self.begin_script_loop_block();
}
if let VarDeclOrPat::VarDecl(initializer) = &mut node.left {
if let ForHead::VarDecl(initializer) = &mut node.left {
for variable in &initializer.decls {
self.hoist_variable_declaration(variable.name.as_ident().unwrap());
}
@ -1755,7 +1755,7 @@ impl Generator {
node.right.visit_mut_with(self);
self.emit_stmt(Stmt::ForIn(ForInStmt {
span: DUMMY_SP,
left: VarDeclOrPat::Pat(key.clone().into()),
left: ForHead::Pat(key.clone().into()),
right: node.right.take(),
body: Box::new(Stmt::Expr(ExprStmt {
span: DUMMY_SP,
@ -1788,17 +1788,21 @@ impl Generator {
);
let variable = match node.left {
VarDeclOrPat::VarDecl(initializer) => {
ForHead::VarDecl(initializer) => {
for variable in initializer.decls.iter() {
self.hoist_variable_declaration(variable.name.as_ident().unwrap());
}
initializer.decls[0].name.clone()
}
VarDeclOrPat::Pat(mut initializer) => {
ForHead::Pat(mut initializer) => {
initializer.visit_mut_with(self);
*initializer
}
ForHead::UsingDecl(..) => {
unreachable!("using declaration must be removed by previous pass")
}
};
self.emit_assignment(
PatOrExpr::Pat(Box::new(variable)),

View File

@ -592,7 +592,7 @@ fn handle_await_for(stmt: &mut Stmt, is_async_generator: bool) {
}
match s.left {
VarDeclOrPat::VarDecl(v) => {
ForHead::VarDecl(v) => {
let var = v.decls.into_iter().next().unwrap();
let var_decl = VarDeclarator {
span: DUMMY_SP,
@ -610,7 +610,7 @@ fn handle_await_for(stmt: &mut Stmt, is_async_generator: bool) {
.into(),
);
}
VarDeclOrPat::Pat(p) => {
ForHead::Pat(p) => {
for_loop_body.push(Stmt::Expr(ExprStmt {
span: DUMMY_SP,
expr: Box::new(Expr::Assign(AssignExpr {
@ -621,6 +621,10 @@ fn handle_await_for(stmt: &mut Stmt, is_async_generator: bool) {
})),
}));
}
ForHead::UsingDecl(..) => {
unreachable!("using declaration must be removed by previous pass")
}
}
for_loop_body.extend(orig_body);

View File

@ -66,7 +66,7 @@ macro_rules! impl_for_for_stmt {
let mut stmt = None;
let left = match &mut for_stmt.left {
VarDeclOrPat::VarDecl(var_decl) => {
ForHead::VarDecl(var_decl) => {
let ref_ident = private_ident!("_ref");
// Unpack variables
@ -105,7 +105,7 @@ macro_rules! impl_for_for_stmt {
}
.into()
}
VarDeclOrPat::Pat(pat) => {
ForHead::Pat(pat) => {
let var_ident = private_ident!("_ref");
let index = self.vars.len();
let pat = pat.take();
@ -160,6 +160,10 @@ macro_rules! impl_for_for_stmt {
}
.into()
}
ForHead::UsingDecl(..) => {
unreachable!("using declaration must be removed by previous pass")
}
};
for_stmt.left = left;

View File

@ -446,8 +446,8 @@ impl SystemJs {
}
}
fn hoist_for_var_decl(&mut self, var_decl_or_pat: VarDeclOrPat) -> VarDeclOrPat {
if let VarDeclOrPat::VarDecl(mut var_decl) = var_decl_or_pat {
fn hoist_for_var_decl(&mut self, var_decl_or_pat: ForHead) -> ForHead {
if let ForHead::VarDecl(mut var_decl) = var_decl_or_pat {
if var_decl.kind == VarDeclKind::Var {
let var_declarator = var_decl.decls.remove(0);
let mut tos: Vec<Id> = vec![];
@ -469,9 +469,9 @@ impl SystemJs {
.push(Ident::new(to.0, DUMMY_SP.with_ctxt(to.1)));
}
VarDeclOrPat::Pat(var_declarator.name.into())
ForHead::Pat(var_declarator.name.into())
} else {
VarDeclOrPat::VarDecl(var_decl)
ForHead::VarDecl(var_decl)
}
} else {
var_decl_or_pat

View File

@ -1007,10 +1007,10 @@ impl VisitMut for TreeShaker {
}
}
fn visit_mut_var_decl_or_pat(&mut self, n: &mut VarDeclOrPat) {
fn visit_mut_for_head(&mut self, n: &mut ForHead) {
match n {
VarDeclOrPat::VarDecl(..) => {}
VarDeclOrPat::Pat(v) => {
ForHead::VarDecl(..) | ForHead::UsingDecl(..) => {}
ForHead::Pat(v) => {
v.visit_mut_with(self);
}
}

View File

@ -1616,7 +1616,7 @@ impl VisitMut for SimplifyExpr {
self.is_modifying = old;
}
fn visit_mut_var_decl_or_pat(&mut self, n: &mut VarDeclOrPat) {
fn visit_mut_for_head(&mut self, n: &mut ForHead) {
let old = self.is_modifying;
self.is_modifying = true;
n.visit_mut_children_with(self);

View File

@ -400,6 +400,15 @@ where
}
}
Decl::Using(ref var) => {
let mut names: Vec<Id> = vec![];
var.decls.visit_with(&mut VarCollector { to: &mut names });
for name in names {
self.store(name.0.clone(), name.1, true);
}
}
Decl::TsEnum(e) => {
// Currently swc cannot remove constant enums
self.store(e.id.sym.clone(), e.id.span.ctxt, true);
@ -1541,6 +1550,9 @@ where
self.decl_names.insert(class.ident.to_id());
class.class.visit_with(self);
}
Decl::Using(d) => {
d.decls.visit_with(self);
}
Decl::Fn(f) => {
self.decl_names.insert(f.ident.to_id());
f.function.visit_with(self)
@ -1745,7 +1757,7 @@ fn is_decl_concrete(d: &Decl) -> bool {
match d {
Decl::TsEnum(..) => true,
Decl::TsTypeAlias(..) | Decl::TsInterface(..) => false,
Decl::Class(_) | Decl::Fn(_) | Decl::Var(_) => true,
Decl::Class(_) | Decl::Fn(_) | Decl::Var(_) | Decl::Using(..) => true,
Decl::TsModule(b) => ts_module_has_concrete(b),
}
}

View File

@ -635,6 +635,7 @@ define!({
Class(ClassDecl),
Fn(FnDecl),
Var(Box<VarDecl>),
Using(Box<UsingDecl>),
TsInterface(Box<TsInterfaceDecl>),
TsTypeAlias(Box<TsTypeAliasDecl>),
TsEnum(Box<TsEnumDecl>),
@ -1405,14 +1406,14 @@ define!({
}
pub struct ForInStmt {
pub span: Span,
pub left: VarDeclOrPat,
pub left: ForHead,
pub right: Box<Expr>,
pub body: Box<Stmt>,
}
pub struct ForOfStmt {
pub span: Span,
pub is_await: bool,
pub left: VarDeclOrPat,
pub left: ForHead,
pub right: Box<Expr>,
pub body: Box<Stmt>,
}
@ -1426,8 +1427,9 @@ define!({
pub param: Option<Pat>,
pub body: BlockStmt,
}
pub enum VarDeclOrPat {
pub enum ForHead {
VarDecl(Box<VarDecl>),
UsingDecl(Box<UsingDecl>),
Pat(Box<Pat>),
}
pub enum VarDeclOrExpr {
@ -1884,6 +1886,12 @@ define!({
Private(PrivateName),
Public(PropName),
}
pub struct UsingDecl {
pub span: Span,
pub decls: Vec<VarDeclarator>,
}
});
#[macro_export]

View File

@ -28,6 +28,8 @@ pub enum Declaration {
FuncDecl(FunctionDeclaration),
#[tag("VariableDeclaration")]
VarDecl(VariableDeclaration),
#[tag("UsingDeclaration")]
UsingDecl(UsingDeclaration),
#[tag("ClassDeclaration")]
ClassDecl(ClassDeclaration),
#[tag("ExportAllDeclaration")]
@ -282,3 +284,13 @@ pub struct EnumDeclaration {
pub id: Identifier,
pub body: EnumBody,
}
#[derive(Debug, Clone, PartialEq)]
#[ast_serde("EnumDeclaration")]
pub struct UsingDeclaration {
#[serde(flatten)]
pub base: BaseNode,
#[serde(default)]
pub declarations: Vec<VariableDeclarator>,
}

View File

@ -20,6 +20,7 @@ use crate::{
TSInterfaceDeclaration, TSModuleDeclaration, TSNamespaceExportDeclaration,
TSTypeAliasDeclaration,
},
UsingDeclaration,
};
#[derive(Debug, Clone, PartialEq)]
@ -103,6 +104,8 @@ pub enum Statement {
TypeAlias(TypeAlias),
#[tag("EnumDeclaration")]
EnumDecl(EnumDeclaration),
#[tag("UsingDeclaration")]
UsingDecl(UsingDeclaration),
#[tag("TSDeclareFunction")]
TSDeclFunc(TSDeclareFunction),
#[tag("TSInterfaceDeclaration")]

View File

@ -1,8 +1,8 @@
use copyless::BoxHelper;
use swc_ecma_ast::{ClassDecl, Decl, FnDecl, VarDecl, VarDeclKind, VarDeclarator};
use swc_ecma_ast::{ClassDecl, Decl, FnDecl, UsingDecl, VarDecl, VarDeclKind, VarDeclarator};
use swc_estree_ast::{
ClassBody, ClassDeclaration, Declaration, FunctionDeclaration, VariableDeclaration,
VariableDeclarationKind, VariableDeclarator,
ClassBody, ClassDeclaration, Declaration, FunctionDeclaration, UsingDeclaration,
VariableDeclaration, VariableDeclarationKind, VariableDeclarator,
};
use crate::babelify::{extract_class_body_span, Babelify, Context};
@ -15,6 +15,7 @@ impl Babelify for Decl {
Decl::Class(d) => Declaration::ClassDecl(d.babelify(ctx)),
Decl::Fn(d) => Declaration::FuncDecl(d.babelify(ctx)),
Decl::Var(d) => Declaration::VarDecl(d.babelify(ctx)),
Decl::Using(d) => Declaration::UsingDecl(d.babelify(ctx)),
Decl::TsInterface(d) => Declaration::TSInterfaceDecl(d.babelify(ctx)),
Decl::TsTypeAlias(d) => Declaration::TSTypeAliasDecl(d.babelify(ctx)),
Decl::TsEnum(d) => Declaration::TSEnumDecl(d.babelify(ctx)),
@ -123,3 +124,14 @@ impl Babelify for VarDeclarator {
}
}
}
impl Babelify for UsingDecl {
type Output = UsingDeclaration;
fn babelify(self, ctx: &Context) -> Self::Output {
UsingDeclaration {
base: ctx.base(self.span),
declarations: self.decls.babelify(ctx),
}
}
}

View File

@ -1,8 +1,8 @@
use copyless::BoxHelper;
use swc_ecma_ast::{
BlockStmt, BreakStmt, CatchClause, ContinueStmt, DebuggerStmt, Decl, DoWhileStmt, EmptyStmt,
ExprStmt, ForInStmt, ForOfStmt, ForStmt, IfStmt, LabeledStmt, ReturnStmt, Stmt, SwitchCase,
SwitchStmt, ThrowStmt, TryStmt, VarDeclOrExpr, VarDeclOrPat, WhileStmt, WithStmt,
ExprStmt, ForHead, ForInStmt, ForOfStmt, ForStmt, IfStmt, LabeledStmt, ReturnStmt, Stmt,
SwitchCase, SwitchStmt, ThrowStmt, TryStmt, VarDeclOrExpr, WhileStmt, WithStmt,
};
use swc_estree_ast::{
BlockStatement, BreakStatement, CatchClause as BabelCatchClause, ContinueStatement,
@ -56,6 +56,7 @@ impl Babelify for Stmt {
Decl::Class(d) => Statement::ClassDecl(d.babelify(ctx)),
Decl::Fn(d) => Statement::FuncDecl(d.babelify(ctx)),
Decl::Var(d) => Statement::VarDecl(d.babelify(ctx)),
Decl::Using(d) => Statement::UsingDecl(d.babelify(ctx)),
Decl::TsInterface(d) => Statement::TSInterfaceDecl(d.babelify(ctx)),
Decl::TsTypeAlias(d) => Statement::TSTypeAliasDecl(d.babelify(ctx)),
Decl::TsEnum(d) => Statement::TSEnumDecl(d.babelify(ctx)),
@ -300,13 +301,16 @@ impl Babelify for CatchClause {
}
}
impl Babelify for VarDeclOrPat {
impl Babelify for ForHead {
type Output = ForStmtLeft;
fn babelify(self, ctx: &Context) -> Self::Output {
match self {
VarDeclOrPat::VarDecl(v) => ForStmtLeft::VarDecl(v.babelify(ctx)),
VarDeclOrPat::Pat(p) => ForStmtLeft::LVal(p.babelify(ctx).into()),
ForHead::VarDecl(v) => ForStmtLeft::VarDecl(v.babelify(ctx)),
ForHead::Pat(p) => ForStmtLeft::LVal(p.babelify(ctx).into()),
_ => {
todo!("ForHead::UsingDecl({self:?})")
}
}
}
}

View File

@ -2,12 +2,12 @@ use swc_common::DUMMY_SP;
use swc_ecma_ast::{
BlockStmt, BreakStmt, ClassDecl, ClassExpr, ContinueStmt, DebuggerStmt, Decl, DefaultDecl,
DoWhileStmt, EmptyStmt, ExportAll, ExportDecl, ExportDefaultDecl, ExportDefaultExpr,
ExportNamedSpecifier, Expr, ExprStmt, FnDecl, FnExpr, ForInStmt, ForOfStmt, ForStmt, IfStmt,
ImportDecl, ImportNamedSpecifier, ImportSpecifier, ImportStarAsSpecifier, KeyValueProp,
ExportNamedSpecifier, Expr, ExprStmt, FnDecl, FnExpr, ForHead, ForInStmt, ForOfStmt, ForStmt,
IfStmt, ImportDecl, ImportNamedSpecifier, ImportSpecifier, ImportStarAsSpecifier, KeyValueProp,
LabeledStmt, Lit, ModuleDecl, ModuleItem, NamedExport, ObjectLit, Pat, Prop, PropName,
PropOrSpread, ReturnStmt, Stmt, SwitchStmt, ThrowStmt, TryStmt, TsExportAssignment,
TsInterfaceDecl, TsModuleDecl, TsTypeAliasDecl, VarDecl, VarDeclKind, VarDeclOrExpr,
VarDeclOrPat, VarDeclarator, WhileStmt, WithStmt,
VarDeclarator, WhileStmt, WithStmt,
};
use swc_estree_ast::{
BlockStatement, BreakStatement, ClassDeclaration, ContinueStatement, DebuggerStatement,
@ -178,12 +178,12 @@ impl Swcify for ForInStatement {
}
impl Swcify for ForStmtLeft {
type Output = VarDeclOrPat;
type Output = ForHead;
fn swcify(self, ctx: &Context) -> Self::Output {
match self {
ForStmtLeft::VarDecl(v) => VarDeclOrPat::VarDecl(v.swcify(ctx).into()),
ForStmtLeft::LVal(v) => VarDeclOrPat::Pat(v.swcify(ctx).into()),
ForStmtLeft::VarDecl(v) => ForHead::VarDecl(v.swcify(ctx).into()),
ForStmtLeft::LVal(v) => ForHead::Pat(v.swcify(ctx).into()),
}
}
}