1use std::{borrow::Cow, sync::Arc};
2
3use anyhow::{Result, bail};
4use bincode::{Decode, Encode};
5use swc_core::{
6 common::{
7 DUMMY_SP, Span,
8 errors::{DiagnosticId, Handler},
9 },
10 ecma::{
11 ast::{
12 Expr, ExprStmt, KeyValueProp, Lit, ModuleItem, ObjectLit, Prop, PropName, PropOrSpread,
13 Stmt, {self},
14 },
15 codegen::{Emitter, text_writer::JsWriter},
16 },
17 quote, quote_expr,
18};
19use turbo_rcstr::RcStr;
20use turbo_tasks::{
21 FxIndexMap, NonLocalValue, ResolvedVc, TryJoinIterExt, ValueToString, Vc,
22 debug::ValueDebugFormat, trace::TraceRawVcs,
23};
24use turbo_tasks_fs::{
25 DirectoryEntry, FileSystemPath, ReadGlobResult,
26 glob::{Glob, GlobOptions},
27};
28use turbopack_core::{
29 chunk::{
30 AsyncModuleInfo, ChunkableModule, ChunkingContext, ChunkingType, MinifyType,
31 ModuleChunkItemIdExt,
32 },
33 ident::AssetIdent,
34 issue::IssueSource,
35 module::{Module, ModuleSideEffects},
36 module_graph::ModuleGraph,
37 reference::{ModuleReference, ModuleReferences},
38 reference_type::EcmaScriptModulesReferenceSubType,
39 resolve::{
40 BindingUsage, ExportUsage, ModuleResolveResult, ResolveErrorMode, origin::ResolveOrigin,
41 parse::Request,
42 },
43};
44use turbopack_resolve::ecmascript::esm_resolve;
45
46use crate::{
47 EcmascriptChunkPlaceable,
48 analyzer::JsValue,
49 chunk::{EcmascriptChunkItemContent, EcmascriptExports, ecmascript_chunk_item},
50 code_gen::{CodeGen, CodeGeneration, IntoCodeGenReference},
51 create_visitor,
52 references::{
53 AstPath,
54 pattern_mapping::{PatternMapping, ResolveType},
55 },
56 runtime_functions::{TURBOPACK_EXPORT_VALUE, TURBOPACK_REQUIRE},
57 utils::module_id_to_lit,
58};
59
60#[derive(Debug, Clone)]
66pub struct ImportMetaGlobOptions {
67 pub patterns: Vec<RcStr>,
69 pub eager: bool,
71 pub import: Option<RcStr>,
73 pub query: Option<RcStr>,
75 pub base: Option<RcStr>,
77}
78
79pub fn parse_import_meta_glob(
91 args: &[JsValue],
92 handler: &Handler,
93 span: Span,
94 diagnostic_id: DiagnosticId,
95) -> Option<ImportMetaGlobOptions> {
96 if args.is_empty() || args.len() > 2 {
97 handler.span_warn_with_code(
98 span,
99 "import.meta.glob() requires 1 or 2 arguments",
100 diagnostic_id,
101 );
102 return None;
103 }
104
105 let patterns = {
107 let mut pats = Vec::new();
108 match &args[0] {
109 JsValue::Array { items, .. } => {
110 for item in items {
111 if let Some(s) = item.as_str() {
112 pats.push(s.into());
113 } else {
114 handler.span_warn_with_code(
115 span,
116 "import.meta.glob() pattern array elements must be constant strings",
117 diagnostic_id,
118 );
119 return None;
120 }
121 }
122 if pats.is_empty() {
123 handler.span_warn_with_code(
124 span,
125 "import.meta.glob() requires at least one pattern",
126 diagnostic_id,
127 );
128 return None;
129 }
130 }
131 _ => {
132 if let Some(s) = args[0].as_str() {
133 pats.push(s.into());
134 } else {
135 handler.span_warn_with_code(
136 span,
137 "import.meta.glob() first argument must be a string literal or array of \
138 string literals",
139 diagnostic_id,
140 );
141 return None;
142 }
143 }
144 }
145 pats
146 };
147
148 let mut eager = false;
150 let mut import = None;
151 let mut query = None;
152 let mut base = None;
153
154 if let Some(opts) = args.get(1) {
155 match opts {
156 JsValue::Object { parts, .. } => {
157 use crate::analyzer::ObjectPart;
158 for part in parts {
159 if let ObjectPart::KeyValue(key, val) = part {
160 match key.as_str() {
161 Some("eager") => {
162 if let Some(b) = val.as_bool() {
163 eager = b;
164 } else {
165 handler.span_warn_with_code(
166 span,
167 "import.meta.glob() 'eager' option must be a constant \
168 boolean (true or false), defaulting to false",
169 diagnostic_id.clone(),
170 );
171 }
172 }
173 Some("import") => {
174 if let Some(s) = val.as_str() {
175 if s != "*" {
178 import = Some(s.into());
179 }
180 } else {
181 handler.span_warn_with_code(
182 span,
183 "import.meta.glob() 'import' option must be a constant \
184 string, ignoring",
185 diagnostic_id.clone(),
186 );
187 }
188 }
189 Some("query") => {
190 if let Some(s) = val.as_str() {
191 let q: RcStr = if s.starts_with('?') {
193 s.into()
194 } else {
195 format!("?{s}").into()
196 };
197 query = Some(q);
198 } else if let JsValue::Object { parts, .. } = val {
199 use crate::analyzer::ObjectPart;
202 let mut pairs: Vec<String> = Vec::new();
203 for part in parts {
204 if let ObjectPart::KeyValue(k, v) = part {
205 if let Some(k_str) = k.as_str() {
206 let enc_key = urlencoding::encode(k_str);
207 if let Some(v_str) = v.as_str() {
208 let enc_val = urlencoding::encode(v_str);
209 pairs.push(format!("{enc_key}={enc_val}"));
210 } else if let Some(v_bool) = v.as_bool() {
211 pairs.push(format!("{enc_key}={v_bool}"));
212 } else {
213 handler.span_warn_with_code(
214 span,
215 &format!(
216 "import.meta.glob() 'query' object \
217 value for key '{k_str}' must be a \
218 constant string or boolean, ignoring"
219 ),
220 diagnostic_id.clone(),
221 );
222 }
223 } else {
224 handler.span_warn_with_code(
225 span,
226 "import.meta.glob() 'query' object keys must \
227 be constant strings",
228 diagnostic_id.clone(),
229 );
230 }
231 } else {
232 handler.span_warn_with_code(
233 span,
234 "import.meta.glob() 'query' object must only \
235 contain constant key-value pairs",
236 diagnostic_id.clone(),
237 );
238 }
239 }
240 if !pairs.is_empty() {
241 query = Some(format!("?{}", pairs.join("&")).into());
242 }
243 } else {
244 handler.span_warn_with_code(
245 span,
246 "import.meta.glob() 'query' option must be a constant \
247 string, ignoring",
248 diagnostic_id.clone(),
249 );
250 }
251 }
252 Some("base") => {
253 if let Some(s) = val.as_str() {
254 base = Some(s.into());
255 } else {
256 handler.span_warn_with_code(
257 span,
258 "import.meta.glob() 'base' option must be a constant \
259 string, ignoring",
260 diagnostic_id.clone(),
261 );
262 }
263 }
264 Some("as") => {
267 handler.span_warn_with_code(
268 span,
269 "import.meta.glob() 'as' option is not supported. Use 'query' \
270 instead (e.g. { query: '?raw' })",
271 diagnostic_id.clone(),
272 );
273 }
274 Some(other) => {
275 handler.span_warn_with_code(
276 span,
277 &format!(
278 "import.meta.glob() unsupported option '{other}'. \
279 Supported options are: eager, import, query, base"
280 ),
281 diagnostic_id.clone(),
282 );
283 }
284 None => {
285 handler.span_warn_with_code(
286 span,
287 "import.meta.glob() option keys must be constant strings",
288 diagnostic_id.clone(),
289 );
290 }
291 }
292 }
293 }
294 }
295 _ => {
296 handler.span_err_with_code(
297 span,
298 "import.meta.glob() second argument must be an object literal",
299 diagnostic_id.clone(),
300 );
301 return None;
302 }
303 }
304 }
305
306 Some(ImportMetaGlobOptions {
307 patterns,
308 eager,
309 import,
310 query,
311 base,
312 })
313}
314
315fn strip_relative_prefix(pattern: &str) -> &str {
323 pattern.strip_prefix("./").unwrap_or(pattern)
324}
325
326async fn flatten_read_glob(result: &ReadGlobResult) -> Result<Vec<(RcStr, FileSystemPath)>> {
334 let mut files = Vec::new();
335
336 fn collect_files(
338 node: &ReadGlobResult,
339 prefix: &str,
340 files: &mut Vec<(RcStr, FileSystemPath)>,
341 ) {
342 for (segment, entry) in &node.results {
343 let full_path = if prefix.is_empty() {
344 segment.to_string()
345 } else {
346 format!("{prefix}/{segment}")
347 };
348 if let DirectoryEntry::File(path) = entry {
349 files.push((full_path.into(), path.clone()));
350 }
351 }
352 }
353
354 let mut pending: Vec<(String, turbo_tasks::ReadRef<ReadGlobResult>)> = Vec::new();
356 collect_files(result, "", &mut files);
357
358 for (segment, inner_vc) in &result.inner {
360 let child_prefix = segment.to_string();
361 let inner = inner_vc.await?;
362 pending.push((child_prefix, inner));
363 }
364
365 while let Some((prefix, node)) = pending.pop() {
366 collect_files(&node, &prefix, &mut files);
367 for (segment, inner_vc) in &node.inner {
368 let child_prefix = format!("{prefix}/{segment}");
369 let inner = inner_vc.await?;
370 pending.push((child_prefix, inner));
371 }
372 }
373
374 files.sort_by(|a: &(RcStr, _), b: &(RcStr, _)| a.0.cmp(&b.0));
375 Ok(files)
376}
377
378#[turbo_tasks::value]
383#[derive(Debug)]
384pub struct ImportMetaGlobMapEntry {
385 pub origin_relative: RcStr,
388 pub request: ResolvedVc<Request>,
389 pub result: ResolvedVc<ModuleResolveResult>,
390}
391
392#[turbo_tasks::value(transparent)]
393pub struct ImportMetaGlobMap(
394 #[bincode(with = "turbo_bincode::indexmap")] FxIndexMap<RcStr, ImportMetaGlobMapEntry>,
395);
396
397#[turbo_tasks::value_impl]
398impl ImportMetaGlobMap {
399 #[turbo_tasks::function]
406 pub(crate) async fn generate(
407 origin: Vc<Box<dyn ResolveOrigin>>,
408 base_dir: FileSystemPath,
409 positive_glob: Vc<Glob>,
410 negative_glob: Option<Vc<Glob>>,
411 query: Option<RcStr>,
412 eager: bool,
413 issue_source: Option<IssueSource>,
414 error_mode: ResolveErrorMode,
415 ) -> Result<Vc<Self>> {
416 let origin_path = origin.origin_path().await?.parent();
417
418 let glob_result = base_dir.read_glob(positive_glob).await?;
420 let files = flatten_read_glob(&glob_result).await?;
421
422 let negative = if let Some(neg) = negative_glob {
424 Some(neg.await?)
425 } else {
426 None
427 };
428
429 let reference_sub_type = if eager {
430 EcmaScriptModulesReferenceSubType::Import
431 } else {
432 EcmaScriptModulesReferenceSubType::DynamicImport
433 };
434
435 let entries: Vec<_> = files
437 .iter()
438 .filter(|(base_relative, _)| {
439 if let Some(ref neg) = negative {
441 !neg.matches(base_relative)
442 } else {
443 true
444 }
445 })
446 .map(|(_base_relative, path)| {
447 let origin_path = &origin_path;
448 let query = &query;
449 let reference_sub_type = &reference_sub_type;
450 async move {
451 let Some(origin_relative) = origin_path.get_relative_path_to(path) else {
454 bail!(
455 "import.meta.glob: failed to compute relative path from origin to \
456 matched file"
457 );
458 };
459
460 let request_str: RcStr = if let Some(q) = query {
462 format!("{origin_relative}{q}").into()
463 } else {
464 origin_relative.clone()
465 };
466
467 let request = Request::parse_string(request_str).to_resolved().await?;
468
469 let result = esm_resolve(
470 origin,
471 *request,
472 reference_sub_type.clone(),
473 error_mode,
474 issue_source,
475 )
476 .await?
477 .to_resolved()
478 .await?;
479
480 Ok((
481 origin_relative.clone(),
482 ImportMetaGlobMapEntry {
483 origin_relative,
484 request,
485 result,
486 },
487 ))
488 }
489 })
490 .try_join()
491 .await?;
492
493 let mut map: FxIndexMap<RcStr, ImportMetaGlobMapEntry> = entries.into_iter().collect();
494
495 map.sort_keys();
496
497 Ok(Vc::cell(map))
498 }
499}
500
501#[turbo_tasks::value]
510#[derive(ValueToString)]
511#[value_to_string("import.meta.glob resolved reference")]
512pub struct ImportMetaGlobModuleReference {
513 result: ResolvedVc<ModuleResolveResult>,
514 export: ExportUsage,
515}
516
517#[turbo_tasks::value_impl]
518impl ModuleReference for ImportMetaGlobModuleReference {
519 #[turbo_tasks::function]
520 fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
521 *self.result
522 }
523
524 fn chunking_type(&self) -> Option<ChunkingType> {
525 Some(ChunkingType::Parallel {
526 inherit_async: false,
527 hoisted: false,
528 })
529 }
530
531 fn binding_usage(&self) -> BindingUsage {
532 BindingUsage {
533 import: Default::default(),
534 export: self.export.clone(),
535 }
536 }
537}
538
539fn modifier(
549 patterns: &[RcStr],
550 eager: bool,
551 import: &Option<RcStr>,
552 query: &Option<RcStr>,
553 base: &Option<RcStr>,
554) -> RcStr {
555 let mut s = format!("import.meta.glob {}", patterns.join(", "));
556 if eager {
557 s.push_str(" eager");
558 }
559 if let Some(named) = import {
560 s.push_str(" import=");
561 s.push_str(named);
562 }
563 if let Some(q) = query {
564 s.push_str(" query=");
565 s.push_str(q);
566 }
567 if let Some(b) = base {
568 s.push_str(" base=");
569 s.push_str(b);
570 }
571 s.into()
572}
573
574#[turbo_tasks::value]
575pub struct ImportMetaGlobAsset {
576 pub origin: ResolvedVc<Box<dyn ResolveOrigin>>,
577 pub patterns: Vec<RcStr>,
578 pub eager: bool,
579 pub import: Option<RcStr>,
580 pub query: Option<RcStr>,
581 pub base: Option<RcStr>,
582 pub issue_source: Option<IssueSource>,
583 pub error_mode: ResolveErrorMode,
584}
585
586#[turbo_tasks::value_impl]
587impl ImportMetaGlobAsset {
588 #[turbo_tasks::function]
595 pub async fn map(&self) -> Result<Vc<ImportMetaGlobMap>> {
596 let origin = *self.origin;
597 let origin_dir = origin.origin_path().await?.parent();
598
599 let base_dir = if let Some(ref b) = self.base {
602 origin_dir.join(b)?
603 } else {
604 origin_dir
605 };
606
607 let (positive_raw, negative_raw): (Vec<_>, Vec<_>) =
610 self.patterns.iter().partition(|p| !p.starts_with('!'));
611
612 let positive_globs: Vec<Vc<Glob>> = positive_raw
616 .iter()
617 .map(|p| Glob::new(strip_relative_prefix(p).into(), GlobOptions::default()))
618 .collect();
619
620 let positive_glob = if positive_globs.len() == 1 {
621 positive_globs.into_iter().next().unwrap()
622 } else {
623 Glob::alternatives(positive_globs)
624 };
625
626 let negative_glob = if !negative_raw.is_empty() {
629 let neg_globs: Vec<Vc<Glob>> = negative_raw
630 .iter()
631 .map(|p| {
632 let stripped = p.strip_prefix('!').unwrap_or(p);
633 let stripped = strip_relative_prefix(stripped);
634 Glob::new(stripped.into(), GlobOptions::default())
635 })
636 .collect();
637
638 let neg = if neg_globs.len() == 1 {
639 neg_globs.into_iter().next().unwrap()
640 } else {
641 Glob::alternatives(neg_globs)
642 };
643 Some(neg)
644 } else {
645 None
646 };
647
648 Ok(ImportMetaGlobMap::generate(
649 origin,
650 base_dir,
651 positive_glob,
652 negative_glob,
653 self.query.clone(),
654 self.eager,
655 self.issue_source,
656 self.error_mode,
657 ))
658 }
659}
660
661#[turbo_tasks::value_impl]
662impl Module for ImportMetaGlobAsset {
663 #[turbo_tasks::function]
664 async fn ident(&self) -> Result<Vc<AssetIdent>> {
665 let origin_path = self.origin.origin_path().owned().await?;
666 Ok(AssetIdent::from_path(origin_path)
667 .with_modifier(modifier(
668 &self.patterns,
669 self.eager,
670 &self.import,
671 &self.query,
672 &self.base,
673 ))
674 .into_vc())
675 }
676
677 #[turbo_tasks::function]
678 fn source(&self) -> Vc<turbopack_core::source::OptionSource> {
679 Vc::cell(None)
680 }
681
682 #[turbo_tasks::function]
683 async fn references(self: Vc<Self>) -> Result<Vc<ModuleReferences>> {
684 let this = self.await?;
685 let map = &*self.map().await?;
686
687 let export = match &this.import {
688 Some(name) => ExportUsage::Named(name.clone()),
689 None => ExportUsage::All,
690 };
691
692 Ok(Vc::cell(
693 map.iter()
694 .map(|(_, entry)| {
695 ResolvedVc::upcast(
696 ImportMetaGlobModuleReference {
697 result: entry.result,
698 export: export.clone(),
699 }
700 .resolved_cell(),
701 )
702 })
703 .collect(),
704 ))
705 }
706
707 #[turbo_tasks::function]
708 fn side_effects(&self) -> Vc<ModuleSideEffects> {
709 if self.eager {
710 ModuleSideEffects::ModuleEvaluationIsSideEffectFree.cell()
714 } else {
715 ModuleSideEffects::SideEffectFree.cell()
718 }
719 }
720}
721
722#[turbo_tasks::value_impl]
723impl ChunkableModule for ImportMetaGlobAsset {
724 #[turbo_tasks::function]
725 fn as_chunk_item(
726 self: ResolvedVc<Self>,
727 module_graph: ResolvedVc<ModuleGraph>,
728 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
729 ) -> Vc<Box<dyn turbopack_core::chunk::ChunkItem>> {
730 ecmascript_chunk_item(ResolvedVc::upcast(self), module_graph, chunking_context)
731 }
732}
733
734#[turbo_tasks::value_impl]
735impl EcmascriptChunkPlaceable for ImportMetaGlobAsset {
736 #[turbo_tasks::function]
737 fn get_exports(&self) -> Vc<EcmascriptExports> {
738 EcmascriptExports::Value.cell()
739 }
740
741 #[turbo_tasks::function]
742 async fn chunk_item_content(
743 self: Vc<Self>,
744 chunking_context: Vc<Box<dyn ChunkingContext>>,
745 _module_graph: Vc<ModuleGraph>,
746 _async_module_info: Option<Vc<AsyncModuleInfo>>,
747 _estimated: bool,
748 ) -> Result<Vc<EcmascriptChunkItemContent>> {
749 let this = self.await?;
750 let map = &*self.map().await?;
751 let minify = chunking_context.minify_type().await?;
752
753 let mut glob_map = ObjectLit {
754 span: DUMMY_SP,
755 props: vec![],
756 };
757
758 for (key, entry) in map {
759 let pm = PatternMapping::resolve_request(
760 *entry.request,
761 *this.origin,
762 chunking_context,
763 *entry.result,
764 ResolveType::ChunkItem,
765 )
766 .await?;
767
768 let PatternMapping::Single(pm) = &*pm else {
769 continue;
770 };
771
772 let key_expr = Expr::Lit(Lit::Str(entry.origin_relative.as_str().into()));
773
774 let value_expr = if this.eager {
776 let module_expr = pm.create_require(Cow::Borrowed(&key_expr));
778 if let Some(named) = &this.import {
780 quote!(
781 "$module[$named]" as Expr,
782 module: Expr = module_expr,
783 named: Expr = Expr::Lit(Lit::Str(named.as_str().into()))
784 )
785 } else {
786 module_expr
787 }
788 } else {
789 let import_expr = pm.create_import(Cow::Borrowed(&key_expr), false);
791 if let Some(named) = &this.import {
792 quote!(
794 "() => $promise.then((m) => m[$named])" as Expr,
795 promise: Expr = import_expr,
796 named: Expr = Expr::Lit(Lit::Str(named.as_str().into()))
797 )
798 } else {
799 quote!(
800 "() => $promise" as Expr,
801 promise: Expr = import_expr
802 )
803 }
804 };
805
806 let prop = KeyValueProp {
809 key: PropName::Str(key.as_str().into()),
810 value: Box::new(value_expr),
811 };
812
813 glob_map
814 .props
815 .push(PropOrSpread::Prop(Box::new(Prop::KeyValue(prop))));
816 }
817
818 let expr = quote_expr!(
819 "$turbopack_export_value($obj);",
820 turbopack_export_value: Expr = TURBOPACK_EXPORT_VALUE.into(),
821 obj: Expr = Expr::Object(glob_map),
822 );
823
824 let module = ast::Module {
825 span: DUMMY_SP,
826 body: vec![ModuleItem::Stmt(Stmt::Expr(ExprStmt {
827 span: DUMMY_SP,
828 expr,
829 }))],
830 shebang: None,
831 };
832
833 let source_map: Arc<swc_core::common::SourceMap> = Default::default();
834
835 let mut bytes: Vec<u8> = vec![];
836 let mut wr: JsWriter<'_, &mut Vec<u8>> =
837 JsWriter::new(source_map.clone(), "\n", &mut bytes, None);
838 if matches!(*minify, MinifyType::Minify { .. }) {
839 wr.set_indent_str("");
840 }
841
842 let mut emitter = Emitter {
843 cfg: swc_core::ecma::codegen::Config::default(),
844 cm: source_map.clone(),
845 comments: None,
846 wr,
847 };
848
849 emitter.emit_module(&module)?;
850
851 Ok(EcmascriptChunkItemContent {
852 inner_code: bytes.into(),
853 ..Default::default()
854 }
855 .cell())
856 }
857}
858
859#[turbo_tasks::value]
864#[derive(Hash, Debug, ValueToString)]
865pub struct ImportMetaGlobAssetReference {
866 pub inner: ResolvedVc<ImportMetaGlobAsset>,
867 pub patterns: Vec<RcStr>,
868}
869
870impl std::fmt::Display for ImportMetaGlobAssetReference {
871 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
872 write!(f, "import.meta.glob {}", self.patterns.join(", "))
873 }
874}
875
876impl ImportMetaGlobAssetReference {
877 pub fn new(
878 origin: ResolvedVc<Box<dyn ResolveOrigin>>,
879 patterns: Vec<RcStr>,
880 eager: bool,
881 import: Option<RcStr>,
882 query: Option<RcStr>,
883 base: Option<RcStr>,
884 issue_source: Option<IssueSource>,
885 error_mode: ResolveErrorMode,
886 ) -> Self {
887 let inner = ImportMetaGlobAsset {
888 origin,
889 patterns: patterns.clone(),
890 eager,
891 import,
892 query,
893 base,
894 issue_source,
895 error_mode,
896 }
897 .resolved_cell();
898
899 ImportMetaGlobAssetReference { inner, patterns }
900 }
901}
902
903#[turbo_tasks::value_impl]
904impl ModuleReference for ImportMetaGlobAssetReference {
905 #[turbo_tasks::function]
906 fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
907 *ModuleResolveResult::module(ResolvedVc::upcast(self.inner))
908 }
909
910 fn chunking_type(&self) -> Option<ChunkingType> {
911 Some(ChunkingType::Parallel {
912 inherit_async: false,
913 hoisted: false,
914 })
915 }
916}
917
918impl IntoCodeGenReference for ImportMetaGlobAssetReference {
919 fn into_code_gen_reference(
920 self,
921 path: AstPath,
922 ) -> (ResolvedVc<Box<dyn ModuleReference>>, CodeGen) {
923 let reference = self.resolved_cell();
924 (
925 ResolvedVc::upcast(reference),
926 CodeGen::ImportMetaGlobAssetReferenceCodeGen(ImportMetaGlobAssetReferenceCodeGen {
927 reference,
928 path,
929 }),
930 )
931 }
932}
933
934#[derive(
939 PartialEq, Eq, TraceRawVcs, ValueDebugFormat, NonLocalValue, Hash, Debug, Encode, Decode,
940)]
941pub struct ImportMetaGlobAssetReferenceCodeGen {
942 path: AstPath,
943 reference: ResolvedVc<ImportMetaGlobAssetReference>,
944}
945
946impl ImportMetaGlobAssetReferenceCodeGen {
947 pub async fn code_generation(
948 &self,
949 chunking_context: Vc<Box<dyn ChunkingContext>>,
950 ) -> Result<CodeGeneration> {
951 let module_id = self
952 .reference
953 .await?
954 .inner
955 .chunk_item_id(chunking_context)
956 .await?;
957
958 let mut visitors = Vec::new();
959 visitors.push(create_visitor!(
960 self.path,
961 visit_mut_expr,
962 |expr: &mut Expr| {
963 if let Expr::Call(_) = expr {
964 *expr = quote!(
966 "$turbopack_require($id)" as Expr,
967 turbopack_require: Expr = TURBOPACK_REQUIRE.into(),
968 id: Expr = module_id_to_lit(&module_id)
969 );
970 }
971 }
972 ));
973 Ok(CodeGeneration::visitors(visitors))
974 }
975}