next_custom_transforms/transforms/
named_import_transform.rs1use std::collections::HashSet;
2
3use serde::Deserialize;
4use swc_core::{
5 common::DUMMY_SP,
6 ecma::{
7 ast::*,
8 visit::{fold_pass, Fold},
9 },
10};
11
12#[derive(Clone, Debug, Deserialize)]
13pub struct Config {
14 pub packages: Vec<String>,
15}
16
17pub fn named_import_transform(config: Config) -> impl Pass {
18 fold_pass(NamedImportTransform {
19 packages: config.packages,
20 })
21}
22
23#[derive(Debug, Default)]
24struct NamedImportTransform {
25 packages: Vec<String>,
26}
27
28impl Fold for NamedImportTransform {
30 fn fold_import_decl(&mut self, decl: ImportDecl) -> ImportDecl {
31 let src_value = decl.src.value.clone();
33
34 if self.packages.iter().any(|p| src_value == *p) {
35 let mut specifier_names = HashSet::new();
36
37 let mut skip_transform = false;
39
40 for specifier in &decl.specifiers {
41 match specifier {
42 ImportSpecifier::Named(specifier) => {
43 if let Some(imported) = &specifier.imported {
45 match imported {
46 ModuleExportName::Ident(ident) => {
47 specifier_names.insert(ident.sym.to_string());
48 }
49 ModuleExportName::Str(str_) => {
50 specifier_names.insert(str_.value.to_string());
51 }
52 }
53 } else {
54 specifier_names.insert(specifier.local.sym.to_string());
55 }
56 }
57 ImportSpecifier::Default(_) => {
58 skip_transform = true;
59 break;
60 }
61 ImportSpecifier::Namespace(_) => {
62 skip_transform = true;
63 break;
64 }
65 }
66 }
67
68 if !skip_transform {
69 let mut names = specifier_names.into_iter().collect::<Vec<_>>();
70 names.sort();
72
73 let new_src = format!(
74 "__barrel_optimize__?names={}!=!{}",
75 names.join(","),
76 src_value
77 );
78
79 let mut new_decl = decl.clone();
81 new_decl.src = Box::new(Str {
82 span: DUMMY_SP,
83 value: new_src.into(),
84 raw: None,
85 });
86
87 return new_decl;
88 }
89 }
90
91 decl
92 }
93}