mirror of
https://github.com/swc-project/swc.git
synced 2024-10-05 04:39:06 +03:00
feat(es/trasform): Support static blocks (#2474)
swc_ecma_transforms_proposal: - Add transform for static blocks, which is stage 3.
This commit is contained in:
parent
cef2c8666e
commit
bb1cc974c7
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -2909,7 +2909,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "swc_ecma_transforms_proposal"
|
||||
version = "0.51.0"
|
||||
version = "0.51.1"
|
||||
dependencies = [
|
||||
"either",
|
||||
"serde",
|
||||
|
@ -6,7 +6,7 @@ edition = "2018"
|
||||
license = "Apache-2.0/MIT"
|
||||
name = "swc_ecma_transforms_proposal"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.51.0"
|
||||
version = "0.51.1"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
pub use self::{
|
||||
decorators::decorators, export_default_from::export_default_from,
|
||||
import_assertions::import_assertions, private_in_object::private_in_object,
|
||||
static_blocks::static_blocks,
|
||||
};
|
||||
|
||||
pub mod decorators;
|
||||
mod export_default_from;
|
||||
mod import_assertions;
|
||||
pub mod private_in_object;
|
||||
pub mod static_blocks;
|
||||
|
116
ecmascript/transforms/proposal/src/static_blocks.rs
Normal file
116
ecmascript/transforms/proposal/src/static_blocks.rs
Normal file
@ -0,0 +1,116 @@
|
||||
use swc_atoms::JsWord;
|
||||
use swc_common::{collections::AHashSet, DUMMY_SP};
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_visit::{noop_fold_type, Fold, FoldWith};
|
||||
|
||||
struct ClassStaticBlock;
|
||||
|
||||
pub fn static_blocks() -> impl Fold {
|
||||
ClassStaticBlock
|
||||
}
|
||||
|
||||
impl ClassStaticBlock {
|
||||
fn fold_class_for_static_block(&mut self, class: Class) -> Class {
|
||||
let mut private_names = AHashSet::default();
|
||||
for member in &class.body {
|
||||
if let ClassMember::PrivateProp(private_property) = member {
|
||||
private_names.insert(private_property.key.id.sym.clone());
|
||||
}
|
||||
}
|
||||
let mut members = vec![];
|
||||
for member in class.body {
|
||||
let new_member = match member {
|
||||
ClassMember::StaticBlock(static_block) => {
|
||||
let static_block_private_id: JsWord = {
|
||||
let mut id_value: JsWord = "_".into();
|
||||
let mut count = 0;
|
||||
while private_names.contains(&id_value) {
|
||||
count = count + 1;
|
||||
id_value = format!("{}{}", &id_value, count).into();
|
||||
}
|
||||
private_names.insert(id_value.clone());
|
||||
id_value
|
||||
};
|
||||
ClassMember::PrivateProp(
|
||||
self.fold_static_block(static_block, static_block_private_id),
|
||||
)
|
||||
}
|
||||
m => m,
|
||||
};
|
||||
members.push(new_member);
|
||||
}
|
||||
Class {
|
||||
body: members,
|
||||
..class
|
||||
}
|
||||
}
|
||||
fn fold_static_block(&mut self, static_block: StaticBlock, private_id: JsWord) -> PrivateProp {
|
||||
PrivateProp {
|
||||
span: DUMMY_SP,
|
||||
is_static: true,
|
||||
is_abstract: false,
|
||||
is_optional: false,
|
||||
is_override: false,
|
||||
readonly: false,
|
||||
computed: false,
|
||||
definite: false,
|
||||
type_ann: None,
|
||||
decorators: Vec::new(),
|
||||
accessibility: None,
|
||||
key: PrivateName {
|
||||
span: DUMMY_SP,
|
||||
id: Ident {
|
||||
span: DUMMY_SP,
|
||||
sym: private_id,
|
||||
optional: false,
|
||||
},
|
||||
},
|
||||
value: Some(Box::new(Expr::Call(CallExpr {
|
||||
span: DUMMY_SP,
|
||||
callee: ExprOrSuper::Expr(Box::new(Expr::Arrow(ArrowExpr {
|
||||
span: DUMMY_SP,
|
||||
params: Vec::new(),
|
||||
is_async: false,
|
||||
is_generator: false,
|
||||
type_params: None,
|
||||
return_type: None,
|
||||
body: BlockStmtOrExpr::BlockStmt(static_block.body),
|
||||
}))),
|
||||
args: Vec::new(),
|
||||
type_args: None,
|
||||
}))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Fold for ClassStaticBlock {
|
||||
noop_fold_type!();
|
||||
|
||||
fn fold_decl(&mut self, declaration: Decl) -> Decl {
|
||||
let declaration = declaration.fold_children_with(self);
|
||||
match declaration {
|
||||
Decl::Class(class_declaration) => {
|
||||
let class = self.fold_class_for_static_block(class_declaration.class);
|
||||
Decl::Class(ClassDecl {
|
||||
class,
|
||||
..class_declaration
|
||||
})
|
||||
}
|
||||
_ => declaration,
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_expr(&mut self, expression: Expr) -> Expr {
|
||||
let expression = expression.fold_children_with(self);
|
||||
match expression {
|
||||
Expr::Class(class_expression) => {
|
||||
let class = self.fold_class_for_static_block(class_expression.class);
|
||||
Expr::Class(ClassExpr {
|
||||
class,
|
||||
..class_expression
|
||||
})
|
||||
}
|
||||
_ => expression,
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
class Foo {
|
||||
static bar = 42;
|
||||
static {
|
||||
this.foo = Foo.bar;
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
class Foo {
|
||||
static bar = 42;
|
||||
static #_ = (() => {
|
||||
this.foo = Foo.bar;
|
||||
})();
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
class Foo extends class extends class Base {
|
||||
static {
|
||||
this.qux = 21;
|
||||
}
|
||||
} {
|
||||
static {
|
||||
this.bar = 21;
|
||||
}
|
||||
} {
|
||||
static {
|
||||
this.foo = this.bar + this.qux;
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
class Foo extends class extends class Base {
|
||||
static #_ = (() => {
|
||||
this.qux = 21;
|
||||
})();
|
||||
} {
|
||||
static #_ = (() => {
|
||||
this.bar = 21;
|
||||
})();
|
||||
} {
|
||||
static #_ = (() => {
|
||||
this.foo = this.bar + this.qux;
|
||||
})();
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
class Foo {
|
||||
static #bar = 21;
|
||||
static {
|
||||
this.foo = this.#bar;
|
||||
this.qux1 = this.qux;
|
||||
}
|
||||
static qux = 21;
|
||||
static {
|
||||
this.qux2 = this.qux;
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
class Foo {
|
||||
static #bar = 21;
|
||||
static #_ = (() => {
|
||||
this.foo = this.#bar;
|
||||
this.qux1 = this.qux;
|
||||
})();
|
||||
static qux = 21;
|
||||
static #_1 = (() => {
|
||||
this.qux2 = this.qux;
|
||||
})();
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
class Foo {
|
||||
static #_ = 42;
|
||||
static {
|
||||
this.foo = this.#_;
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
class Foo {
|
||||
static #_ = 42;
|
||||
static #_1 = (() => {
|
||||
this.foo = this.#_;
|
||||
})();
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
class Base {
|
||||
constructor() {
|
||||
this.Foo = class {
|
||||
static {
|
||||
this.foo = new.target;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
class Base {
|
||||
constructor() {
|
||||
this.Foo = class {
|
||||
static #_ = (() => {
|
||||
this.foo = new.target;
|
||||
})();
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
class Foo {
|
||||
static bar = 42;
|
||||
static {
|
||||
this.foo = Foo.bar;
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
class Foo {}
|
||||
_defineProperty(Foo, "bar", 42);
|
||||
var __ = {
|
||||
writable: true,
|
||||
value: (() => {
|
||||
Foo.foo = Foo.bar;
|
||||
})(),
|
||||
};
|
@ -0,0 +1,13 @@
|
||||
class Foo extends class extends class Base {
|
||||
static {
|
||||
this.qux = 21;
|
||||
}
|
||||
} {
|
||||
static {
|
||||
this.bar = 21;
|
||||
}
|
||||
} {
|
||||
static {
|
||||
this.foo = this.bar + this.qux;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
class Foo extends (function () {
|
||||
class _class extends (function () {
|
||||
class Base {}
|
||||
var __ = {
|
||||
writable: true,
|
||||
value: (() => {
|
||||
Base.qux = 21;
|
||||
})(),
|
||||
};
|
||||
return Base;
|
||||
})() {}
|
||||
var __ = {
|
||||
writable: true,
|
||||
value: (() => {
|
||||
_class.bar = 21;
|
||||
})(),
|
||||
};
|
||||
return _class;
|
||||
})() {}
|
||||
var __ = {
|
||||
writable: true,
|
||||
value: (() => {
|
||||
Foo.foo = Foo.bar + Foo.qux;
|
||||
})(),
|
||||
};
|
@ -0,0 +1,11 @@
|
||||
class Foo {
|
||||
static #bar = 21;
|
||||
static {
|
||||
this.foo = this.#bar;
|
||||
this.qux1 = this.qux;
|
||||
}
|
||||
static qux = 21;
|
||||
static {
|
||||
this.qux2 = this.qux;
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
class Foo {}
|
||||
var _bar = {
|
||||
writable: true,
|
||||
value: 21,
|
||||
};
|
||||
var __ = {
|
||||
writable: true,
|
||||
value: (() => {
|
||||
Foo.foo = Foo.#bar;
|
||||
Foo.qux1 = Foo.qux;
|
||||
})(),
|
||||
};
|
||||
_defineProperty(Foo, "qux", 21);
|
||||
var __1 = {
|
||||
writable: true,
|
||||
value: (() => {
|
||||
Foo.qux2 = Foo.qux;
|
||||
})(),
|
||||
};
|
@ -0,0 +1,6 @@
|
||||
class Foo {
|
||||
static #_ = 42;
|
||||
static {
|
||||
this.foo = this.#_;
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
class Foo {}
|
||||
var __ = {
|
||||
writable: true,
|
||||
value: 42,
|
||||
};
|
||||
var __1 = {
|
||||
writable: true,
|
||||
value: (() => {
|
||||
Foo.foo = Foo.#_;
|
||||
})(),
|
||||
};
|
@ -0,0 +1,9 @@
|
||||
class Base {
|
||||
constructor() {
|
||||
this.Foo = class {
|
||||
static {
|
||||
this.foo = new.target;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
class Base {
|
||||
constructor() {
|
||||
this.Foo = (function () {
|
||||
class _class {}
|
||||
var __ = {
|
||||
writable: true,
|
||||
value: (() => {
|
||||
_class.foo = new.target;
|
||||
})(),
|
||||
};
|
||||
return _class;
|
||||
})();
|
||||
}
|
||||
}
|
33
ecmascript/transforms/proposal/tests/static_blocks.rs
Normal file
33
ecmascript/transforms/proposal/tests/static_blocks.rs
Normal file
@ -0,0 +1,33 @@
|
||||
use std::path::PathBuf;
|
||||
use swc_common::chain;
|
||||
use swc_ecma_parser::{EsConfig, Syntax};
|
||||
use swc_ecma_transforms_compat::es2020::class_properties;
|
||||
use swc_ecma_transforms_proposal::static_blocks;
|
||||
use swc_ecma_transforms_testing::test_fixture;
|
||||
use swc_ecma_visit::Fold;
|
||||
|
||||
#[testing::fixture("tests/static-blocks/**/input.js")]
|
||||
fn fixture(input: PathBuf) {
|
||||
let parent = input.parent().unwrap();
|
||||
|
||||
let output = parent.join("output.js");
|
||||
test_fixture(
|
||||
Syntax::Es(EsConfig {
|
||||
static_blocks: true,
|
||||
..Default::default()
|
||||
}),
|
||||
&|_t| {
|
||||
let pass: Box<dyn Fold> = if input.to_string_lossy().contains("class-properties") {
|
||||
Box::new(chain!(
|
||||
static_blocks(),
|
||||
class_properties(class_properties::Config::default())
|
||||
))
|
||||
} else {
|
||||
Box::new(static_blocks())
|
||||
};
|
||||
pass
|
||||
},
|
||||
&input,
|
||||
&output,
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue
Block a user