-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
perf(es/compat): Merge export_namespace_from to Transformer
#11309
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+180
−20
Merged
Changes from 3 commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,7 @@ | ||
| use swc_ecma_ast::Pass; | ||
| use swc_ecma_compiler::{Compiler, Features}; | ||
|
|
||
| pub fn export_namespace_from() -> impl Pass { | ||
| Compiler::new(swc_ecma_compiler::Config { | ||
| includes: Features::EXPORT_NAMESPACE_FROM, | ||
| ..Default::default() | ||
| }) | ||
| let mut options = swc_ecma_transformer::Options::default(); | ||
| options.env.es2020.export_namespace_from = true; | ||
| options.into_pass() | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
132 changes: 132 additions & 0 deletions
132
crates/swc_ecma_transformer/src/es2020/export_namespace_from.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,132 @@ | ||
| use swc_ecma_ast::*; | ||
| use swc_ecma_hooks::VisitMutHook; | ||
| use swc_ecma_utils::private_ident; | ||
|
|
||
| use crate::{utils::normalize_module_export_name, TraverseCtx}; | ||
|
|
||
| pub fn hook() -> impl VisitMutHook<TraverseCtx> { | ||
| ExportNamespaceFromPass | ||
| } | ||
|
|
||
| struct ExportNamespaceFromPass; | ||
|
|
||
| impl ExportNamespaceFromPass { | ||
| fn transform_export_namespace_from(&mut self, items: &mut Vec<ModuleItem>) { | ||
| let count = items | ||
| .iter() | ||
| .filter(|m| { | ||
| matches!(m, ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(NamedExport { | ||
| specifiers, | ||
| src: Some(..), | ||
| type_only: false, | ||
| .. | ||
| })) if specifiers.iter().any(|s| s.is_namespace())) | ||
| }) | ||
| .count(); | ||
|
|
||
| if count == 0 { | ||
| return; | ||
| } | ||
|
|
||
| let mut stmts = Vec::<ModuleItem>::with_capacity(items.len() + count); | ||
|
|
||
| for item in items.drain(..) { | ||
| match item { | ||
| ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(NamedExport { | ||
| span, | ||
| specifiers, | ||
| src: Some(src), | ||
| type_only: false, | ||
| with, | ||
| })) if specifiers.iter().any(|s| s.is_namespace()) => { | ||
| let mut origin_specifiers = Vec::new(); | ||
|
|
||
| let mut import_specifiers = Vec::new(); | ||
| let mut export_specifiers = Vec::new(); | ||
|
|
||
| for s in specifiers.into_iter() { | ||
| match s { | ||
| ExportSpecifier::Namespace(ExportNamespaceSpecifier { span, name }) => { | ||
| let local_bridge = private_ident!(format!( | ||
| "_{}", | ||
| normalize_module_export_name(&name) | ||
| )); | ||
|
|
||
| import_specifiers.push(ImportSpecifier::Namespace( | ||
| ImportStarAsSpecifier { | ||
| span, | ||
| local: local_bridge.clone(), | ||
| }, | ||
| )); | ||
| export_specifiers.push(ExportSpecifier::Named( | ||
| ExportNamedSpecifier { | ||
| span, | ||
| orig: local_bridge.into(), | ||
| exported: Some(name), | ||
| is_type_only: false, | ||
| }, | ||
| )) | ||
| } | ||
| ExportSpecifier::Default(..) | ExportSpecifier::Named(..) => { | ||
| origin_specifiers.push(s); | ||
| } | ||
| #[cfg(swc_ast_unknown)] | ||
| _ => panic!("unable to access unknown nodes"), | ||
| } | ||
| } | ||
|
|
||
| stmts.push( | ||
| ImportDecl { | ||
| span, | ||
| specifiers: import_specifiers, | ||
| src: src.clone(), | ||
| type_only: false, | ||
| with: with.clone(), | ||
| phase: Default::default(), | ||
| } | ||
| .into(), | ||
| ); | ||
|
|
||
| stmts.push( | ||
| NamedExport { | ||
| span, | ||
| specifiers: export_specifiers, | ||
| src: None, | ||
| type_only: false, | ||
| with: None, | ||
| } | ||
| .into(), | ||
| ); | ||
|
|
||
| if !origin_specifiers.is_empty() { | ||
| stmts.push( | ||
| NamedExport { | ||
| span, | ||
| specifiers: origin_specifiers, | ||
| src: Some(src), | ||
| type_only: false, | ||
| with, | ||
| } | ||
| .into(), | ||
| ); | ||
| } | ||
| } | ||
| _ => { | ||
| stmts.push(item); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| *items = stmts; | ||
| } | ||
| } | ||
|
|
||
| impl VisitMutHook<TraverseCtx> for ExportNamespaceFromPass { | ||
| fn exit_program(&mut self, node: &mut Program, _: &mut TraverseCtx) { | ||
| let Program::Module(module) = node else { | ||
| return; | ||
| }; | ||
|
|
||
| self.transform_export_namespace_from(&mut module.body); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,17 +1,19 @@ | ||
| use swc_ecma_hooks::VisitMutHook; | ||
|
|
||
| use crate::TraverseCtx; | ||
| use crate::{hook_utils::OptionalHook, TraverseCtx}; | ||
|
|
||
| mod export_namespace_from; | ||
|
|
||
| #[derive(Debug, Default)] | ||
| #[non_exhaustive] | ||
| pub struct Es2020Options {} | ||
|
|
||
| pub fn hook(options: Es2020Options) -> impl VisitMutHook<TraverseCtx> { | ||
| Es2020Pass { options } | ||
| pub struct Es2020Options { | ||
| pub export_namespace_from: bool, | ||
| } | ||
|
|
||
| struct Es2020Pass { | ||
| options: Es2020Options, | ||
| pub fn hook(options: Es2020Options) -> impl VisitMutHook<TraverseCtx> { | ||
| OptionalHook(if options.export_namespace_from { | ||
| Some(self::export_namespace_from::hook()) | ||
| } else { | ||
| None | ||
| }) | ||
| } | ||
|
|
||
| impl VisitMutHook<TraverseCtx> for Es2020Pass {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,6 +23,7 @@ mod jsx; | |
| mod options; | ||
| mod regexp; | ||
| mod typescript; | ||
| mod utils; | ||
|
|
||
| pub struct TraverseCtx {} | ||
|
|
||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| use std::borrow::Cow; | ||
|
|
||
| use swc_atoms::Atom; | ||
| use swc_ecma_ast::*; | ||
|
|
||
| pub(crate) fn normalize_module_export_name(module_export_name: &ModuleExportName) -> Cow<Atom> { | ||
| match module_export_name { | ||
| ModuleExportName::Ident(Ident { sym: name, .. }) => Cow::Borrowed(name), | ||
| ModuleExportName::Str(Str { value: name, .. }) => { | ||
| // Normally, the export name should be valid UTF-8. But it might also contain | ||
| // unpaired surrogates. Node would give an error in this case: | ||
kdy1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // `SyntaxError: Invalid module export name: contains unpaired | ||
| // surrogate`. Here, we temporarily replace the unpaired surrogates | ||
| // with U+FFFD REPLACEMENT CHARACTER by using Wtf8::to_string_lossy. | ||
| Cow::Owned(Atom::from(name.to_string_lossy())) | ||
| } | ||
| #[cfg(swc_ast_unknown)] | ||
| _ => panic!("unable to access unknown nodes"), | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.