fix(bundler): Fix bundler (#1427)

swc_bundler:
 - Create variables for export while preparing a module. (denoland/deno#9560)
 - Fix order of statements.
 - Invoke dce multiple time if required. (denoland/deno#9546)

swc_ecma_transforms_optimization:
 - dce: Track modifications correctly.
This commit is contained in:
강동윤 2021-02-26 18:21:42 +09:00 committed by GitHub
parent 05a90715d1
commit c047e0e54d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
94 changed files with 18390 additions and 5494 deletions

View File

@ -11,7 +11,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc"
repository = "https://github.com/swc-project/swc.git"
version = "0.7.0"
version = "0.7.1"
[lib]
name = "swc"
@ -33,8 +33,8 @@ swc_ecma_ast = {version = "0.40.0", path = "./ecmascript/ast"}
swc_ecma_codegen = {version = "0.47.0", path = "./ecmascript/codegen"}
swc_ecma_ext_transforms = {version = "0.6.0", path = "./ecmascript/ext-transforms"}
swc_ecma_parser = {version = "0.49.0", path = "./ecmascript/parser"}
swc_ecma_preset_env = {version = "0.8.0", path = "./ecmascript/preset_env"}
swc_ecma_transforms = {version = "0.38.0", path = "./ecmascript/transforms", features = [
swc_ecma_preset_env = {version = "0.8.1", path = "./ecmascript/preset_env"}
swc_ecma_transforms = {version = "0.38.1", path = "./ecmascript/transforms", features = [
"compat",
"module",
"optimization",

View File

@ -9,7 +9,7 @@ include = ["Cargo.toml", "build.rs", "src/**/*.rs", "src/**/*.js"]
license = "Apache-2.0/MIT"
name = "swc_bundler"
repository = "https://github.com/swc-project/swc.git"
version = "0.25.0"
version = "0.25.1"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
@ -35,7 +35,7 @@ swc_common = {version = "0.10.10", path = "../common"}
swc_ecma_ast = {version = "0.40.0", path = "../ecmascript/ast"}
swc_ecma_codegen = {version = "0.47.0", path = "../ecmascript/codegen"}
swc_ecma_parser = {version = "0.49.0", path = "../ecmascript/parser"}
swc_ecma_transforms = {version = "0.38.0", path = "../ecmascript/transforms", features = ["optimization"]}
swc_ecma_transforms = {version = "0.38.1", path = "../ecmascript/transforms", features = ["optimization"]}
swc_ecma_utils = {version = "0.30.0", path = "../ecmascript/utils"}
swc_ecma_visit = {version = "0.26.0", path = "../ecmascript/visit"}
@ -44,7 +44,7 @@ hex = "0.4"
ntest = "0.7.2"
reqwest = {version = "0.10.8", features = ["blocking"]}
sha-1 = "0.9"
swc_ecma_transforms = {version = "0.38.0", path = "../ecmascript/transforms", features = ["react", "typescript"]}
swc_ecma_transforms = {version = "0.38.1", path = "../ecmascript/transforms", features = ["react", "typescript"]}
tempfile = "3.1.0"
testing = {version = "0.10.3", path = "../testing"}
url = "2.1.1"

View File

@ -144,8 +144,8 @@ where
let dep_info = self.scope.get_module(dep_id).unwrap();
let mut dep = if self.scope.should_be_wrapped_with_a_fn(dep_id) {
let mut dep: Modules = self.get_module_for_merging(ctx, dep_id, false)?;
dep = self.wrap_esm(ctx, dep_id, dep.into())?.into();
self.prepare(&dep_info, &mut dep);
dep = self.wrap_esm(ctx, dep_id, dep.into())?.into();
dep
} else {
self.merge_modules(ctx, dep_id, false, false)

View File

@ -1,4 +1,3 @@
use crate::id::Id;
use crate::modules::Modules;
use crate::util::ExprExt;
use crate::util::VarDeclaratorExt;
@ -54,7 +53,6 @@ where
};
let mut module_items = vec![];
let mut extra_exports = vec![];
let stmts = {
module.iter().for_each(|(_, item)| {
@ -114,10 +112,7 @@ where
let mut module = Module::from(module).fold_with(&mut ExportToReturn {
synthesized_ctxt: self.synthesized_ctxt,
injected_ctxt: self.injected_ctxt,
return_props: Default::default(),
esm_exports: &mut extra_exports,
module_var: &module_var_name,
});
take(&mut module.body)
@ -189,7 +184,6 @@ where
};
module_items.push(ModuleItem::Stmt(Stmt::Decl(Decl::Var(var_decl))));
module_items.extend(extra_exports);
// print_hygiene(
// "wrap",
@ -229,60 +223,27 @@ impl Visit for TopLevelAwaitFinder {
}
}
struct ExportToReturn<'a> {
injected_ctxt: SyntaxContext,
module_var: &'a Id,
struct ExportToReturn {
return_props: Vec<PropOrSpread>,
synthesized_ctxt: SyntaxContext,
esm_exports: &'a mut Vec<ModuleItem>,
}
impl ExportToReturn<'_> {
impl ExportToReturn {
fn export_id(&mut self, i: Ident) {
self.return_props
.push(PropOrSpread::Prop(Box::new(Prop::Shorthand(i.clone()))));
if self.module_var.ctxt() == i.span.ctxt {
return;
}
let src = i.clone();
let mut exported = i;
exported.span.ctxt = self.module_var.ctxt();
self.esm_exports.push(
src.assign_to(exported)
.into_module_item(self.injected_ctxt, "export to return => export_id"),
);
}
fn export_key_value(&mut self, key: Ident, value: Ident, skip_var: bool) {
fn export_key_value(&mut self, key: Ident, value: Ident) {
self.return_props
.push(PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
key: PropName::Ident(key.clone()),
value: Box::new(Expr::Ident(value.clone())),
}))));
if skip_var {
return;
}
if self.module_var.ctxt() == value.span.ctxt {
return;
}
let mut exported = key;
exported.span.ctxt = self.module_var.ctxt();
self.esm_exports.push(
value
.assign_to(exported)
.into_module_item(self.injected_ctxt, "export to return => export_key_value"),
);
}
}
impl Fold for ExportToReturn<'_> {
impl Fold for ExportToReturn {
noop_fold_type!();
fn fold_stmt(&mut self, s: Stmt) -> Stmt {
@ -320,7 +281,6 @@ impl Fold for ExportToReturn<'_> {
self.export_key_value(
Ident::new(js_word!("default"), export.span),
ident.clone(),
false,
);
Some(Stmt::Decl(Decl::Class(ClassDecl {
@ -336,7 +296,6 @@ impl Fold for ExportToReturn<'_> {
self.export_key_value(
Ident::new(js_word!("default"), export.span),
ident.clone(),
false,
);
Some(Stmt::Decl(Decl::Fn(FnDecl {
@ -360,11 +319,7 @@ impl Fold for ExportToReturn<'_> {
Some(exported) => {
// As injected named exports are converted to variables by other
// passes, we should not create a variable for it.
self.export_key_value(
exported.clone(),
named.orig.clone(),
export.span.ctxt == self.injected_ctxt || export.src.is_some(),
);
self.export_key_value(exported.clone(), named.orig.clone());
}
None => {
self.export_id(named.orig.clone());

View File

@ -14,7 +14,6 @@ use rayon::iter::ParallelIterator;
use swc_atoms::js_word;
use swc_common::{SyntaxContext, DUMMY_SP};
use swc_ecma_ast::*;
use swc_ecma_utils::{ident::IdentLike, Id};
use swc_ecma_visit::{noop_fold_type, Fold};
impl<L, R> Bundler<'_, L, R>
@ -61,7 +60,6 @@ where
) -> Result<Modules, Error> {
self.run(|| {
log::debug!("Reexporting {:?}", dep_id);
let injected_ctxt = self.injected_ctxt;
let dep_info = self.scope.get_module(dep_id).unwrap();
let mut dep = self
@ -95,32 +93,18 @@ where
// `export *`
if specifiers.is_empty() {
let mut items = vec![];
// We should exclude `default`
dep.retain_mut(|module_id, item| match item {
dep.retain_mut(|_, item| match item {
ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(export)) => {
export.specifiers.retain(|s| match s {
ExportSpecifier::Named(ExportNamedSpecifier {
orig,
exported:
Some(Ident {
sym: js_word!("default"),
span: exported_span,
..
}),
..
}) => {
items.push((
module_id,
orig.clone()
.assign_to(Ident::new(js_word!("default"), *exported_span))
.into_module_item(
injected_ctxt,
"Removing default for export *",
),
));
false
}
}) => false,
_ => true,
});
if export.specifiers.is_empty() {
@ -131,14 +115,8 @@ where
}
_ => true,
});
dep.append_all(items);
} else {
unexprt_as_var(&mut dep, dep_info.export_ctxt());
dep = dep.fold_with(&mut DepUnexporter {
exports: &specifiers,
});
dep = dep.fold_with(&mut DepUnexporter {});
// print_hygiene(&format!("dep: unexport"), &self.cm,
// &dep.clone().into());
@ -218,170 +196,28 @@ pub(super) fn inject_export(
entry.add_dep(dep);
}
/// Converts
///
/// ```js
/// export { l1 as e2 };
/// ```
///
/// to
///
/// ```js
/// const e3 = l1;
/// ```
///
/// export { foo#7 } from './b' where #7 is mark of './b'
/// =>
/// export { foo#7 as foo#5 } where #5 is mark of current entry.
fn unexprt_as_var(modules: &mut Modules, dep_export_ctxt: SyntaxContext) {
modules.map_items_mut(|_, n| {
match n {
ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
ref export @ NamedExport { src: None, .. },
)) => {
let mut decls = vec![];
for s in &export.specifiers {
match s {
ExportSpecifier::Namespace(_) => {}
ExportSpecifier::Default(_) => {}
ExportSpecifier::Named(n) => match &n.exported {
Some(exported) => {
// TODO: (maybe) Check previous context
let exported = exported.clone();
// exported.span = exported.span.with_ctxt(self.dep_ctxt);
struct DepUnexporter;
if exported.sym != n.orig.sym
|| exported.span.ctxt != n.orig.span.ctxt
{
decls.push(VarDeclarator {
span: n.span,
name: Pat::Ident(exported.into()),
init: Some(Box::new(Expr::Ident(n.orig.clone()))),
definite: true,
})
}
}
None => {
if n.orig.span.ctxt != dep_export_ctxt {
log::trace!("Alias: {:?} -> {:?}", n.orig, dep_export_ctxt);
decls.push(VarDeclarator {
span: n.span,
name: Pat::Ident(
Ident::new(
n.orig.sym.clone(),
n.orig.span.with_ctxt(dep_export_ctxt),
)
.into(),
),
init: Some(Box::new(Expr::Ident(n.orig.clone()))),
definite: false,
})
}
}
},
}
}
if decls.is_empty() {
*n = ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP }))
} else {
*n = ModuleItem::Stmt(Stmt::Decl(Decl::Var(VarDecl {
span: export.span,
decls,
declare: false,
kind: VarDeclKind::Const,
})))
}
}
_ => {}
}
})
}
struct DepUnexporter<'a> {
exports: &'a [Specifier],
}
impl DepUnexporter<'_> {
fn is_exported(&self, id: &Id) -> bool {
if self.exports.is_empty() {
return true;
}
self.exports.iter().any(|s| match s {
Specifier::Specific { local, .. } => local.to_id() == *id,
Specifier::Namespace { local, all } => local.to_id() == *id || *all,
})
}
}
impl Fold for DepUnexporter<'_> {
impl Fold for DepUnexporter {
noop_fold_type!();
fn fold_module_item(&mut self, item: ModuleItem) -> ModuleItem {
match item {
ModuleItem::ModuleDecl(decl) => match decl {
ModuleDecl::ExportDecl(mut export) => {
match &mut export.decl {
Decl::Class(c) => {
if self.is_exported(&c.ident.to_id()) {
return ModuleItem::Stmt(Stmt::Decl(export.decl));
}
}
Decl::Fn(f) => {
if self.is_exported(&f.ident.to_id()) {
return ModuleItem::Stmt(Stmt::Decl(export.decl));
}
}
Decl::Var(..) => {
if self.exports.is_empty() {
return ModuleItem::Stmt(Stmt::Decl(export.decl));
}
}
_ => {}
}
ModuleItem::Stmt(Stmt::Decl(export.decl))
}
ModuleDecl::ExportDefaultDecl(export) => match export.decl {
DefaultDecl::Class(ClassExpr { ident: None, .. })
| DefaultDecl::Fn(FnExpr { ident: None, .. }) => {
ModuleItem::ModuleDecl(decl) => {
match decl {
// Empty statement
ModuleDecl::ExportDecl(..)
| ModuleDecl::ExportDefaultDecl(..)
| ModuleDecl::ExportAll(..)
| ModuleDecl::ExportDefaultExpr(..)
| ModuleDecl::ExportNamed(..) => {
ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP }))
}
DefaultDecl::TsInterfaceDecl(decl) => {
ModuleItem::Stmt(Stmt::Decl(Decl::TsInterface(decl)))
}
ModuleDecl::Import(..) => ModuleItem::ModuleDecl(decl),
DefaultDecl::Class(ClassExpr {
ident: Some(ident),
class,
}) => ModuleItem::Stmt(Stmt::Decl(Decl::Class(ClassDecl {
declare: false,
ident,
class,
}))),
DefaultDecl::Fn(FnExpr {
ident: Some(ident),
function,
}) => ModuleItem::Stmt(Stmt::Decl(Decl::Fn(FnDecl {
declare: false,
function,
ident,
}))),
},
// Empty statement
ModuleDecl::ExportAll(..)
| ModuleDecl::ExportDefaultExpr(..)
| ModuleDecl::ExportNamed(..) => {
ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP }))
_ => unimplemented!("Unexported: {:?}", decl),
}
ModuleDecl::Import(..) => ModuleItem::ModuleDecl(decl),
_ => unimplemented!("Unexported: {:?}", decl),
},
}
_ => item,
}

View File

@ -130,8 +130,8 @@ where
// Now we handle imports
let mut module = if wrapped {
let mut module: Modules = self.get_module_for_merging(ctx, dep_id, false)?;
module = self.wrap_esm(ctx, dep_id, module.into())?.into();
self.prepare(&dep_info, &mut module);
module = self.wrap_esm(ctx, dep_id, module.into())?.into();
let plan = ctx.plan.normal.get(&dep_id);
let default_plan;
@ -712,10 +712,12 @@ where
// print_hygiene("before sort", &self.cm, &entry.clone().into());
entry.sort(id, &ctx.graph, &self.cm);
// print_hygiene("before inline", &self.cm, &entry.clone().into());
inline(self.injected_ctxt, entry);
entry.sort(id, &ctx.graph, &self.cm);
// print_hygiene("done", &self.cm, &entry.clone().into());
entry.retain_mut(|_, item| {
@ -800,6 +802,9 @@ where
/// Basically one module have two top-level contexts. One is for it's codes
/// and another is for exporting. This method connects two module by
/// injecting `const local_A = exported_B_from_foo;`
///
///
/// TODO: We convert all exports to variable at here.
pub(crate) fn prepare(&self, info: &TransformedModule, module: &mut Modules) {
let injected_ctxt = self.injected_ctxt;
@ -877,7 +882,7 @@ where
.assign_to(s.local.clone())
.into_module_item(
injected_ctxt,
"from_replace_import_specifiers: namespaced",
"prepare -> import -> namespace",
),
);
}
@ -973,13 +978,20 @@ where
local.sym
);
let exported =
Ident::new(js_word!("default"), DUMMY_SP.with_ctxt(info.export_ctxt()));
new.push(
local
.clone()
.assign_to(exported.clone())
.into_module_item(injected_ctxt, "prepare -> export default decl"),
);
let specifier = ExportSpecifier::Named(ExportNamedSpecifier {
span: DUMMY_SP,
orig: local,
exported: Some(Ident::new(
js_word!("default"),
DUMMY_SP.with_ctxt(info.export_ctxt()),
)),
exported: Some(exported),
});
new.push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
NamedExport {
@ -1011,14 +1023,21 @@ where
.into_module_item(injected_ctxt, "prepare -> export default expr"),
);
let exported =
Ident::new(js_word!("default"), DUMMY_SP.with_ctxt(info.export_ctxt()));
new.push(
local
.clone()
.assign_to(exported.clone())
.into_module_item(injected_ctxt, "prepare -> export default expr"),
);
// Create `export { local_default as default }`
let specifier = ExportSpecifier::Named(ExportNamedSpecifier {
span: DUMMY_SP,
orig: local,
exported: Some(Ident::new(
js_word!("default"),
DUMMY_SP.with_ctxt(info.export_ctxt()),
)),
exported: Some(exported),
});
log::trace!("Exporting `default` with `export default expr`");
new.push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
@ -1056,8 +1075,8 @@ where
new.push(ModuleItem::Stmt(Stmt::Decl(Decl::Var(v))));
log::trace!("Exporting `default` with `export decl``");
new.push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
NamedExport {
let export =
ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(NamedExport {
span: export.span.with_ctxt(injected_ctxt),
specifiers: ids
.into_iter()
@ -1067,6 +1086,15 @@ where
id.span.with_ctxt(info.export_ctxt()),
);
new.push(
id.clone()
.assign_to(exported.clone())
.into_module_item(
injected_ctxt,
"prepare -> export decl -> var",
),
);
ExportNamedSpecifier {
span: DUMMY_SP,
orig: id,
@ -1078,8 +1106,8 @@ where
src: None,
type_only: false,
asserts: None,
},
)));
}));
new.push(export);
continue;
}
@ -1097,6 +1125,14 @@ where
// Create `export { local_ident as exported_ident }`
let exported =
Ident::new(local.sym.clone(), local.span.with_ctxt(info.export_ctxt()));
new.push(
local
.clone()
.assign_to(exported.clone())
.into_module_item(injected_ctxt, "prepare -> export decl -> var"),
);
let specifier = ExportSpecifier::Named(ExportNamedSpecifier {
span: DUMMY_SP,
orig: local,
@ -1114,6 +1150,50 @@ where
)));
}
ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(NamedExport {
ref specifiers,
..
})) => {
for s in specifiers {
match s {
ExportSpecifier::Named(ExportNamedSpecifier {
orig,
exported: Some(exported),
..
}) => {
new.push(
orig.clone().assign_to(exported.clone()).into_module_item(
injected_ctxt,
"prepare -> export named -> aliased",
),
);
}
ExportSpecifier::Default(ExportDefaultSpecifier {
exported,
..
}) => {
new.push(
Ident::new(
js_word!("default"),
DUMMY_SP.with_ctxt(info.local_ctxt()),
)
.clone()
.assign_to(exported.clone())
.into_module_item(
injected_ctxt,
"prepare -> export named -> aliased",
),
);
}
_ => {}
}
}
new.push(item);
}
_ => {
new.push(item);
}
@ -1259,17 +1339,7 @@ where
for specifier in &export.specifiers {
match specifier {
ExportSpecifier::Namespace(ns) => {
let mut lhs = ns.name.clone();
lhs.span = lhs.span.with_ctxt(info.export_ctxt());
vars.push((
module_id,
ns.name.clone().assign_to(lhs).into_module_item(
injected_ctxt,
"import_deps_namespace",
),
));
}
ExportSpecifier::Namespace(..) => {}
ExportSpecifier::Default(default) => {
let mut lhs = default.exported.clone();
lhs.span = lhs.span.with_ctxt(info.export_ctxt());
@ -1285,73 +1355,8 @@ where
),
));
}
ExportSpecifier::Named(named) => match &named.exported {
Some(exported) => {
assert_ne!(
named.orig.span.ctxt, exported.span.ctxt,
"While handling imports, all named export \
specifiers should be modified to reflect syntax \
context correctly by previous passes"
);
vars.push((
module_id,
named
.orig
.clone()
.assign_to(exported.clone())
.into_module_item(
injected_ctxt,
&format!(
"import -> named alias -> prepared: {}",
info.fm.name
),
),
));
if exported.span.ctxt != info.export_ctxt()
&& exported.sym != js_word!("default")
{
let mut lhs = exported.clone();
lhs.span = lhs.span.with_ctxt(info.export_ctxt());
vars.push((
module_id,
exported
.clone()
.assign_to(lhs)
.into_module_item(
injected_ctxt,
&format!(
"import -> named alias -> export: \
{}",
info.fm.name
),
),
));
}
}
None => {
if info.export_ctxt() != named.orig.span.ctxt {
let mut lhs: Ident = named.orig.clone();
lhs.span.ctxt = info.export_ctxt();
vars.push((
module_id,
named
.orig
.clone()
.assign_to(lhs)
.into_module_item(
injected_ctxt,
&format!(
"import_deps: named without \
alias: {}",
info.fm.name
),
),
));
}
}
},
// Handlded by `prepare`
ExportSpecifier::Named(..) => {}
}
}

