mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 17:34:47 -05:00
feat(repl): support exports in the REPL (#11592)
This commit is contained in:
parent
15b0e61de5
commit
e9ddc7a41a
3 changed files with 195 additions and 24 deletions
|
@ -314,6 +314,7 @@ impl ParsedModule {
|
||||||
let mut passes = chain!(
|
let mut passes = chain!(
|
||||||
Optional::new(jsx_pass, options.transform_jsx),
|
Optional::new(jsx_pass, options.transform_jsx),
|
||||||
Optional::new(transforms::DownlevelImportsFolder, options.repl_imports),
|
Optional::new(transforms::DownlevelImportsFolder, options.repl_imports),
|
||||||
|
Optional::new(transforms::StripExportsFolder, options.repl_imports),
|
||||||
proposals::decorators::decorators(proposals::decorators::Config {
|
proposals::decorators::decorators(proposals::decorators::Config {
|
||||||
legacy: true,
|
legacy: true,
|
||||||
emit_metadata: options.emit_metadata
|
emit_metadata: options.emit_metadata
|
||||||
|
|
|
@ -21,33 +21,12 @@ impl Fold for DownlevelImportsFolder {
|
||||||
ModuleItem::ModuleDecl(ModuleDecl::Import(import_decl)) => {
|
ModuleItem::ModuleDecl(ModuleDecl::Import(import_decl)) => {
|
||||||
// Handle type only imports
|
// Handle type only imports
|
||||||
if import_decl.type_only {
|
if import_decl.type_only {
|
||||||
return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP }));
|
// should have no side effects
|
||||||
|
return create_empty_stmt();
|
||||||
}
|
}
|
||||||
|
|
||||||
// The initializer (ex. `await import('./mod.ts')`)
|
// The initializer (ex. `await import('./mod.ts')`)
|
||||||
let initializer = Box::new(Expr::Await(AwaitExpr {
|
let initializer = create_await_import_expr(&import_decl.src.value);
|
||||||
span: DUMMY_SP,
|
|
||||||
arg: Box::new(Expr::Call(CallExpr {
|
|
||||||
span: DUMMY_SP,
|
|
||||||
callee: ExprOrSuper::Expr(Box::new(Expr::Ident(Ident {
|
|
||||||
span: DUMMY_SP,
|
|
||||||
sym: "import".into(),
|
|
||||||
optional: false,
|
|
||||||
}))),
|
|
||||||
args: vec![ExprOrSpread {
|
|
||||||
spread: None,
|
|
||||||
expr: Box::new(Expr::Lit(Lit::Str(Str {
|
|
||||||
span: DUMMY_SP,
|
|
||||||
has_escape: false,
|
|
||||||
kind: StrKind::Normal {
|
|
||||||
contains_quote: false,
|
|
||||||
},
|
|
||||||
value: import_decl.src.value.clone(),
|
|
||||||
}))),
|
|
||||||
}],
|
|
||||||
type_args: None,
|
|
||||||
})),
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Handle imports for the side effects
|
// Handle imports for the side effects
|
||||||
// ex. `import "module.ts"` -> `await import("module.ts");`
|
// ex. `import "module.ts"` -> `await import("module.ts");`
|
||||||
|
@ -128,6 +107,78 @@ impl Fold for DownlevelImportsFolder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Strips export declarations and exports on named exports for the REPL.
|
||||||
|
pub struct StripExportsFolder;
|
||||||
|
|
||||||
|
impl Fold for StripExportsFolder {
|
||||||
|
noop_fold_type!(); // skip typescript specific nodes
|
||||||
|
|
||||||
|
fn fold_module_item(
|
||||||
|
&mut self,
|
||||||
|
module_item: swc_ast::ModuleItem,
|
||||||
|
) -> swc_ast::ModuleItem {
|
||||||
|
use swc_ecmascript::ast::*;
|
||||||
|
|
||||||
|
match module_item {
|
||||||
|
ModuleItem::ModuleDecl(ModuleDecl::ExportAll(export_all)) => {
|
||||||
|
ModuleItem::Stmt(Stmt::Expr(ExprStmt {
|
||||||
|
span: DUMMY_SP,
|
||||||
|
expr: create_await_import_expr(&export_all.src.value),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(export_named)) => {
|
||||||
|
if let Some(src) = export_named.src {
|
||||||
|
ModuleItem::Stmt(Stmt::Expr(ExprStmt {
|
||||||
|
span: DUMMY_SP,
|
||||||
|
expr: create_await_import_expr(&src.value),
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
create_empty_stmt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultExpr(default_expr)) => {
|
||||||
|
// transform a default export expression to its expression
|
||||||
|
ModuleItem::Stmt(Stmt::Expr(ExprStmt {
|
||||||
|
span: DUMMY_SP,
|
||||||
|
expr: default_expr.expr,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(export_decl)) => {
|
||||||
|
// strip the export keyword on an exported declaration
|
||||||
|
ModuleItem::Stmt(Stmt::Decl(export_decl.decl))
|
||||||
|
}
|
||||||
|
ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultDecl(default_decl)) => {
|
||||||
|
// only keep named default exports
|
||||||
|
match default_decl.decl {
|
||||||
|
DefaultDecl::Fn(FnExpr {
|
||||||
|
ident: Some(ident),
|
||||||
|
function,
|
||||||
|
}) => ModuleItem::Stmt(Stmt::Decl(Decl::Fn(FnDecl {
|
||||||
|
declare: false,
|
||||||
|
ident,
|
||||||
|
function,
|
||||||
|
}))),
|
||||||
|
DefaultDecl::Class(ClassExpr {
|
||||||
|
ident: Some(ident),
|
||||||
|
class,
|
||||||
|
}) => ModuleItem::Stmt(Stmt::Decl(Decl::Class(ClassDecl {
|
||||||
|
declare: false,
|
||||||
|
ident,
|
||||||
|
class,
|
||||||
|
}))),
|
||||||
|
_ => create_empty_stmt(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => module_item,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_empty_stmt() -> swc_ast::ModuleItem {
|
||||||
|
use swc_ast::*;
|
||||||
|
ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP }))
|
||||||
|
}
|
||||||
|
|
||||||
fn create_binding_ident(name: String) -> swc_ast::BindingIdent {
|
fn create_binding_ident(name: String) -> swc_ast::BindingIdent {
|
||||||
swc_ast::BindingIdent {
|
swc_ast::BindingIdent {
|
||||||
id: create_ident(name),
|
id: create_ident(name),
|
||||||
|
@ -161,6 +212,33 @@ fn create_key_value(key: String, value: String) -> swc_ast::ObjectPatProp {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_await_import_expr(module_specifier: &str) -> Box<swc_ast::Expr> {
|
||||||
|
use swc_ast::*;
|
||||||
|
Box::new(Expr::Await(AwaitExpr {
|
||||||
|
span: DUMMY_SP,
|
||||||
|
arg: Box::new(Expr::Call(CallExpr {
|
||||||
|
span: DUMMY_SP,
|
||||||
|
callee: ExprOrSuper::Expr(Box::new(Expr::Ident(Ident {
|
||||||
|
span: DUMMY_SP,
|
||||||
|
sym: "import".into(),
|
||||||
|
optional: false,
|
||||||
|
}))),
|
||||||
|
args: vec![ExprOrSpread {
|
||||||
|
spread: None,
|
||||||
|
expr: Box::new(Expr::Lit(Lit::Str(Str {
|
||||||
|
span: DUMMY_SP,
|
||||||
|
has_escape: false,
|
||||||
|
kind: StrKind::Normal {
|
||||||
|
contains_quote: false,
|
||||||
|
},
|
||||||
|
value: module_specifier.into(),
|
||||||
|
}))),
|
||||||
|
}],
|
||||||
|
type_args: None,
|
||||||
|
})),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
fn create_assignment(key: String) -> swc_ast::ObjectPatProp {
|
fn create_assignment(key: String) -> swc_ast::ObjectPatProp {
|
||||||
swc_ast::ObjectPatProp::Assign(swc_ast::AssignPatProp {
|
swc_ast::ObjectPatProp::Assign(swc_ast::AssignPatProp {
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
|
@ -264,6 +342,85 @@ mod test {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_strip_exports_export_all() {
|
||||||
|
test_transform(
|
||||||
|
StripExportsFolder,
|
||||||
|
r#"export * from "./test.ts";"#,
|
||||||
|
r#"await import("./test.ts");"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_strip_exports_export_named() {
|
||||||
|
test_transform(
|
||||||
|
StripExportsFolder,
|
||||||
|
r#"export { test } from "./test.ts";"#,
|
||||||
|
r#"await import("./test.ts");"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
test_transform(StripExportsFolder, r#"export { test };"#, ";");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_strip_exports_export_default_expr() {
|
||||||
|
test_transform(StripExportsFolder, "export default 5;", "5;");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_strip_exports_export_default_decl_name() {
|
||||||
|
test_transform(
|
||||||
|
StripExportsFolder,
|
||||||
|
"export default class Test {}",
|
||||||
|
"class Test {\n}",
|
||||||
|
);
|
||||||
|
|
||||||
|
test_transform(
|
||||||
|
StripExportsFolder,
|
||||||
|
"export default function test() {}",
|
||||||
|
"function test() {\n}",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_strip_exports_export_default_decl_no_name() {
|
||||||
|
test_transform(StripExportsFolder, "export default class {}", ";");
|
||||||
|
|
||||||
|
test_transform(StripExportsFolder, "export default function() {}", ";");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_strip_exports_export_named_decls() {
|
||||||
|
test_transform(
|
||||||
|
StripExportsFolder,
|
||||||
|
"export class Test {}",
|
||||||
|
"class Test {\n}",
|
||||||
|
);
|
||||||
|
|
||||||
|
test_transform(
|
||||||
|
StripExportsFolder,
|
||||||
|
"export function test() {}",
|
||||||
|
"function test() {\n}",
|
||||||
|
);
|
||||||
|
|
||||||
|
test_transform(StripExportsFolder, "export enum Test {}", "enum Test {\n}");
|
||||||
|
|
||||||
|
test_transform(
|
||||||
|
StripExportsFolder,
|
||||||
|
"export namespace Test {}",
|
||||||
|
"module Test {\n}",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_strip_exports_not_in_namespace() {
|
||||||
|
test_transform(
|
||||||
|
StripExportsFolder,
|
||||||
|
"namespace Test { export class Test {} }",
|
||||||
|
"module Test {\n export class Test {\n }\n}",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn test_transform(
|
fn test_transform(
|
||||||
mut transform: impl Fold,
|
mut transform: impl Fold,
|
||||||
src: &str,
|
src: &str,
|
||||||
|
|
|
@ -422,6 +422,19 @@ fn import_declarations() {
|
||||||
assert!(out.contains("hello!\n"));
|
assert!(out.contains("hello!\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exports_stripped() {
|
||||||
|
let (out, err) = util::run_and_collect_output(
|
||||||
|
true,
|
||||||
|
"repl",
|
||||||
|
Some(vec!["export default 5;", "export class Test {}"]),
|
||||||
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
assert!(out.contains("5\n"));
|
||||||
|
assert!(err.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn eval_unterminated() {
|
fn eval_unterminated() {
|
||||||
let (out, err) = util::run_and_collect_output(
|
let (out, err) = util::run_and_collect_output(
|
||||||
|
|
Loading…
Add table
Reference in a new issue