mirror of
https://github.com/swc-project/swc.git
synced 2024-09-11 16:55:27 +03:00
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:
parent
05a90715d1
commit
c047e0e54d
@ -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",
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
@ -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());
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
})
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -1,4 +1,4 @@
|
||||
const c1 = 'c';
|
||||
const a1 = 'a';
|
||||
const c1 = 'c';
|
||||
export { a1 as a };
|
||||
export { c1 as c };
|
||||
|
@ -1,4 +1,4 @@
|
||||
const c1 = 'c';
|
||||
const a1 = 'a';
|
||||
const c1 = 'c';
|
||||
export { a1 as a };
|
||||
export { c1 as c };
|
||||
|
@ -1,3 +1,3 @@
|
||||
const c = 'c';
|
||||
const a = 'a';
|
||||
const c = 'c';
|
||||
console.log(a, c);
|
||||
|
@ -1,3 +1,3 @@
|
||||
const c = 'c';
|
||||
const a = 'a';
|
||||
const c = 'c';
|
||||
console.log(a, c);
|
||||
|
@ -1,3 +1,3 @@
|
||||
const b = 2;
|
||||
const a = 1;
|
||||
const b = 2;
|
||||
console.log(a, b);
|
||||
|
@ -2,7 +2,7 @@ async function foo1() {
|
||||
}
|
||||
const mod = function() {
|
||||
return {
|
||||
mod: foo1
|
||||
foo: foo1
|
||||
};
|
||||
}();
|
||||
export { mod as foo };
|
||||
|
@ -2,7 +2,7 @@ async function foo1() {
|
||||
}
|
||||
const mod = function() {
|
||||
return {
|
||||
mod: foo1
|
||||
foo: foo1
|
||||
};
|
||||
}();
|
||||
export { mod as foo };
|
||||
|
@ -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);
|
||||
|
@ -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
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -3,7 +3,7 @@ function Foo(name) {
|
||||
}
|
||||
const mod = function() {
|
||||
return {
|
||||
Foo
|
||||
Foo: Foo
|
||||
};
|
||||
}();
|
||||
const bar = Foo('bar');
|
||||
|
@ -3,7 +3,7 @@ function Foo(name) {
|
||||
}
|
||||
const mod = function() {
|
||||
return {
|
||||
Foo
|
||||
Foo: Foo
|
||||
};
|
||||
}();
|
||||
const bar = Foo('bar');
|
||||
|
@ -3,7 +3,7 @@ const bar = 123;
|
||||
const mod = function() {
|
||||
return {
|
||||
foo: foo,
|
||||
bar
|
||||
bar: bar
|
||||
};
|
||||
}();
|
||||
console.log(mod);
|
||||
|
@ -1,7 +1,7 @@
|
||||
const a = "hello world";
|
||||
const mod = function() {
|
||||
return {
|
||||
a: a
|
||||
instanceof: a
|
||||
};
|
||||
}();
|
||||
console.log(a, mod);
|
||||
|
@ -1,7 +1,7 @@
|
||||
const a = "hello world";
|
||||
const mod = function() {
|
||||
return {
|
||||
a: a
|
||||
instanceof: a
|
||||
};
|
||||
}();
|
||||
console.log(a, mod);
|
||||
|
3
bundler/tests/fixture/deno-9546/case1/input/entry.ts
Normal file
3
bundler/tests/fixture/deno-9546/case1/input/entry.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { a } from './lib'
|
||||
|
||||
a()
|
3
bundler/tests/fixture/deno-9546/case1/input/lib.ts
Normal file
3
bundler/tests/fixture/deno-9546/case1/input/lib.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export function a() { return 'a' }
|
||||
export function b() { return 'b' }
|
||||
export function c() { return b() }
|
@ -0,0 +1,4 @@
|
||||
function a() {
|
||||
return 'a';
|
||||
}
|
||||
a();
|
4
bundler/tests/fixture/deno-9546/case1/output/entry.ts
Normal file
4
bundler/tests/fixture/deno-9546/case1/output/entry.ts
Normal file
@ -0,0 +1,4 @@
|
||||
function a() {
|
||||
return 'a';
|
||||
}
|
||||
a();
|
2
bundler/tests/fixture/deno-9560/case1/input/entry.ts
Normal file
2
bundler/tests/fixture/deno-9560/case1/input/entry.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export { foo } from './foo';
|
||||
export { isWater } from "./things";
|
5
bundler/tests/fixture/deno-9560/case1/input/foo.ts
Normal file
5
bundler/tests/fixture/deno-9560/case1/input/foo.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import * as things from './things';
|
||||
|
||||
export function foo(x) {
|
||||
return things[x]
|
||||
}
|
4
bundler/tests/fixture/deno-9560/case1/input/things.ts
Normal file
4
bundler/tests/fixture/deno-9560/case1/input/things.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export const water = 'Water';
|
||||
export function isWater(x) {
|
||||
return x === water;
|
||||
}
|
@ -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 };
|
15
bundler/tests/fixture/deno-9560/case1/output/entry.ts
Normal file
15
bundler/tests/fixture/deno-9560/case1/output/entry.ts
Normal 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 };
|
1
bundler/tests/fixture/deno-9591/input/entry.ts
Normal file
1
bundler/tests/fixture/deno-9591/input/entry.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from 'https://deno.land/x/dnit@dnit-v1.11.0/main.ts'
|
6510
bundler/tests/fixture/deno-9591/output/entry.inlined.ts
Normal file
6510
bundler/tests/fixture/deno-9591/output/entry.inlined.ts
Normal file
File diff suppressed because one or more lines are too long
6522
bundler/tests/fixture/deno-9591/output/entry.ts
Normal file
6522
bundler/tests/fixture/deno-9591/output/entry.ts
Normal file
File diff suppressed because one or more lines are too long
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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}
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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}
|
||||
|
@ -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"}
|
||||
|
@ -889,6 +889,7 @@ impl Dce<'_> {
|
||||
if self.is_marked(item.span()) {
|
||||
Some(item)
|
||||
} else {
|
||||
self.dropped = true;
|
||||
None
|
||||
}
|
||||
});
|
||||
|
@ -0,0 +1,3 @@
|
||||
function a() { return 'a' }
|
||||
function b() { return 'b' }
|
||||
export function c() { return b() }
|
@ -0,0 +1,6 @@
|
||||
function b() {
|
||||
return "b";
|
||||
}
|
||||
export function c() {
|
||||
return b();
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
function b() { return 'b' }
|
||||
export function c() { return b() }
|
@ -0,0 +1,7 @@
|
||||
function a() {
|
||||
return 'a';
|
||||
}
|
||||
function b() {
|
||||
return 'b';
|
||||
}
|
||||
a();
|
@ -0,0 +1,4 @@
|
||||
function a() {
|
||||
return "a";
|
||||
}
|
||||
a();
|
@ -0,0 +1,4 @@
|
||||
function a() {
|
||||
return "a";
|
||||
}
|
||||
a();
|
@ -0,0 +1,10 @@
|
||||
function a() {
|
||||
return 'a';
|
||||
}
|
||||
function b() {
|
||||
return 'b';
|
||||
}
|
||||
function c() {
|
||||
return b();
|
||||
}
|
||||
a();
|
@ -0,0 +1,4 @@
|
||||
function a() {
|
||||
return "a";
|
||||
}
|
||||
a();
|
@ -0,0 +1,7 @@
|
||||
function a() {
|
||||
return "a";
|
||||
}
|
||||
function b() {
|
||||
return "b";
|
||||
}
|
||||
a();
|
36
ecmascript/transforms/optimization/tests/fixture.rs
Normal file
36
ecmascript/transforms/optimization/tests/fixture.rs
Normal 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,
|
||||
);
|
||||
}
|
@ -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 {
|
||||
|
@ -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());
|
||||
|
@ -1,4 +1,4 @@
|
||||
console.log('b');
|
||||
console.log('c');
|
||||
console.log('a');
|
||||
console.log('c');
|
||||
console.log('b');
|
||||
console.log('entry');
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -6,7 +6,7 @@ const arr = [
|
||||
];
|
||||
const mod = function() {
|
||||
return {
|
||||
arr
|
||||
arr: arr
|
||||
};
|
||||
}();
|
||||
console.log(mod[foo()]);
|
||||
|
@ -2,7 +2,7 @@ class A {
|
||||
}
|
||||
const mod = function() {
|
||||
return {
|
||||
A
|
||||
A: A
|
||||
};
|
||||
}();
|
||||
export { mod as a };
|
||||
|
@ -2,7 +2,7 @@ class A {
|
||||
}
|
||||
const mod = function() {
|
||||
return {
|
||||
A
|
||||
A: A
|
||||
};
|
||||
}();
|
||||
console.log(mod);
|
||||
|
@ -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 };
|
||||
|
@ -1,8 +1,8 @@
|
||||
function f2() {
|
||||
console.log("f2");
|
||||
}
|
||||
function f1() {
|
||||
console.log("f1");
|
||||
}
|
||||
function f2() {
|
||||
console.log("f2");
|
||||
}
|
||||
f2();
|
||||
f1();
|
||||
|
@ -1,7 +1,7 @@
|
||||
const a = "a";
|
||||
const mod = function() {
|
||||
return {
|
||||
a
|
||||
a: a
|
||||
};
|
||||
}();
|
||||
console.log(mod); // { a: "a" }
|
||||
|
@ -3,7 +3,7 @@ class C {
|
||||
}
|
||||
const mod = function() {
|
||||
return {
|
||||
mod: c,
|
||||
c: c,
|
||||
default: C
|
||||
};
|
||||
}();
|
||||
|
@ -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');
|
||||
|
@ -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 };
|
||||
|
@ -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 };
|
||||
|
@ -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');
|
||||
|
@ -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');
|
||||
|
@ -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 };
|
||||
|
@ -1,6 +1,5 @@
|
||||
class b {
|
||||
}
|
||||
console.log('b', b);
|
||||
const b1 = b;
|
||||
console.log('a');
|
||||
export { b1 as a };
|
||||
export { b as a };
|
||||
|
@ -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');
|
||||
|
@ -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');
|
||||
|
@ -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');
|
||||
|
@ -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');
|
||||
|
@ -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 };
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -1,2 +1,3 @@
|
||||
//! Some utilities for generated visitors.
|
||||
pub mod map;
|
||||
pub mod move_map;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user