mirror of
https://github.com/swc-project/swc.git
synced 2024-12-24 14:16:12 +03:00
Fix bugs (#221)
swc_ecmascript_parser: - fix parsing of `export default from 'src';` swc_ecmascript: - add a pass which allows injecting helpers before the module pass
This commit is contained in:
parent
2a094e42db
commit
1a1889f437
@ -1062,6 +1062,42 @@ export default App"#;
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn export_default_3() {
|
||||
let src = "export default from 'bar';";
|
||||
test_parser(
|
||||
src,
|
||||
Syntax::Es(EsConfig {
|
||||
export_default_from: true,
|
||||
..Default::default()
|
||||
}),
|
||||
|p| {
|
||||
p.parse_module().map_err(|mut e| {
|
||||
e.emit();
|
||||
()
|
||||
})
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn export_default_4() {
|
||||
let src = "export default, {foo} from 'bar';";
|
||||
test_parser(
|
||||
src,
|
||||
Syntax::Es(EsConfig {
|
||||
export_default_from: true,
|
||||
..Default::default()
|
||||
}),
|
||||
|p| {
|
||||
p.parse_module().map_err(|mut e| {
|
||||
e.emit();
|
||||
()
|
||||
})
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shebang_01() {
|
||||
let src = "#!/usr/bin/env node";
|
||||
|
@ -200,6 +200,9 @@ impl<'a, I: Input> Parser<'a, I> {
|
||||
}));
|
||||
}
|
||||
|
||||
// Some("default") if default is exported from 'src'
|
||||
let mut export_default = None;
|
||||
|
||||
if eat!("default") {
|
||||
if self.input.syntax().typescript() {
|
||||
if is!("abstract") && peeked_is!("class") {
|
||||
@ -221,22 +224,27 @@ impl<'a, I: Input> Parser<'a, I> {
|
||||
}
|
||||
}
|
||||
|
||||
let decl = if is!("class") {
|
||||
self.parse_default_class(decorators)?
|
||||
if is!("class") {
|
||||
let decl = self.parse_default_class(decorators)?;
|
||||
return Ok(ModuleDecl::ExportDefaultDecl(decl));
|
||||
} else if is!("async")
|
||||
&& peeked_is!("function")
|
||||
&& !self.input.has_linebreak_between_cur_and_peeked()
|
||||
{
|
||||
self.parse_default_async_fn(decorators)?
|
||||
let decl = self.parse_default_async_fn(decorators)?;
|
||||
return Ok(ModuleDecl::ExportDefaultDecl(decl));
|
||||
} else if is!("function") {
|
||||
self.parse_default_fn(decorators)?
|
||||
let decl = self.parse_default_fn(decorators)?;
|
||||
return Ok(ModuleDecl::ExportDefaultDecl(decl));
|
||||
} else if self.input.syntax().export_default_from()
|
||||
&& (is!("from") || (is!(',') && peeked_is!('{')))
|
||||
{
|
||||
export_default = Some(Ident::new("default".into(), self.input.prev_span()))
|
||||
} else {
|
||||
let expr = self.include_in_expr(true).parse_assignment_expr()?;
|
||||
expect!(';');
|
||||
return Ok(ModuleDecl::ExportDefaultExpr(expr));
|
||||
};
|
||||
|
||||
return Ok(ModuleDecl::ExportDefaultDecl(decl));
|
||||
}
|
||||
}
|
||||
|
||||
let decl = if is!("class") {
|
||||
@ -271,10 +279,15 @@ impl<'a, I: Input> Parser<'a, I> {
|
||||
// export {};
|
||||
// export {} from '';
|
||||
|
||||
let default = if self.input.syntax().export_default_from() && is!(IdentRef) {
|
||||
Some(self.parse_ident(false, false)?)
|
||||
} else {
|
||||
None
|
||||
let default = match export_default {
|
||||
Some(default) => Some(default),
|
||||
None => {
|
||||
if self.input.syntax().export_default_from() && is!(IdentName) {
|
||||
Some(self.parse_ident(false, false)?)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if is!("from") {
|
||||
|
116
ecmascript/transforms/src/modules/import_analysis.rs
Normal file
116
ecmascript/transforms/src/modules/import_analysis.rs
Normal file
@ -0,0 +1,116 @@
|
||||
use super::util::Scope;
|
||||
use crate::util::State;
|
||||
use ast::*;
|
||||
use swc_common::{Fold, Visit, VisitWith};
|
||||
|
||||
/// Inject required helpers methods **for** module transform passes.
|
||||
#[derive(Default, Clone)]
|
||||
pub struct ImportAnalyzer {
|
||||
scope: State<Scope>,
|
||||
}
|
||||
|
||||
impl Fold<Module> for ImportAnalyzer {
|
||||
fn fold(&mut self, module: Module) -> Module {
|
||||
module.visit_with(self);
|
||||
|
||||
for (_, ty) in self.scope.value.import_types.drain() {
|
||||
match ty {
|
||||
true => {
|
||||
helper!(interop_require_wildcard);
|
||||
}
|
||||
false => {
|
||||
helper!(interop_require_default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit<ExportAll> for ImportAnalyzer {
|
||||
fn visit(&mut self, export: &ExportAll) {
|
||||
self.scope
|
||||
.value
|
||||
.import_types
|
||||
.entry(export.src.value.clone())
|
||||
.and_modify(|v| *v = true);
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit<NamedExport> for ImportAnalyzer {
|
||||
fn visit(&mut self, export: &NamedExport) {
|
||||
for &NamedExportSpecifier {
|
||||
ref orig,
|
||||
ref exported,
|
||||
..
|
||||
} in export.specifiers.iter().map(|e| match *e {
|
||||
ExportSpecifier::Named(ref e) => e,
|
||||
_ => unreachable!("export default from 'foo'; should be removed by previous pass"),
|
||||
}) {
|
||||
let is_import_default = orig.sym == js_word!("default");
|
||||
|
||||
if let Some(ref src) = export.src {
|
||||
if is_import_default {
|
||||
self.scope
|
||||
.import_types
|
||||
.entry(src.value.clone())
|
||||
.or_insert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit<ImportDecl> for ImportAnalyzer {
|
||||
fn visit(&mut self, import: &ImportDecl) {
|
||||
if import.specifiers.is_empty() {
|
||||
// import 'foo';
|
||||
// -> require('foo');
|
||||
} else if import.specifiers.len() == 1
|
||||
&& match import.specifiers[0] {
|
||||
ImportSpecifier::Namespace(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
{
|
||||
} else {
|
||||
for s in &import.specifiers {
|
||||
match *s {
|
||||
ImportSpecifier::Namespace(..) => unreachable!(
|
||||
"import * as foo cannot be used with other type of import specifiers"
|
||||
),
|
||||
ImportSpecifier::Default(ref i) => {
|
||||
self.scope
|
||||
.import_types
|
||||
.entry(import.src.value.clone())
|
||||
.or_insert(false);
|
||||
}
|
||||
ImportSpecifier::Specific(ref i) => {
|
||||
let ImportSpecific {
|
||||
ref local,
|
||||
ref imported,
|
||||
..
|
||||
} = *i;
|
||||
let name = imported
|
||||
.as_ref()
|
||||
.map(|i| i.sym.clone())
|
||||
.unwrap_or_else(|| local.sym.clone());
|
||||
let is_default = name == js_word!("default");
|
||||
|
||||
if is_default {
|
||||
self.scope
|
||||
.import_types
|
||||
.entry(import.src.value.clone())
|
||||
.or_insert(false);
|
||||
} else {
|
||||
self.scope
|
||||
.import_types
|
||||
.entry(import.src.value.clone())
|
||||
.and_modify(|v| *v = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
pub mod amd;
|
||||
pub mod common_js;
|
||||
pub mod import_analysis;
|
||||
pub mod umd;
|
||||
mod util;
|
||||
|
Loading…
Reference in New Issue
Block a user