View File

@ -213,9 +213,7 @@ where
for s in &mut named.specifiers {
match s {
ExportSpecifier::Namespace(n) => {
if let Some((_, export_ctxt)) = ctxt {
n.name.span.ctxt = export_ctxt;
}
n.name.span.ctxt = self.export_ctxt;
need_wrapping = true;
v.push(Specifier::Namespace {

View File

@ -1,4 +1,5 @@
use crate::{Bundler, Load, Resolve};
use swc_common::pass::Repeat;
use swc_ecma_ast::*;
use swc_ecma_transforms::optimization::simplify::{const_propgation::constant_propagation, dce};
use swc_ecma_visit::FoldWith;
@ -18,10 +19,10 @@ where
node = node.fold_with(&mut constant_propagation())
}
node = node.fold_with(&mut dce::dce(dce::Config {
node = node.fold_with(&mut Repeat::new(dce::dce(dce::Config {
used: None,
used_mark: self.used_mark,
}));
})));
node
})

View File

@ -37,11 +37,6 @@ struct Inliner {
impl Inliner {
fn store(&mut self, from: Id, to: Id) {
if let Some(mapped) = self.data.ids.get(&to).cloned() {
self.store(from, mapped);
return;
}
if let Some(prev) = self.data.ids.insert(from.clone(), to.clone()) {
unreachable!(
"Multiple identifiers equivalent up to span hygiene found: {:#?}\nFirst = \
@ -86,6 +81,74 @@ impl Visit for Inliner {
impl VisitMut for Inliner {
noop_visit_mut_type!();
/// Don't modify exported ident.
fn visit_mut_export_named_specifier(&mut self, n: &mut ExportNamedSpecifier) {
if n.exported.is_none() {
n.exported = Some(n.orig.clone());
}
n.orig.visit_mut_with(self);
}
fn visit_mut_ident(&mut self, n: &mut Ident) {
if let Some(mapped) = self.data.ids.get(&n.clone().into()).cloned() {
*n = mapped.into();
n.visit_mut_with(self);
}
}
/// General logic for member expression.s
fn visit_mut_member_expr(&mut self, n: &mut MemberExpr) {
n.obj.visit_mut_with(self);
if n.computed {
n.prop.visit_mut_with(self);
}
}
fn visit_mut_module_items(&mut self, n: &mut Vec<ModuleItem>) {
n.visit_mut_children_with(self);
n.retain(|v| match v {
ModuleItem::Stmt(Stmt::Empty(..)) => false,
_ => true,
});
}
fn visit_mut_prop(&mut self, n: &mut Prop) {
match n {
Prop::Shorthand(i) => {
let orig = i.clone();
i.visit_mut_with(self);
if i.span.ctxt != orig.span.ctxt {
return;
}
if i.sym != orig.sym {
*n = Prop::KeyValue(KeyValueProp {
key: PropName::Ident(orig),
value: Box::new(Expr::Ident(i.clone())),
});
return;
}
}
_ => {
n.visit_mut_children_with(self);
}
}
}
fn visit_mut_prop_name(&mut self, n: &mut PropName) {
match n {
PropName::Ident(_) => {}
PropName::Str(_) => {}
PropName::Num(_) => {}
PropName::Computed(e) => {
e.expr.visit_mut_with(self);
}
PropName::BigInt(_) => {}
}
}
fn visit_mut_stmt(&mut self, n: &mut Stmt) {
n.visit_mut_children_with(self);
@ -113,50 +176,4 @@ impl VisitMut for Inliner {
n.visit_mut_children_with(self);
}
fn visit_mut_ident(&mut self, n: &mut Ident) {
if let Some(mapped) = self.data.ids.get(&n.clone().into()).cloned() {
*n = mapped.into();
}
}
fn visit_mut_prop(&mut self, n: &mut Prop) {
match n {
Prop::Shorthand(i) => {
let orig = i.clone();
i.visit_mut_with(self);
if i.span.ctxt != orig.span.ctxt {
return;
}
if i.sym != orig.sym {
*n = Prop::KeyValue(KeyValueProp {
key: PropName::Ident(orig),
value: Box::new(Expr::Ident(i.clone())),
});
return;
}
}
_ => {
n.visit_mut_children_with(self);
}
}
}
/// Don't modify exported ident.
fn visit_mut_export_named_specifier(&mut self, n: &mut ExportNamedSpecifier) {
if n.exported.is_none() {
n.exported = Some(n.orig.clone());
}
n.orig.visit_mut_with(self);
}
/// General logic for member expression.s
fn visit_mut_member_expr(&mut self, n: &mut MemberExpr) {
n.obj.visit_mut_with(self);
if n.computed {
n.prop.visit_mut_with(self);
}
}
}

View File

@ -183,8 +183,9 @@ fn toposort_real_module_ids<'a>(
// dbg!(&deps);
let all_modules_in_circle =
let mut all_modules_in_circle =
all_modules_in_circle(id, &done, &mut Default::default(), graph);
all_modules_in_circle.reverse();
if all_modules_in_circle.is_empty() {
queue.push_front(id);

View File

@ -325,34 +325,6 @@ fn iter<'a>(
continue 'main;
}
// Prefer inserting module as a whole.
let next = idx + 1;
if current_range.contains(&next) {
if moves.insert((idx, next)) {
if !done.contains(&next) {
stack.push_front(next);
}
}
}
// The logic below is not required because we inline all simple injected
// variables.
//
//
// {
// // We emit free dependants as early as possible.
// let free_dependants = graph
// .neighbors_directed(idx, Dependants)
// .filter(|&dependant| !done.contains(&dependant) &&
// free.contains(&dependant)) .collect::<Vec<_>>();
// if !free_dependants.is_empty() {
// for dependant in free_dependants {
// stack.push_front(dependant);
// }
// }
// }
graph.remove_node(idx);
done.insert(idx);
return Some(idx);

View File

@ -207,6 +207,7 @@ fn deno_jszip_03() {
}
#[test]
#[ignore = "Outdated"]
fn sort_006() {
assert_sorted(
&[
@ -225,6 +226,7 @@ fn sort_006() {
}
#[test]
#[ignore = "Outdated"]
fn sort_007() {
assert_sorted_with_free(
&[
@ -322,6 +324,7 @@ fn sort_010() {
}
#[test]
#[ignore = "Outdated"]
fn sort_011() {
assert_sorted(
&[
@ -409,6 +412,7 @@ fn sort_013() {
}
#[test]
#[ignore = "Outdated"]
fn sort_014() {
assert_sorted(
&[
@ -472,6 +476,34 @@ fn sort_015() {
);
}
#[test]
fn sort_016() {
assert_sorted(
&[
"
function f1() {
}
f2();
",
"
function f2() {
}
f1();
",
],
"
function f1() {
}
function f2() {
}
f2();
f1();
",
);
}
fn mark(item: &mut ModuleItem, ctxt: SyntaxContext) {
match item {
ModuleItem::ModuleDecl(item) => match item {

View File

@ -1,4 +1,4 @@
const c1 = 'c';
const a1 = 'a';
const c1 = 'c';
export { a1 as a };
export { c1 as c };

View File

@ -1,4 +1,4 @@
const c1 = 'c';
const a1 = 'a';
const c1 = 'c';
export { a1 as a };
export { c1 as c };

View File

@ -1,3 +1,3 @@
const c = 'c';
const a = 'a';
const c = 'c';
console.log(a, c);

View File

@ -1,3 +1,3 @@
const c = 'c';
const a = 'a';
const c = 'c';
console.log(a, c);

View File

@ -1,3 +1,3 @@
const b = 2;
const a = 1;
const b = 2;
console.log(a, b);

View File

@ -2,7 +2,7 @@ async function foo1() {
}
const mod = function() {
return {
mod: foo1
foo: foo1
};
}();
export { mod as foo };

View File

@ -2,7 +2,7 @@ async function foo1() {
}
const mod = function() {
return {
mod: foo1
foo: foo1
};
}();
export { mod as foo };

View File

@ -1,15 +1,12 @@
const __default = {
"hello": "world"
};
const __default1 = {
"a": "a",
"b": "b",
"c": "c"
};
const __default2 = {
const __default1 = {
"a": "a1",
"b": "b1",
"c": "c1"
};
console.log(__default);
console.log(__default1);
console.log(__default2);

View File

@ -1,15 +1,12 @@
const __default = {
"hello": "world"
};
const __default1 = {
"a": "a",
"b": "b",
"c": "c"
};
const __default2 = {
const __default1 = {
"a": "a1",
"b": "b1",
"c": "c1"
};
console.log(__default);
console.log(__default1);
console.log(__default2);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,3 @@
const showList = (v)=>{
return `[${v.map(showValue1).join(', ')}]`;
};
const showValue1 = (v)=>{
if (v === 0) {
return showList([
@ -9,6 +6,9 @@ const showValue1 = (v)=>{
}
return `${v}`;
};
const showList = (v)=>{
return `[${v.map(showValue1).join(', ')}]`;
};
console.log(showList([
1,
2,

View File

@ -1,6 +1,3 @@
const showList = (v)=>{
return `[${v.map(showValue1).join(', ')}]`;
};
const showValue1 = (v)=>{
if (v === 0) {
return showList([
@ -9,6 +6,9 @@ const showValue1 = (v)=>{
}
return `${v}`;
};
const showList = (v)=>{
return `[${v.map(showValue1).join(', ')}]`;
};
console.log(showList([
1,
2,

View File

@ -1,6 +1,3 @@
const showList = (v)=>{
return `[${v.map(showValue).join(', ')}]`;
};
const showValue = (v)=>{
if (v === 0) {
return showList([
@ -9,6 +6,9 @@ const showValue = (v)=>{
}
return `${v}`;
};
const showList = (v)=>{
return `[${v.map(showValue).join(', ')}]`;
};
console.log(showList([
1,
2,

View File

@ -1,6 +1,3 @@
const showList = (v)=>{
return `[${v.map(showValue).join(', ')}]`;
};
const showValue = (v)=>{
if (v === 0) {
return showList([
@ -9,6 +6,9 @@ const showValue = (v)=>{
}
return `${v}`;
};
const showList = (v)=>{
return `[${v.map(showValue).join(', ')}]`;
};
console.log(showList([
1,
2,

View File

@ -1,6 +1,6 @@
class A {
}
console.log(3, A);
console.log(2, A);
console.log(1, A);
console.log(3, A);
console.log(1);

View File

@ -1,9 +1,9 @@
class A {
}
const c = 3;
console.log(c, A);
const b = 2;
console.log(b, A);
const a = 1;
console.log(a, A);
const c = 3;
console.log(c, A);
console.log(a);

View File

@ -3,7 +3,7 @@ function Foo(name) {
}
const mod = function() {
return {
Foo
Foo: Foo
};
}();
const bar = Foo('bar');

View File

@ -3,7 +3,7 @@ function Foo(name) {
}
const mod = function() {
return {
Foo
Foo: Foo
};
}();
const bar = Foo('bar');

View File

@ -3,7 +3,7 @@ const bar = 123;
const mod = function() {
return {
foo: foo,
bar
bar: bar
};
}();
console.log(mod);

View File

@ -1,7 +1,7 @@
const a = "hello world";
const mod = function() {
return {
a: a
instanceof: a
};
}();
console.log(a, mod);

View File

@ -1,7 +1,7 @@
const a = "hello world";
const mod = function() {
return {
a: a
instanceof: a
};
}();
console.log(a, mod);

View File

@ -0,0 +1,3 @@
import { a } from './lib'
a()

View File

@ -0,0 +1,3 @@
export function a() { return 'a' }
export function b() { return 'b' }
export function c() { return b() }

View File

@ -0,0 +1,4 @@
function a() {
return 'a';
}
a();

View File

@ -0,0 +1,4 @@
function a() {
return 'a';
}
a();

View File

@ -0,0 +1,2 @@
export { foo } from './foo';
export { isWater } from "./things";

View File

@ -0,0 +1,5 @@
import * as things from './things';
export function foo(x) {
return things[x]
}

View File

@ -0,0 +1,4 @@
export const water = 'Water';
export function isWater(x) {
return x === water;
}

View File

@ -0,0 +1,15 @@
const water = 'Water';
function isWater1(x) {
return x === water;
}
const mod = function() {
return {
water: water,
isWater: isWater1
};
}();
function foo1(x) {
return mod[x];
}
export { foo1 as foo };
export { isWater1 as isWater };

View File

@ -0,0 +1,15 @@
const water = 'Water';
function isWater1(x) {
return x === water;
}
const mod = function() {
return {
water: water,
isWater: isWater1
};
}();
function foo1(x) {
return mod[x];
}
export { foo1 as foo };
export { isWater1 as isWater };

View File

@ -0,0 +1 @@
export * from 'https://deno.land/x/dnit@dnit-v1.11.0/main.ts'

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,23 +1,21 @@
function a() {
console.log("a");
}
var O2;
var O1;
(function(O1) {
O1[O1["A"] = 0] = "A";
O1[O1["B"] = 1] = "B";
O1[O1["C"] = 2] = "C";
})(O2 || (O2 = {
})(O1 || (O1 = {
}));
const a1 = a;
const O1 = O2;
export { O1 as O };
class A {
#a;
#c;
constructor(o = {
}){
const { a: a2 = a1 , c , } = o;
this.#a = a2;
const { a: a1 = a , c , } = o;
this.#a = a1;
this.#c = c;
}
a() {
@ -27,6 +25,6 @@ class A {
console.log(this.#c);
}
}
let a3 = new A();
a3.a();
a3.c();
let a2 = new A();
a2.a();
a2.c();

View File

@ -1,23 +1,21 @@
function a() {
console.log("a");
}
var O2;
var O1;
(function(O1) {
O1[O1["A"] = 0] = "A";
O1[O1["B"] = 1] = "B";
O1[O1["C"] = 2] = "C";
})(O2 || (O2 = {
})(O1 || (O1 = {
}));
const a1 = a;
const O1 = O2;
export { O1 as O };
class A {
#a;
#c;
constructor(o = {
}){
const { a: a2 = a1 , c , } = o;
this.#a = a2;
const { a: a1 = a , c , } = o;
this.#a = a1;
this.#c = c;
}
a() {
@ -27,6 +25,6 @@ class A {
console.log(this.#c);
}
}
let a3 = new A();
a3.a();
a3.c();
let a2 = new A();
a2.a();
a2.c();

View File

@ -6,7 +6,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_common"
repository = "https://github.com/swc-project/swc.git"
version = "0.10.11"
version = "0.10.12"
[features]
concurrent = ["parking_lot"]
@ -31,7 +31,7 @@ serde = {version = "1.0.119", features = ["derive"]}
sourcemap = {version = "6", optional = true}
string_cache = "0.8.1"
swc_eq_ignore_macros = {version = "0.1", path = "../macros/eq_ignore"}
swc_visit = {version = "0.2.3", path = "../visit"}
swc_visit = {version = "0.2.4", path = "../visit"}
termcolor = {version = "1.0", optional = true}
unicode-width = "0.1.4"

View File

@ -1,6 +1,9 @@
//! This module reexports items from `swc_visit` with some swc-specific traits.
use std::borrow::Cow;
pub use swc_visit::*;
/// A named compiler pass.
pub trait CompilerPass {
///
/// - name should follow hyphen-case.

View File

@ -6,7 +6,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_ecmascript"
repository = "https://github.com/swc-project/swc.git"
version = "0.24.0"
version = "0.24.1"
[package.metadata.docs.rs]
all-features = true
@ -31,7 +31,7 @@ swc_ecma_ast = {version = "0.40.0", path = "./ast"}
swc_ecma_codegen = {version = "0.47.0", path = "./codegen", optional = true}
swc_ecma_dep_graph = {version = "0.17.0", path = "./dep-graph", optional = true}
swc_ecma_parser = {version = "0.49.0", path = "./parser", optional = true}
swc_ecma_transforms = {version = "0.38.0", path = "./transforms", optional = true}
swc_ecma_transforms = {version = "0.38.1", path = "./transforms", optional = true}
swc_ecma_utils = {version = "0.30.0", path = "./utils", optional = true}
swc_ecma_visit = {version = "0.26.0", path = "./visit", optional = true}

View File

@ -5,7 +5,7 @@ documentation = "https://swc.rs/rustdoc/swc_ecma_preset_env/"
edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_ecma_preset_env"
version = "0.8.0"
version = "0.8.1"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -21,7 +21,7 @@ string_enum = {version = "0.3.1", path = "../../macros/string_enum"}
swc_atoms = {version = "0.2", path = "../../atoms"}
swc_common = {version = "0.10.10", path = "../../common"}
swc_ecma_ast = {version = "0.40.0", path = "../ast"}
swc_ecma_transforms = {version = "0.38.0", path = "../transforms", features = ["compat", "proposal"]}
swc_ecma_transforms = {version = "0.38.1", path = "../transforms", features = ["compat", "proposal"]}
swc_ecma_utils = {version = "0.30.0", path = "../utils"}
swc_ecma_visit = {version = "0.26.0", path = "../visit"}
walkdir = "2"

View File

@ -6,7 +6,10 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_ecma_transforms"
repository = "https://github.com/swc-project/swc.git"
version = "0.38.0"
version = "0.38.1"
[package.metadata.docs.rs]
all-features = true
[features]
compat = ["swc_ecma_transforms_compat"]
@ -24,7 +27,7 @@ swc_ecma_parser = {version = "0.49.0", path = "../parser"}
swc_ecma_transforms_base = {version = "0.6.0", path = "./base"}
swc_ecma_transforms_compat = {version = "0.7.0", path = "./compat", optional = true}
swc_ecma_transforms_module = {version = "0.7.0", path = "./module", optional = true}
swc_ecma_transforms_optimization = {version = "0.8.0", path = "./optimization", optional = true}
swc_ecma_transforms_optimization = {version = "0.8.1", path = "./optimization", optional = true}
swc_ecma_transforms_proposal = {version = "0.7.0", path = "./proposal", optional = true}
swc_ecma_transforms_react = {version = "0.8.0", path = "./react", optional = true}
swc_ecma_transforms_typescript = {version = "0.7.0", path = "./typescript", optional = true}

View File

@ -6,7 +6,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_ecma_transforms_optimization"
repository = "https://github.com/swc-project/swc.git"
version = "0.8.0"
version = "0.8.1"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
@ -32,3 +32,4 @@ swc_ecma_transforms_proposal = {version = "0.7.0", path = "../proposal"}
swc_ecma_transforms_react = {version = "0.8.0", path = "../react"}
swc_ecma_transforms_testing = {version = "0.6.0", path = "../testing"}
swc_ecma_transforms_typescript = {version = "0.7.0", path = "../typescript"}
testing = {version = "0.10.0", path = "../../../testing"}

View File

@ -889,6 +889,7 @@ impl Dce<'_> {
if self.is_marked(item.span()) {
Some(item)
} else {
self.dropped = true;
None
}
});

View File

@ -0,0 +1,3 @@
function a() { return 'a' }
function b() { return 'b' }
export function c() { return b() }

View File

@ -0,0 +1,6 @@
function b() {
return "b";
}
export function c() {
return b();
}

View File

@ -0,0 +1,2 @@
function b() { return 'b' }
export function c() { return b() }

View File

@ -0,0 +1,7 @@
function a() {
return 'a';
}
function b() {
return 'b';
}
a();

View File

@ -0,0 +1,4 @@
function a() {
return "a";
}
a();

View File

@ -0,0 +1,4 @@
function a() {
return "a";
}
a();

View File

@ -0,0 +1,10 @@
function a() {
return 'a';
}
function b() {
return 'b';
}
function c() {
return b();
}
a();

View File

@ -0,0 +1,4 @@
function a() {
return "a";
}
a();

View File

@ -0,0 +1,7 @@
function a() {
return "a";
}
function b() {
return "b";
}
a();

View File

@ -0,0 +1,36 @@
use std::path::PathBuf;
use swc_common::pass::Repeat;
use swc_ecma_parser::EsConfig;
use swc_ecma_parser::Syntax;
use swc_ecma_transforms_optimization::simplify::dce::dce;
use swc_ecma_transforms_testing::test_fixture;
#[testing::fixture("dce/**/input.js")]
fn dce_single_pass(input: PathBuf) {
let output = input.with_file_name("output.js");
test_fixture(
Syntax::Es(EsConfig {
dynamic_import: true,
..Default::default()
}),
&|_| dce(Default::default()),
&input,
&output,
);
}
#[testing::fixture("dce/**/input.js")]
fn dce_repeated(input: PathBuf) {
let output = input.with_file_name("output.full.js");
test_fixture(
Syntax::Es(EsConfig {
dynamic_import: true,
..Default::default()
}),
&|_| Repeat::new(dce(Default::default())),
&input,
&output,
);
}

View File

@ -27,6 +27,7 @@ use syn::Path;
use syn::Stmt;
use syn::Token;
/// Derives `swc_common::TypeEq`.
///
/// - Field annotated with `#[use_eq]` will be compared using `==`.
/// - Field annotated with `#[not_type]` will be ignored
@ -49,7 +50,10 @@ pub fn derive_type_eq(item: proc_macro::TokenStream) -> proc_macro::TokenStream
.derive(item)
}
/// Fields annotated with `#[not_panned]` or `#[use_eq]` will use` ==` instead
/// Derives `swc_common::EqIgnoreSpan`.
///
///
/// Fields annotated with `#[not_spanned]` or `#[use_eq]` will use` ==` instead
/// of `eq_ignore_span`.
#[proc_macro_derive(EqIgnoreSpan, attributes(not_spanned, use_eq))]
pub fn derive_eq_ignore_span(item: proc_macro::TokenStream) -> proc_macro::TokenStream {

View File

@ -1,11 +1,11 @@
function getC() {
return C;
}
class C {
}
function a() {
return new A();
}
function getC() {
return C;
}
class A extends getC() {
}
class C {
}
console.log(a, a());

View File

@ -1,4 +1,4 @@
console.log('b');
console.log('c');
console.log('a');
console.log('c');
console.log('b');
console.log('entry');

View File

@ -1,27 +1,3 @@
const encoder = new TextEncoder();
function encode(input) {
return encoder.encode(input);
}
const decoder = new TextDecoder();
function decode(input) {
return decoder.decode(input);
}
function findIndex(source, pat) {
const s = pat[0];
for(let i = 0; i < source.length; i++){
if (source[i] !== s) continue;
const pin = i;
let matched = 1;
let j = i;
while(matched < pat.length){
j++;
if (source[j] !== pat[j - pin]) break;
matched++;
}
if (matched === pat.length) return pin;
}
return -1;
}
function concat(origin, b) {
const output = new Uint8Array(origin.length + b.length);
output.set(origin, 0);
@ -492,125 +468,13 @@ class BufWriterSync extends AbstractBufBase {
this.buf = new Uint8Array(size3);
}
}
/** Generate longest proper prefix which is also suffix array. */ function createLPS(pat) {
const lps = new Uint8Array(pat.length);
lps[0] = 0;
let prefixEnd = 0;
let i = 1;
while(i < lps.length)if (pat[i] == pat[prefixEnd]) {
prefixEnd++;
lps[i] = prefixEnd;
i++;
} else if (prefixEnd === 0) {
lps[i] = 0;
i++;
} else prefixEnd = pat[prefixEnd - 1];
return lps;
const encoder = new TextEncoder();
function encode(input) {
return encoder.encode(input);
}
async function* readDelim(reader, delim) {
// Avoid unicode problems
const delimLen = delim.length;
const delimLPS = createLPS(delim);
let inputBuffer = new Deno.Buffer();
const inspectArr = new Uint8Array(Math.max(1024, delimLen + 1));
// Modified KMP
let inspectIndex = 0;
let matchIndex = 0;
while(true){
const result = await reader.read(inspectArr);
if (result === null) {
// Yield last chunk.
yield inputBuffer.bytes();
return;
}
if (result < 0) // Discard all remaining and silently fail.
return;
const sliceRead = inspectArr.subarray(0, result);
await Deno.writeAll(inputBuffer, sliceRead);
let sliceToProcess = inputBuffer.bytes();
while(inspectIndex < sliceToProcess.length)if (sliceToProcess[inspectIndex] === delim[matchIndex]) {
inspectIndex++;
matchIndex++;
if (matchIndex === delimLen) {
// Full match
const matchEnd = inspectIndex - delimLen;
const readyBytes = sliceToProcess.subarray(0, matchEnd);
// Copy
const pendingBytes = sliceToProcess.slice(inspectIndex);
yield readyBytes;
// Reset match, different from KMP.
sliceToProcess = pendingBytes;
inspectIndex = 0;
matchIndex = 0;
}
} else if (matchIndex === 0) inspectIndex++;
else matchIndex = delimLPS[matchIndex - 1];
// Keep inspectIndex and matchIndex.
inputBuffer = new Deno.Buffer(sliceToProcess);
}
}
async function* readStringDelim(reader, delim) {
const encoder1 = new TextEncoder();
const decoder1 = new TextDecoder();
for await (const chunk of readDelim(reader, encoder1.encode(delim)))yield decoder1.decode(chunk);
}
function deferred() {
let methods;
const promise = new Promise((resolve, reject)=>{
methods = {
resolve,
reject
};
});
return Object.assign(promise, methods);
}
var tmp = Symbol.asyncIterator;
class MuxAsyncIterator {
add(iterator) {
++this.iteratorCount;
this.callIteratorNext(iterator);
}
async callIteratorNext(iterator) {
try {
const { value , done } = await iterator.next();
if (done) --this.iteratorCount;
else this.yields.push({
iterator,
value
});
} catch (e) {
this.throws.push(e);
}
this.signal.resolve();
}
async *iterate() {
while(this.iteratorCount > 0){
// Sleep until any of the wrapped iterators yields.
await this.signal;
// Note that while we're looping over `yields`, new items may be added.
for(let i = 0; i < this.yields.length; i++){
const { iterator , value } = this.yields[i];
yield value;
this.callIteratorNext(iterator);
}
if (this.throws.length) {
for (const e of this.throws)throw e;
this.throws.length = 0;
}
// Clear the `yields` list and reset the `signal` promise.
this.yields.length = 0;
this.signal = deferred();
}
}
[tmp]() {
return this.iterate();
}
constructor(){
this.iteratorCount = 0;
this.yields = [];
this.throws = [];
this.signal = deferred();
}
const decoder = new TextDecoder();
function decode(input) {
return decoder.decode(input);
}
// FROM https://github.com/denoland/deno/blob/b34628a26ab0187a827aa4ebe256e23178e25d39/cli/js/web/headers.ts#L9
const invalidHeaderCharRegex = /[^\t\x20-\x7e\x80-\xff]/g;
@ -719,6 +583,64 @@ class TextProtoReader {
}
}
const STATUS_TEXT = new Map([]);
function deferred() {
let methods;
const promise = new Promise((resolve, reject)=>{
methods = {
resolve,
reject
};
});
return Object.assign(promise, methods);
}
var tmp = Symbol.asyncIterator;
class MuxAsyncIterator {
add(iterator) {
++this.iteratorCount;
this.callIteratorNext(iterator);
}
async callIteratorNext(iterator) {
try {
const { value , done } = await iterator.next();
if (done) --this.iteratorCount;
else this.yields.push({
iterator,
value
});
} catch (e) {
this.throws.push(e);
}
this.signal.resolve();
}
async *iterate() {
while(this.iteratorCount > 0){
// Sleep until any of the wrapped iterators yields.
await this.signal;
// Note that while we're looping over `yields`, new items may be added.
for(let i = 0; i < this.yields.length; i++){
const { iterator , value } = this.yields[i];
yield value;
this.callIteratorNext(iterator);
}
if (this.throws.length) {
for (const e of this.throws)throw e;
this.throws.length = 0;
}
// Clear the `yields` list and reset the `signal` promise.
this.yields.length = 0;
this.signal = deferred();
}
}
[tmp]() {
return this.iterate();
}
constructor(){
this.iteratorCount = 0;
this.yields = [];
this.throws = [];
this.signal = deferred();
}
}
function emptyReader() {
return {
read (_) {
@ -916,38 +838,6 @@ async function writeResponse(w, r1) {
}
await writer.flush();
}
function parseHTTPVersion(vers) {
switch(vers){
case "HTTP/1.1":
return [
1,
1
];
case "HTTP/1.0":
return [
1,
0
];
default:
{
const Big = 1000000; // arbitrary upper bound
if (!vers.startsWith("HTTP/")) break;
const dot = vers.indexOf(".");
if (dot < 0) break;
const majorStr = vers.substring(vers.indexOf("/") + 1, dot);
const major = Number(majorStr);
if (!Number.isInteger(major) || major < 0 || major > Big) break;
const minorStr = vers.substring(dot + 1);
const minor = Number(minorStr);
if (!Number.isInteger(minor) || minor < 0 || minor > Big) break;
return [
major,
minor
];
}
}
throw new Error(`malformed HTTP version ${vers}`);
}
class ServerRequest {
/**
* Value of Content-Length header.
@ -1020,6 +910,38 @@ class ServerRequest {
}
}
var tmp1 = Symbol.asyncIterator;
function parseHTTPVersion(vers) {
switch(vers){
case "HTTP/1.1":
return [
1,
1
];
case "HTTP/1.0":
return [
1,
0
];
default:
{
const Big = 1000000; // arbitrary upper bound
if (!vers.startsWith("HTTP/")) break;
const dot = vers.indexOf(".");
if (dot < 0) break;
const majorStr = vers.substring(vers.indexOf("/") + 1, dot);
const major = Number(majorStr);
if (!Number.isInteger(major) || major < 0 || major > Big) break;
const minorStr = vers.substring(dot + 1);
const minor = Number(minorStr);
if (!Number.isInteger(minor) || minor < 0 || minor > Big) break;
return [
major,
minor
];
}
}
throw new Error(`malformed HTTP version ${vers}`);
}
async function readRequest(conn, bufr) {
const tp = new TextProtoReader(bufr);
const firstLine = await tp.readLine(); // e.g. GET /index.html HTTP/1.0
@ -1035,26 +957,6 @@ async function readRequest(conn, bufr) {
fixLength(req);
return req;
}
function fixLength(req) {
const contentLength = req.headers.get("Content-Length");
if (contentLength) {
const arrClen = contentLength.split(",");
if (arrClen.length > 1) {
const distinct = [
...new Set(arrClen.map((e)=>e.trim()
))
];
if (distinct.length > 1) throw Error("cannot contain multiple Content-Length headers");
else req.headers.set("Content-Length", distinct[0]);
}
const c = req.headers.get("Content-Length");
if (req.method === "HEAD" && c && c !== "0") throw Error("http: method cannot contain a Content-Length");
if (c && req.headers.has("transfer-encoding")) // A sender MUST NOT send a Content-Length header field in any message
// that contains a Transfer-Encoding header field.
// rfc: https://tools.ietf.org/html/rfc7230#section-3.3.2
throw new Error("http: Transfer-Encoding and Content-Length cannot be send together");
}
}
class Server {
close() {
this.closing = true;
@ -1165,13 +1067,25 @@ async function listenAndServe(addr, handler) {
const server = serve(addr);
for await (const request of server)handler(request);
}
function serveTLS(options) {
const tlsOptions = {
...options,
transport: "tcp"
};
const listener1 = Deno.listenTls(tlsOptions);
return new Server(listener1);
function fixLength(req) {
const contentLength = req.headers.get("Content-Length");
if (contentLength) {
const arrClen = contentLength.split(",");
if (arrClen.length > 1) {
const distinct = [
...new Set(arrClen.map((e)=>e.trim()
))
];
if (distinct.length > 1) throw Error("cannot contain multiple Content-Length headers");
else req.headers.set("Content-Length", distinct[0]);
}
const c = req.headers.get("Content-Length");
if (req.method === "HEAD" && c && c !== "0") throw Error("http: method cannot contain a Content-Length");
if (c && req.headers.has("transfer-encoding")) // A sender MUST NOT send a Content-Length header field in any message
// that contains a Transfer-Encoding header field.
// rfc: https://tools.ietf.org/html/rfc7230#section-3.3.2
throw new Error("http: Transfer-Encoding and Content-Length cannot be send together");
}
}
listenAndServe({
port: 8080

View File

@ -253,38 +253,6 @@ async function writeResponse(w, r) {
}
await writer.flush();
}
function parseHTTPVersion(vers) {
switch(vers){
case "HTTP/1.1":
return [
1,
1
];
case "HTTP/1.0":
return [
1,
0
];
default:
{
const Big = 1000000; // arbitrary upper bound
if (!vers.startsWith("HTTP/")) break;
const dot = vers.indexOf(".");
if (dot < 0) break;
const majorStr = vers.substring(vers.indexOf("/") + 1, dot);
const major = Number(majorStr);
if (!Number.isInteger(major) || major < 0 || major > Big) break;
const minorStr = vers.substring(dot + 1);
const minor = Number(minorStr);
if (!Number.isInteger(minor) || minor < 0 || minor > Big) break;
return [
major,
minor
];
}
}
throw new Error(`malformed HTTP version ${vers}`);
}
class ServerRequest {
/**
* Value of Content-Length header.
@ -357,6 +325,38 @@ class ServerRequest {
}
}
var tmp1 = Symbol.asyncIterator;
function parseHTTPVersion(vers) {
switch(vers){
case "HTTP/1.1":
return [
1,
1
];
case "HTTP/1.0":
return [
1,
0
];
default:
{
const Big = 1000000; // arbitrary upper bound
if (!vers.startsWith("HTTP/")) break;
const dot = vers.indexOf(".");
if (dot < 0) break;
const majorStr = vers.substring(vers.indexOf("/") + 1, dot);
const major = Number(majorStr);
if (!Number.isInteger(major) || major < 0 || major > Big) break;
const minorStr = vers.substring(dot + 1);
const minor = Number(minorStr);
if (!Number.isInteger(minor) || minor < 0 || minor > Big) break;
return [
major,
minor
];
}
}
throw new Error(`malformed HTTP version ${vers}`);
}
async function readRequest(conn, bufr) {
const tp = new TextProtoReader(bufr);
const firstLine = await tp.readLine(); // e.g. GET /index.html HTTP/1.0
@ -372,26 +372,6 @@ async function readRequest(conn, bufr) {
fixLength(req);
return req;
}
function fixLength(req) {
const contentLength = req.headers.get("Content-Length");
if (contentLength) {
const arrClen = contentLength.split(",");
if (arrClen.length > 1) {
const distinct = [
...new Set(arrClen.map((e)=>e.trim()
))
];
if (distinct.length > 1) throw Error("cannot contain multiple Content-Length headers");
else req.headers.set("Content-Length", distinct[0]);
}
const c = req.headers.get("Content-Length");
if (req.method === "HEAD" && c && c !== "0") throw Error("http: method cannot contain a Content-Length");
if (c && req.headers.has("transfer-encoding")) // A sender MUST NOT send a Content-Length header field in any message
// that contains a Transfer-Encoding header field.
// rfc: https://tools.ietf.org/html/rfc7230#section-3.3.2
throw new Error("http: Transfer-Encoding and Content-Length cannot be send together");
}
}
class Server {
close() {
this.closing = true;
@ -502,13 +482,25 @@ async function listenAndServe(addr, handler) {
const server = serve(addr);
for await (const request of server)handler(request);
}
function serveTLS(options) {
const tlsOptions = {
...options,
transport: "tcp"
};
const listener1 = Deno.listenTls(tlsOptions);
return new Server(listener1);
function fixLength(req) {
const contentLength = req.headers.get("Content-Length");
if (contentLength) {
const arrClen = contentLength.split(",");
if (arrClen.length > 1) {
const distinct = [
...new Set(arrClen.map((e)=>e.trim()
))
];
if (distinct.length > 1) throw Error("cannot contain multiple Content-Length headers");
else req.headers.set("Content-Length", distinct[0]);
}
const c = req.headers.get("Content-Length");
if (req.method === "HEAD" && c && c !== "0") throw Error("http: method cannot contain a Content-Length");
if (c && req.headers.has("transfer-encoding")) // A sender MUST NOT send a Content-Length header field in any message
// that contains a Transfer-Encoding header field.
// rfc: https://tools.ietf.org/html/rfc7230#section-3.3.2
throw new Error("http: Transfer-Encoding and Content-Length cannot be send together");
}
}
listenAndServe({
port: 8080

View File

@ -6,7 +6,7 @@ const arr = [
];
const mod = function() {
return {
arr
arr: arr
};
}();
console.log(mod[foo()]);

View File

@ -2,7 +2,7 @@ class A {
}
const mod = function() {
return {
A
A: A
};
}();
export { mod as a };

View File

@ -2,7 +2,7 @@ class A {
}
const mod = function() {
return {
A
A: A
};
}();
console.log(mod);

View File

@ -1,9 +1,9 @@
function f2() {
console.log("f2");
}
function f11() {
console.log("f1");
}
function f2() {
console.log("f2");
}
f2();
f11();
export { f11 as f1 };

View File

@ -1,8 +1,8 @@
function f2() {
console.log("f2");
}
function f1() {
console.log("f1");
}
function f2() {
console.log("f2");
}
f2();
f1();

View File

@ -1,7 +1,7 @@
const a = "a";
const mod = function() {
return {
a
a: a
};
}();
console.log(mod); // { a: "a" }

View File

@ -3,7 +3,7 @@ class C {
}
const mod = function() {
return {
mod: c,
c: c,
default: C
};
}();

View File

@ -1,6 +1,5 @@
const b = 1;
console.log('b');
const a1 = b;
console.log('a.js');
export { a1 as a };
export { b as a };
console.log('entry');

View File

@ -1,5 +1,4 @@
const b = 1;
console.log('b', b);
const a1 = b;
console.log('a');
export { a1 as a };
export { b as a };

View File

@ -1,5 +1,4 @@
const b = 1;
console.log('b', b);
const b1 = b;
console.log('a');
export { b1 as a };
export { b as a };

View File

@ -1,8 +1,6 @@
const c = 1;
console.log('c', c);
const b = c;
console.log('b');
const b1 = b;
console.log('a');
export { b1 as a };
export { c as a };
console.log('entry');

View File

@ -1,8 +1,6 @@
const c = 1;
console.log('c', c);
const b = c;
console.log('b');
const a1 = b;
console.log('a');
export { a1 as a };
export { c as a };
console.log('entry');

View File

@ -2,6 +2,5 @@ function b() {
console.log(b);
}
console.log('b', b);
const b1 = b;
console.log('a');
export { b1 as a };
export { b as a };

View File

@ -1,6 +1,5 @@
class b {
}
console.log('b', b);
const b1 = b;
console.log('a');
export { b1 as a };
export { b as a };

View File

@ -1,7 +1,5 @@
const d = 1;
const d1 = d;
console.log('d');
const b1 = d1;
console.log('a.js');
export { b1 as b };
export { d as b };
console.log('entry');

View File

@ -1,7 +1,6 @@
const c = 'c';
console.log('c');
console.log('b');
const b1 = c;
console.log('a.js');
export { b1 as b };
export { c as b };
console.log('entry');

View File

@ -1,9 +1,7 @@
const d = 1;
const d1 = d;
console.log('d');
console.log('c');
console.log('b');
const b1 = d1;
console.log('a.js');
export { b1 as b };
export { d as b };
console.log('entry');

View File

@ -1,10 +1,8 @@
const e = 'e';
console.log('e');
const d = e;
console.log('d');
console.log('c');
console.log('b');
const b1 = d;
console.log('a.js');
export { b1 as b };
export { e as b };
console.log('entry');

View File

@ -1,8 +1,5 @@
const foo3 = 1;
const bar3 = 1;
const baz3 = 1;
const foo1 = foo3, bar1 = bar3, baz1 = baz3;
const foo2 = foo1, bar2 = bar1;
const baz2 = baz1;
export { foo2 as foo, bar2 as bar };
export { baz2 as baz };
const foo1 = 1;
const bar1 = 1;
const baz1 = 1;
export { foo1 as foo, bar1 as bar };
export { baz1 as baz };

View File

@ -5,7 +5,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_visit"
repository = "https://github.com/swc-project/swc.git"
version = "0.2.3"
version = "0.2.4"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -10,6 +10,7 @@ pub struct All<V> {
pub visitor: V,
}
/// A visitor which visits node only if `enabled` is true.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Optional<V> {
pub enabled: bool,
@ -22,6 +23,9 @@ impl<V> Optional<V> {
}
}
/// Trait for a pass which is designed to invoked multiple time to same input.
///
/// See [Repeat].
pub trait Repeated {
/// Should run again?
fn changed(&self) -> bool;
@ -30,12 +34,14 @@ pub trait Repeated {
fn reset(&mut self);
}
/// A visitor which applies `A` and then `B`.
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct AndThen<A, B> {
pub first: A,
pub second: B,
}
/// Chains multiple visitor.
#[macro_export]
macro_rules! chain {
($a:expr, $b:expr) => {{
@ -61,6 +67,13 @@ macro_rules! chain {
}};
}
/// A visitor which applies `V` again and again if `V` modifies the node.
///
/// # Note
/// `V` should return `true` from `changed()` to make the pass run multiple
/// time.
///
/// See: [Repeated]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct Repeat<V>
where

View File

@ -1,8 +1,12 @@
use std::{mem, ptr};
/// Copied from `syntax::ptr::P`
/// Copied from `syntax::ptr::P` of rustc.
pub trait Map<T> {
/// Transform the inner value, consuming `self` and producing a new `P<T>`.
///
/// # Memory leak
///
/// This will leak `self` if the given closure panics.
fn map<F>(self, f: F) -> Self
where
F: FnOnce(T) -> T;

View File

@ -1,2 +1,3 @@
//! Some utilities for generated visitors.
pub mod map;
pub mod move_map;

View File

@ -1,5 +1,6 @@
use std::{iter, ptr};
/// Modifiers vector in-place.
pub trait MoveMap<T>: Sized {
/// Map in place.
fn move_map<F>(self, mut f: F) -> Self