swc_bundler/bundler/chunk/
computed_key.rs1use std::mem::take;
2
3use anyhow::{bail, Error};
4use swc_atoms::atom;
5use swc_common::{SyntaxContext, DUMMY_SP};
6use swc_ecma_ast::*;
7use swc_ecma_utils::{contains_top_level_await, find_pat_ids, private_ident, ExprFactory};
8use swc_ecma_visit::{noop_fold_type, Fold};
9
10use crate::{
11 bundler::chunk::merge::Ctx,
12 modules::Modules,
13 util::{is_injected, ExportMetadata},
14 Bundler, Load, ModuleId, Resolve,
15};
16
17impl<L, R> Bundler<'_, L, R>
18where
19 L: Load,
20 R: Resolve,
21{
22 pub(super) fn wrap_esm(
39 &self,
40 ctx: &Ctx,
41 id: ModuleId,
42 module: Modules,
43 ) -> Result<Modules, Error> {
44 let span = DUMMY_SP;
45 let module_var_name = match self.scope.wrapped_esm_id(id) {
46 Some(v) => v,
47 None => bail!("{:?} should not be wrapped with a function", id),
48 };
49
50 let is_async = module.iter().any(|m| contains_top_level_await(m.1));
51
52 let mut additional_items = Vec::new();
53
54 module.iter().for_each(|(module_id, item)| {
55 match item {
56 ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(NamedExport {
60 ref specifiers,
61 with: Some(with),
62 ..
63 })) if is_injected(with) => {
64 for s in specifiers {
65 if let ExportSpecifier::Named(ExportNamedSpecifier {
66 orig,
67 exported: Some(exported),
68 ..
69 }) = s
70 {
71 let exported = match exported {
72 ModuleExportName::Ident(ident) => ident,
73 ModuleExportName::Str(..) => {
74 unimplemented!("module string names unimplemented")
75 }
76 #[cfg(swc_ast_unknown)]
77 _ => panic!("unable to access unknown nodes"),
78 };
79 if ctx.transitive_remap.get(&exported.ctxt).is_some() {
80 let specifier = ExportSpecifier::Named(ExportNamedSpecifier {
81 span: DUMMY_SP,
82 orig: orig.clone(),
83 exported: Some(ModuleExportName::Ident(exported.clone())),
84 is_type_only: false,
85 });
86 additional_items.push((
87 module_id,
88 NamedExport {
89 span: DUMMY_SP,
90 specifiers: vec![specifier],
91 src: None,
92 type_only: false,
93 with: Some(
94 ExportMetadata {
95 injected: true,
96 ..Default::default()
97 }
98 .into_with(),
99 ),
100 }
101 .into(),
102 ));
103 }
104 }
105 }
106 }
107 _ => {}
108 }
109 });
110
111 let mut export_visitor = ExportToReturn {
112 synthesized_ctxt: self.synthesized_ctxt,
113 return_props: Default::default(),
114 };
115 let mut module = module.fold_with(&mut export_visitor);
116
117 module.append_all(additional_items);
118
119 let return_stmt = ReturnStmt {
120 span: DUMMY_SP,
121 arg: Some(
122 ObjectLit {
123 span: DUMMY_SP,
124 props: take(&mut export_visitor.return_props),
125 }
126 .into(),
127 ),
128 }
129 .into();
130
131 module.iter().for_each(|(_, v)| {
132 if let ModuleItem::ModuleDecl(ModuleDecl::ExportAll(ref export)) = v {
133 let mut map = ctx.export_stars_in_wrapped.lock();
135 let data = ExportMetadata::decode(export.with.as_deref());
136 if let Some(export_ctxt) = data.export_ctxt {
137 map.entry(id).or_default().push(export_ctxt);
138 }
139 }
140 });
141
142 let module_fn: Expr = FnExpr {
143 function: Box::new(Function {
144 params: Default::default(),
145 body: Some(BlockStmt {
146 span: DUMMY_SP,
147 stmts: vec![return_stmt],
148 ..Default::default()
149 }),
150 is_generator: false,
151 is_async,
152 ..Default::default()
153 }),
154 ident: None,
155 }
156 .into();
157
158 let mut module_expr = CallExpr {
159 span: DUMMY_SP,
160 callee: module_fn.as_callee(),
161 args: Default::default(),
162 ..Default::default()
163 }
164 .into();
165
166 if is_async {
167 module_expr = AwaitExpr {
168 span: DUMMY_SP,
169 arg: Box::new(module_expr),
170 }
171 .into();
172 }
173
174 let var_decl = VarDecl {
175 span,
176 ctxt: self.injected_ctxt,
177 declare: false,
178 kind: VarDeclKind::Const,
179 decls: vec![VarDeclarator {
180 span: DUMMY_SP,
181 definite: false,
182 name: Pat::Ident(module_var_name.into_ident().into()),
183 init: Some(Box::new(module_expr)),
184 }],
185 };
186
187 module.append(id, var_decl.into());
188
189 Ok(module)
200 }
201}
202
203struct ExportToReturn {
204 return_props: Vec<PropOrSpread>,
205 synthesized_ctxt: SyntaxContext,
206}
207
208impl ExportToReturn {
209 fn export_id(&mut self, mut i: Ident) {
210 i.ctxt = SyntaxContext::empty();
211 self.return_props
212 .push(PropOrSpread::Prop(Box::new(Prop::Shorthand(i))));
213 }
214
215 fn export_key_value(&mut self, key: Ident, value: Ident) {
216 self.return_props
217 .push(PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
218 key: PropName::Ident(key.into()),
219 value: value.into(),
220 }))));
221 }
222}
223
224impl Fold for ExportToReturn {
225 noop_fold_type!();
226
227 fn fold_stmt(&mut self, s: Stmt) -> Stmt {
228 s
229 }
230
231 fn fold_module_item(&mut self, item: ModuleItem) -> ModuleItem {
232 let decl = match item {
233 ModuleItem::ModuleDecl(decl) => decl,
234 ModuleItem::Stmt(_) => return item,
235 #[cfg(swc_ast_unknown)]
236 _ => panic!("unable to access unknown nodes"),
237 };
238
239 let stmt = match decl {
240 ModuleDecl::Import(_) => return decl.into(),
241 ModuleDecl::ExportDecl(export) => {
242 match &export.decl {
243 Decl::Class(ClassDecl { ident, .. }) | Decl::Fn(FnDecl { ident, .. }) => {
244 self.export_id(ident.clone());
245 }
246 Decl::Var(decl) => {
247 let ids: Vec<Ident> = find_pat_ids(decl);
248 ids.into_iter().for_each(|id| self.export_id(id));
249 }
250 _ => unreachable!(),
251 }
252
253 Some(ModuleItem::from(export.decl))
254 }
255
256 ModuleDecl::ExportDefaultDecl(export) => match export.decl {
257 DefaultDecl::Class(expr) => {
258 let ident = expr.ident;
259 let ident = ident.unwrap_or_else(|| private_ident!("_default_decl"));
260
261 self.export_key_value(
262 Ident::new_no_ctxt(atom!("default"), export.span),
263 ident.clone(),
264 );
265
266 Some(
267 ClassDecl {
268 ident,
269 class: expr.class,
270 declare: false,
271 }
272 .into(),
273 )
274 }
275 DefaultDecl::Fn(expr) => {
276 let ident = expr.ident;
277 let ident = ident.unwrap_or_else(|| private_ident!("_default_decl"));
278
279 self.export_key_value(
280 Ident::new_no_ctxt(atom!("default"), export.span),
281 ident.clone(),
282 );
283
284 Some(
285 FnDecl {
286 ident,
287 function: expr.function,
288 declare: false,
289 }
290 .into(),
291 )
292 }
293 DefaultDecl::TsInterfaceDecl(_) => None,
294 #[cfg(swc_ast_unknown)]
295 _ => panic!("unable to access unknown nodes"),
296 },
297 ModuleDecl::ExportDefaultExpr(_) => None,
298 ModuleDecl::ExportAll(export) => return export.into(),
299 ModuleDecl::ExportNamed(export) => {
300 for specifier in &export.specifiers {
301 match specifier {
302 ExportSpecifier::Namespace(_) => {}
303 ExportSpecifier::Default(_) => {}
304 ExportSpecifier::Named(named) => match &named.exported {
305 Some(ModuleExportName::Ident(exported)) => {
306 if let ModuleExportName::Ident(orig) = &named.orig {
309 self.export_key_value(exported.clone(), orig.clone());
310 } else {
311 unimplemented!("module string names unimplemented")
312 }
313 }
314 Some(ModuleExportName::Str(..)) => {
315 unimplemented!("module string names unimplemented")
316 }
317 #[cfg(swc_ast_unknown)]
318 Some(_) => panic!("unable to access unknown nodes"),
319 None => {
320 if let ModuleExportName::Ident(orig) = &named.orig {
321 self.export_id(orig.clone());
322 } else {
323 unimplemented!("module string names unimplemented")
324 }
325 }
326 },
327 #[cfg(swc_ast_unknown)]
328 _ => panic!("unable to access unknown nodes"),
329 }
330 }
331
332 let md = ExportMetadata::decode(export.with.as_deref());
333 if export.src.is_none()
335 && md.export_ctxt.unwrap_or_default() != self.synthesized_ctxt
336 {
337 None
338 } else {
339 return export.into();
340 }
341 }
342 ModuleDecl::TsImportEquals(_) => None,
343 ModuleDecl::TsExportAssignment(_) => None,
344 ModuleDecl::TsNamespaceExport(_) => None,
345 #[cfg(swc_ast_unknown)]
346 _ => panic!("unable to access unknown nodes"),
347 };
348
349 if let Some(stmt) = stmt {
350 stmt
351 } else {
352 EmptyStmt { span: DUMMY_SP }.into()
353 }
354 }
355}