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::{visit_mut_pass, VisitMut},
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 + VisitMut {
18 visit_mut_pass(NamedImportTransform {
19 packages: config.packages,
20 })
21}
22
23#[derive(Debug, Default)]
24struct NamedImportTransform {
25 packages: Vec<String>,
26}
27
28impl VisitMut for NamedImportTransform {
29 fn visit_mut_import_decl(&mut self, decl: &mut ImportDecl) {
30 let src_value = &decl.src.value;
32
33 if self
34 .packages
35 .iter()
36 .any(|p| src_value.as_str() == Some(&**p))
37 {
38 let mut specifier_names = HashSet::new();
39
40 let mut skip_transform = false;
42
43 for specifier in &decl.specifiers {
44 match specifier {
45 ImportSpecifier::Named(specifier) => {
46 specifier_names.insert(specifier.imported.as_ref().map_or_else(
48 || specifier.local.sym.clone(),
49 |i| i.atom().into_owned(),
50 ));
51 }
52 ImportSpecifier::Default(_) => {
53 skip_transform = true;
54 break;
55 }
56 ImportSpecifier::Namespace(_) => {
57 skip_transform = true;
58 break;
59 }
60 }
61 }
62
63 if !skip_transform {
64 let mut names = specifier_names
65 .iter()
66 .map(|n| n.as_str())
67 .collect::<Vec<_>>();
68 names.sort();
70
71 let new_src = format!(
72 "__barrel_optimize__?names={}!=!{}",
73 names.join(","),
74 src_value.to_string_lossy()
75 );
76
77 *decl.src = Str {
78 span: DUMMY_SP,
79 value: new_src.into(),
80 raw: None,
81 };
82 }
83 }
84 }
85}