diff --git a/crates/turbopack-cli/src/build/mod.rs b/crates/turbopack-cli/src/build/mod.rs index 7c8a9b98a2f00..ff5ee97fa7bd5 100644 --- a/crates/turbopack-cli/src/build/mod.rs +++ b/crates/turbopack-cli/src/build/mod.rs @@ -213,12 +213,18 @@ async fn build_internal( .cloned() .map(|r| async move { Ok(match &*r.await? { - EntryRequest::Relative(p) => { - Request::relative(Value::new(p.clone().into()), Default::default(), false) - } - EntryRequest::Module(m, p) => { - Request::module(m.clone(), Value::new(p.clone().into()), Default::default()) - } + EntryRequest::Relative(p) => Request::relative( + Value::new(p.clone().into()), + Default::default(), + Default::default(), + false, + ), + EntryRequest::Module(m, p) => Request::module( + m.clone(), + Value::new(p.clone().into()), + Default::default(), + Default::default(), + ), }) }) .try_join() diff --git a/crates/turbopack-cli/src/dev/mod.rs b/crates/turbopack-cli/src/dev/mod.rs index bd3742020b70c..afcfca7a216d2 100644 --- a/crates/turbopack-cli/src/dev/mod.rs +++ b/crates/turbopack-cli/src/dev/mod.rs @@ -268,12 +268,18 @@ async fn source( let entry_requests = entry_requests .iter() .map(|r| match r { - EntryRequest::Relative(p) => { - Request::relative(Value::new(p.clone().into()), Default::default(), false) - } - EntryRequest::Module(m, p) => { - Request::module(m.clone(), Value::new(p.clone().into()), Default::default()) - } + EntryRequest::Relative(p) => Request::relative( + Value::new(p.clone().into()), + Default::default(), + Default::default(), + false, + ), + EntryRequest::Module(m, p) => Request::module( + m.clone(), + Value::new(p.clone().into()), + Default::default(), + Default::default(), + ), }) .collect(); diff --git a/crates/turbopack-core/src/resolve/mod.rs b/crates/turbopack-core/src/resolve/mod.rs index 7f166b7e1c77a..7953886469e03 100644 --- a/crates/turbopack-core/src/resolve/mod.rs +++ b/crates/turbopack-core/src/resolve/mod.rs @@ -1541,6 +1541,7 @@ async fn resolve_internal_inline( path, query, force_in_lookup_dir, + fragment, } => { let mut results = Vec::new(); let matches = read_matches( @@ -1563,6 +1564,7 @@ async fn resolve_internal_inline( options_value, options, *query, + *fragment, ) .await?, ); @@ -1582,6 +1584,7 @@ async fn resolve_internal_inline( path, query, force_in_lookup_dir, + fragment, } => { resolve_relative_request( lookup_path, @@ -1591,6 +1594,7 @@ async fn resolve_internal_inline( path, *query, *force_in_lookup_dir, + *fragment, ) .await? } @@ -1598,6 +1602,7 @@ async fn resolve_internal_inline( module, path, query, + fragment, } => { resolve_module_request( lookup_path, @@ -1607,13 +1612,18 @@ async fn resolve_internal_inline( module, path, *query, + *fragment, ) .await? } - Request::ServerRelative { path, query } => { + Request::ServerRelative { + path, + query, + fragment, + } => { let mut new_pat = path.clone(); new_pat.push_front(".".to_string().into()); - let relative = Request::relative(Value::new(new_pat), *query, true); + let relative = Request::relative(Value::new(new_pat), *query, *fragment, true); if !has_alias { ResolvingIssue { @@ -1640,7 +1650,11 @@ async fn resolve_internal_inline( ) .await? } - Request::Windows { path: _, query: _ } => { + Request::Windows { + path: _, + query: _, + fragment: _, + } => { if !has_alias { ResolvingIssue { severity: IssueSeverity::Error.cell(), @@ -1684,6 +1698,8 @@ async fn resolve_internal_inline( Request::Uri { protocol, remainder, + query: _, + fragment: _, } => { let uri = format!("{}{}", protocol, remainder); ResolveResult::primary_with_key( @@ -1818,6 +1834,7 @@ async fn resolve_relative_request( path_pattern: &Pattern, query: Vc, force_in_lookup_dir: bool, + fragment: Vc, ) -> Result> { // Check alias field for aliases first let lookup_path_ref = &*lookup_path.await?; @@ -1832,6 +1849,7 @@ async fn resolve_relative_request( Some(request) }, query, + fragment, ) .await? { @@ -1882,6 +1900,7 @@ async fn resolve_relative_request( options_value, options, query, + fragment, ) .await?, ); @@ -1899,6 +1918,7 @@ async fn resolve_relative_request( options_value, options, query, + fragment, ) .await?, ); @@ -1922,6 +1942,7 @@ async fn apply_in_package( options_value: &ResolveOptions, get_request: impl Fn(&FileSystemPath) -> Option, query: Vc, + fragment: Vc, ) -> Result>> { // Check alias field for module aliases first for in_package in options_value.in_package.iter() { @@ -1987,7 +2008,8 @@ async fn apply_in_package( resolve_internal( package_path, Request::parse(Value::new(Pattern::Constant(value.to_string()))) - .with_query(query), + .with_query(query) + .with_fragment(fragment), options, ) .with_replaced_request_key(value.to_string(), Value::new(request_key)) @@ -2023,6 +2045,7 @@ async fn resolve_module_request( module: &str, path: &Pattern, query: Vc, + fragment: Vc, ) -> Result> { // Check alias field for module aliases first if let Some(result) = apply_in_package( @@ -2034,6 +2057,7 @@ async fn resolve_module_request( full_pattern.into_string() }, query, + fragment, ) .await? { @@ -2068,6 +2092,7 @@ async fn resolve_module_request( Value::new(path.clone()), package_path, query, + fragment, options, )); } @@ -2081,6 +2106,7 @@ async fn resolve_module_request( options_value, options, query, + fragment, ) .await?; results.push(resolved) @@ -2103,7 +2129,7 @@ async fn resolve_module_request( "/".to_string().into(), path.clone(), ]); - let relative = Request::relative(Value::new(pattern), query, true); + let relative = Request::relative(Value::new(pattern), query, fragment, true); let relative_result = resolve_internal_boxed(lookup_path, relative.resolve().await?, options).await?; let relative_result = relative_result.with_replaced_request_key( @@ -2122,6 +2148,7 @@ async fn resolve_into_package( path: Value, package_path: Vc, query: Vc, + fragment: Vc, options: Vc, ) -> Result> { let path = path.into_value(); @@ -2186,7 +2213,7 @@ async fn resolve_into_package( let mut new_pat = path.clone(); new_pat.push_front(".".to_string().into()); - let relative = Request::relative(Value::new(new_pat), query, true); + let relative = Request::relative(Value::new(new_pat), query, fragment, true); results .push(resolve_internal_inline(package_path, relative.resolve().await?, options).await?); } @@ -2270,6 +2297,7 @@ async fn resolved( options_value: &ResolveOptions, options: Vc, query: Vc, + fragment: Vc, ) -> Result> { let RealPathResult { path, symlinks } = &*fs_path.realpath_with_links().await?; @@ -2281,6 +2309,7 @@ async fn resolved( options_value, |package_path| package_path.get_relative_path_to(path_ref), query, + fragment, ) .await? { diff --git a/crates/turbopack-core/src/resolve/parse.rs b/crates/turbopack-core/src/resolve/parse.rs index bf72046401398..baf6256ce752d 100644 --- a/crates/turbopack-core/src/resolve/parse.rs +++ b/crates/turbopack-core/src/resolve/parse.rs @@ -12,24 +12,29 @@ pub enum Request { path: Pattern, query: Vc, force_in_lookup_dir: bool, + fragment: Vc, }, Relative { path: Pattern, query: Vc, force_in_lookup_dir: bool, + fragment: Vc, }, Module { module: String, path: Pattern, query: Vc, + fragment: Vc, }, ServerRelative { path: Pattern, query: Vc, + fragment: Vc, }, Windows { path: Pattern, query: Vc, + fragment: Vc, }, Empty, PackageInternal { @@ -38,6 +43,8 @@ pub enum Request { Uri { protocol: String, remainder: String, + query: Vc, + fragment: Vc, }, Unknown { path: Pattern, @@ -48,14 +55,29 @@ pub enum Request { }, } -fn split_off_query(raw: String) -> (Pattern, Vc) { +fn split_off_query_fragment(raw: String) -> (Pattern, Vc, Vc) { let Some((raw, query)) = raw.split_once('?') else { - return (Pattern::Constant(raw), Vc::::default()); + if let Some((raw, fragment)) = raw.split_once('#') { + return ( + Pattern::Constant(raw.to_string()), + Vc::::default(), + Vc::cell(fragment.to_string()), + ); + } + + return ( + Pattern::Constant(raw), + Vc::::default(), + Vc::::default(), + ); }; + let (query, fragment) = query.split_once('#').unwrap_or((query, "")); + ( Pattern::Constant(raw.to_string()), Vc::cell(format!("?{}", query)), + Vc::cell(format!("#{}", fragment)), ) } @@ -91,6 +113,7 @@ impl Request { Request::Uri { protocol, remainder, + .. } => format!("{protocol}{remainder}"), Request::Unknown { path: Pattern::Constant(path), @@ -107,20 +130,25 @@ impl Request { if r.is_empty() { Request::Empty } else if r.starts_with('/') { - let (path, query) = split_off_query(r); + let (path, query, fragment) = split_off_query_fragment(r); - Request::ServerRelative { path, query } + Request::ServerRelative { + path, + query, + fragment, + } } else if r.starts_with('#') { Request::PackageInternal { path: Pattern::Constant(r), } } else if r.starts_with("./") || r.starts_with("../") || r == "." || r == ".." { - let (path, query) = split_off_query(r); + let (path, query, fragment) = split_off_query_fragment(r); Request::Relative { path, force_in_lookup_dir: false, query, + fragment, } } else { lazy_static! { @@ -131,9 +159,13 @@ impl Request { } if WINDOWS_PATH.is_match(&r) { - let (path, query) = split_off_query(r); + let (path, query, fragment) = split_off_query_fragment(r); - return Request::Windows { path, query }; + return Request::Windows { + path, + query, + fragment, + }; } if let Some(caps) = URI_PATH.captures(&r) { @@ -142,6 +174,8 @@ impl Request { return Request::Uri { protocol: protocol.as_str().to_string(), remainder: remainder.as_str().to_string(), + query: Vc::::default(), + fragment: Vc::::default(), }; } } @@ -150,12 +184,14 @@ impl Request { .captures(&r) .and_then(|caps| caps.get(1).zip(caps.get(2))) { - let (path, query) = split_off_query(path.as_str().to_string()); + let (path, query, fragment) = + split_off_query_fragment(path.as_str().to_string()); return Request::Module { module: module.as_str().to_string(), path, query, + fragment, }; } @@ -228,11 +264,17 @@ impl Request { } #[turbo_tasks::function] - pub fn raw(request: Value, query: Vc, force_in_lookup_dir: bool) -> Vc { + pub fn raw( + request: Value, + query: Vc, + fragment: Vc, + force_in_lookup_dir: bool, + ) -> Vc { Self::cell(Request::Raw { path: request.into_value(), force_in_lookup_dir, query, + fragment, }) } @@ -240,21 +282,29 @@ impl Request { pub fn relative( request: Value, query: Vc, + fragment: Vc, force_in_lookup_dir: bool, ) -> Vc { Self::cell(Request::Relative { path: request.into_value(), force_in_lookup_dir, query, + fragment, }) } #[turbo_tasks::function] - pub fn module(module: String, path: Value, query: Vc) -> Vc { + pub fn module( + module: String, + path: Value, + query: Vc, + fragment: Vc, + ) -> Vc { Self::cell(Request::Module { module, path: path.into_value(), query, + fragment, }) } @@ -273,6 +323,7 @@ impl Request { module, path, query: _, + fragment: _, } => { let mut pat = Pattern::Constant(format!("./{module}")); pat.push(path.clone()); @@ -303,40 +354,56 @@ impl Request { path, query: _, force_in_lookup_dir, + fragment, } => Request::Raw { path: path.clone(), query, force_in_lookup_dir: *force_in_lookup_dir, + fragment: *fragment, } .cell(), Request::Relative { path, query: _, force_in_lookup_dir, + fragment, } => Request::Relative { path: path.clone(), query, force_in_lookup_dir: *force_in_lookup_dir, + fragment: *fragment, } .cell(), Request::Module { module, path, query: _, + fragment, } => Request::Module { module: module.clone(), path: path.clone(), query, + fragment: *fragment, } .cell(), - Request::ServerRelative { path, query: _ } => Request::ServerRelative { + Request::ServerRelative { + path, + query: _, + fragment, + } => Request::ServerRelative { path: path.clone(), query, + fragment: *fragment, } .cell(), - Request::Windows { path, query: _ } => Request::Windows { + Request::Windows { + path, + query: _, + fragment, + } => Request::Windows { path: path.clone(), query, + fragment: *fragment, } .cell(), Request::Empty => self, @@ -355,6 +422,81 @@ impl Request { }) } + #[turbo_tasks::function] + pub async fn with_fragment(self: Vc, fragment: Vc) -> Result> { + Ok(match &*self.await? { + Request::Raw { + path, + query, + force_in_lookup_dir, + fragment: _, + } => Request::Raw { + path: path.clone(), + query: *query, + force_in_lookup_dir: *force_in_lookup_dir, + fragment, + } + .cell(), + Request::Relative { + path, + query, + force_in_lookup_dir, + fragment: _, + } => Request::Relative { + path: path.clone(), + query: *query, + force_in_lookup_dir: *force_in_lookup_dir, + fragment, + } + .cell(), + Request::Module { + module, + path, + query, + fragment: _, + } => Request::Module { + module: module.clone(), + path: path.clone(), + query: *query, + fragment, + } + .cell(), + Request::ServerRelative { + path, + query, + fragment: _, + } => Request::ServerRelative { + path: path.clone(), + query: *query, + fragment, + } + .cell(), + Request::Windows { + path, + query, + fragment: _, + } => Request::Windows { + path: path.clone(), + query: *query, + fragment, + } + .cell(), + Request::Empty => self, + Request::PackageInternal { .. } => self, + Request::Uri { .. } => self, + Request::Unknown { .. } => self, + Request::Dynamic => self, + Request::Alternatives { requests } => { + let requests = requests + .iter() + .copied() + .map(|req| req.with_fragment(fragment)) + .collect(); + Request::Alternatives { requests }.cell() + } + }) + } + #[turbo_tasks::function] pub async fn append_path(self: Vc, suffix: String) -> Result> { Ok(match &*self.await? { @@ -362,44 +504,57 @@ impl Request { path, query, force_in_lookup_dir, + fragment, } => { let mut pat = Pattern::concat([path.clone(), suffix.into()]); pat.normalize(); - Self::raw(Value::new(pat), *query, *force_in_lookup_dir) + Self::raw(Value::new(pat), *query, *fragment, *force_in_lookup_dir) } Request::Relative { path, query, force_in_lookup_dir, + fragment, } => { let mut pat = Pattern::concat([path.clone(), suffix.into()]); pat.normalize(); - Self::relative(Value::new(pat), *query, *force_in_lookup_dir) + Self::relative(Value::new(pat), *query, *fragment, *force_in_lookup_dir) } Request::Module { module, path, query, + fragment, } => { let mut pat = Pattern::concat([path.clone(), suffix.into()]); pat.normalize(); - Self::module(module.clone(), Value::new(pat), *query) + Self::module(module.clone(), Value::new(pat), *query, *fragment) } - Request::ServerRelative { path, query } => { + Request::ServerRelative { + path, + query, + fragment, + } => { let mut pat = Pattern::concat([path.clone(), suffix.into()]); pat.normalize(); Self::ServerRelative { path: pat, query: *query, + fragment: *fragment, } .cell() } - Request::Windows { path, query } => { + Request::Windows { + path, + query, + fragment, + } => { let mut pat = Pattern::concat([path.clone(), suffix.into()]); pat.normalize(); Self::Windows { path: pat, query: *query, + fragment: *fragment, } .cell() } @@ -412,11 +567,15 @@ impl Request { Request::Uri { protocol, remainder, + query, + fragment, } => { let remainder = format!("{}{}", remainder, suffix); Self::Uri { protocol: protocol.clone(), remainder, + query: *query, + fragment: *fragment, } .cell() } @@ -496,6 +655,7 @@ impl ValueToString for Request { Request::Uri { protocol, remainder, + .. } => format!("uri \"{protocol}\" \"{remainder}\""), Request::Unknown { path } => format!("unknown {path}"), Request::Dynamic => "dynamic".to_string(), diff --git a/crates/turbopack-css/src/references/import.rs b/crates/turbopack-css/src/references/import.rs index 3ca477432f8ce..48607176cdc8d 100644 --- a/crates/turbopack-css/src/references/import.rs +++ b/crates/turbopack-css/src/references/import.rs @@ -264,6 +264,7 @@ impl CodeGenerateable for ImportAssetReference { if let Request::Uri { protocol, remainder, + .. } = &*this.request.await? { imports.push(CssImport::External(Vc::cell(format!( diff --git a/crates/turbopack-ecmascript/src/references/typescript.rs b/crates/turbopack-ecmascript/src/references/typescript.rs index ede39fbbcd498..e481d01c02e28 100644 --- a/crates/turbopack-ecmascript/src/references/typescript.rs +++ b/crates/turbopack-ecmascript/src/references/typescript.rs @@ -131,6 +131,7 @@ impl ModuleReference for TsReferenceTypeAssetReference { self.module.clone(), Value::new("".to_string().into()), Vc::::default(), + Vc::::default(), ), ) } diff --git a/crates/turbopack-ecmascript/src/typescript/mod.rs b/crates/turbopack-ecmascript/src/typescript/mod.rs index e35afaf795f5a..d8cb607ca092c 100644 --- a/crates/turbopack-ecmascript/src/typescript/mod.rs +++ b/crates/turbopack-ecmascript/src/typescript/mod.rs @@ -145,6 +145,7 @@ impl Module for TsConfigModuleAsset { name, Value::new("".to_string().into()), Vc::::default(), + Vc::::default(), ), ))); } diff --git a/crates/turbopack-resolve/src/typescript.rs b/crates/turbopack-resolve/src/typescript.rs index 0f6d614dceff6..a781287fef8e5 100644 --- a/crates/turbopack-resolve/src/typescript.rs +++ b/crates/turbopack-resolve/src/typescript.rs @@ -374,6 +374,7 @@ pub async fn type_resolve( module: m, path: p, query: _, + fragment: _, } = &*request.await? { let m = if let Some(stripped) = m.strip_prefix('@') { @@ -385,6 +386,7 @@ pub async fn type_resolve( format!("@types/{m}"), Value::new(p.clone()), Vc::::default(), + Vc::::default(), )) } else { None