diff --git a/crates/next-core/src/lib.rs b/crates/next-core/src/lib.rs index bcdaf709d9d221..995324669edea3 100644 --- a/crates/next-core/src/lib.rs +++ b/crates/next-core/src/lib.rs @@ -27,7 +27,6 @@ mod next_import_map; pub mod next_manifests; pub mod next_pages; mod next_root_params; -mod next_route_matcher; pub mod next_server; pub mod next_server_component; pub mod next_server_utility; diff --git a/crates/next-core/src/next_route_matcher/all.rs b/crates/next-core/src/next_route_matcher/all.rs deleted file mode 100644 index 5839a948626e82..00000000000000 --- a/crates/next-core/src/next_route_matcher/all.rs +++ /dev/null @@ -1,15 +0,0 @@ -use serde::{Deserialize, Serialize}; -use turbopack_node::route_matcher::{Params, RouteMatcherRef}; - -#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)] -pub struct AllMatch; - -impl RouteMatcherRef for AllMatch { - fn matches(&self, _path: &str) -> bool { - true - } - - fn params(&self, _path: &str) -> Params { - Params(Some(Default::default())) - } -} diff --git a/crates/next-core/src/next_route_matcher/mod.rs b/crates/next-core/src/next_route_matcher/mod.rs deleted file mode 100644 index 9593930ee43c09..00000000000000 --- a/crates/next-core/src/next_route_matcher/mod.rs +++ /dev/null @@ -1,182 +0,0 @@ -use anyhow::{Result, bail}; -use turbo_rcstr::RcStr; -use turbo_tasks::{ResolvedVc, Vc}; -use turbopack_node::route_matcher::{Params, RouteMatcher, RouteMatcherRef}; - -use self::{ - all::AllMatch, - path_regex::{PathRegex, PathRegexBuilder}, - prefix_suffix::PrefixSuffixMatcher, -}; - -mod all; -mod path_regex; -mod prefix_suffix; - -/// A route matcher that matches a path against an exact route. -#[turbo_tasks::value] -pub(crate) struct NextExactMatcher { - path: ResolvedVc, -} - -#[turbo_tasks::value_impl] -impl NextExactMatcher { - #[turbo_tasks::function] - pub fn new(path: ResolvedVc) -> Vc { - Self::cell(NextExactMatcher { path }) - } -} - -#[turbo_tasks::value_impl] -impl RouteMatcher for NextExactMatcher { - #[turbo_tasks::function] - async fn matches(&self, path: RcStr) -> Result> { - Ok(Vc::cell(path == *self.path.await?)) - } - - #[turbo_tasks::function] - async fn params(&self, path: RcStr) -> Result> { - Ok(Vc::cell(if path == *self.path.await? { - Some(Default::default()) - } else { - None - })) - } -} - -/// A route matcher that matches a path against a route regex. -#[turbo_tasks::value] -pub(crate) struct NextParamsMatcher { - #[turbo_tasks(trace_ignore)] - matcher: PathRegex, -} - -#[turbo_tasks::value_impl] -impl NextParamsMatcher { - #[turbo_tasks::function] - pub async fn new(path: ResolvedVc) -> Result> { - Ok(Self::cell(NextParamsMatcher { - matcher: build_path_regex(path.await?.as_str())?, - })) - } -} - -#[turbo_tasks::value_impl] -impl RouteMatcher for NextParamsMatcher { - #[turbo_tasks::function] - fn matches(&self, path: RcStr) -> Vc { - Vc::cell(self.matcher.matches(&path)) - } - - #[turbo_tasks::function] - fn params(&self, path: RcStr) -> Vc { - Params::cell(self.matcher.params(&path)) - } -} - -/// A route matcher that strips a prefix and a suffix from a path before -/// matching it against a route regex. -#[turbo_tasks::value] -pub(crate) struct NextPrefixSuffixParamsMatcher { - #[turbo_tasks(trace_ignore)] - matcher: PrefixSuffixMatcher, -} - -#[turbo_tasks::value_impl] -impl NextPrefixSuffixParamsMatcher { - /// Converts a filename within the server root into a regular expression - /// with named capture groups for every dynamic segment. - #[turbo_tasks::function] - pub async fn new(path: ResolvedVc, prefix: RcStr, suffix: RcStr) -> Result> { - Ok(Self::cell(NextPrefixSuffixParamsMatcher { - matcher: PrefixSuffixMatcher::new( - prefix.to_string(), - suffix.to_string(), - build_path_regex(path.await?.as_str())?, - ), - })) - } -} - -#[turbo_tasks::value_impl] -impl RouteMatcher for NextPrefixSuffixParamsMatcher { - #[turbo_tasks::function] - fn matches(&self, path: RcStr) -> Vc { - Vc::cell(self.matcher.matches(&path)) - } - - #[turbo_tasks::function] - fn params(&self, path: RcStr) -> Vc { - Params::cell(self.matcher.params(&path)) - } -} - -/// A route matcher that matches against all paths. -#[turbo_tasks::value] -pub(crate) struct NextFallbackMatcher { - #[turbo_tasks(trace_ignore)] - matcher: AllMatch, -} - -#[turbo_tasks::value_impl] -impl NextFallbackMatcher { - #[turbo_tasks::function] - pub fn new() -> Vc { - Self::cell(NextFallbackMatcher { matcher: AllMatch }) - } -} - -#[turbo_tasks::value_impl] -impl RouteMatcher for NextFallbackMatcher { - #[turbo_tasks::function] - fn matches(&self, path: RcStr) -> Vc { - Vc::cell(self.matcher.matches(&path)) - } - - #[turbo_tasks::function] - fn params(&self, path: RcStr) -> Vc { - Params::cell(self.matcher.params(&path)) - } -} - -/// Converts a filename within the server root into a regular expression -/// with named capture groups for every dynamic segment. -fn build_path_regex(path: &str) -> Result { - let mut path_regex = PathRegexBuilder::new(); - for segment in path.split('/') { - if let Some(segment) = segment.strip_prefix('[') { - if let Some(segment) = segment.strip_prefix("[...") { - if let Some((placeholder, rem)) = segment.split_once("]]") { - path_regex.push_optional_catch_all(placeholder, rem); - } else { - bail!( - "path ({}) contains '[[' without matching ']]' at '[[...{}'", - path, - segment - ); - } - } else if let Some(segment) = segment.strip_prefix("...") { - if let Some((placeholder, rem)) = segment.split_once(']') { - path_regex.push_catch_all(placeholder, rem); - } else { - bail!( - "path ({}) contains '[' without matching ']' at '[...{}'", - path, - segment - ); - } - } else if let Some((placeholder, rem)) = segment.split_once(']') { - path_regex.push_dynamic_segment(placeholder, rem); - } else { - bail!( - "path ({}) contains '[' without matching ']' at '[{}'", - path, - segment - ); - } - } else { - path_regex.push_static_segment(segment); - } - } - path_regex.build() -} diff --git a/crates/next-core/src/next_route_matcher/path_regex.rs b/crates/next-core/src/next_route_matcher/path_regex.rs deleted file mode 100644 index ec5b5a37925800..00000000000000 --- a/crates/next-core/src/next_route_matcher/path_regex.rs +++ /dev/null @@ -1,166 +0,0 @@ -use anyhow::{Context, Result}; -use serde::{Deserialize, Serialize}; -use turbo_tasks::primitives::Regex; -use turbopack_node::route_matcher::{Param, Params, RouteMatcherRef}; - -/// A regular expression that matches a path, with named capture groups for the -/// dynamic parts of the path. -#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)] -pub struct PathRegex { - regex: Regex, - named_params: Vec, -} - -#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)] -struct NamedParam { - name: String, - kind: NamedParamKind, -} - -#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)] -enum NamedParamKind { - Single, - Multi, -} - -impl std::fmt::Display for PathRegex { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.regex.as_str()) - } -} - -impl RouteMatcherRef for PathRegex { - fn matches(&self, path: &str) -> bool { - self.regex.is_match(path) - } - - fn params(&self, path: &str) -> Params { - Params(self.regex.captures(path).map(|capture| { - self.named_params - .iter() - .enumerate() - .filter_map(|(idx, param)| { - if param.name.is_empty() { - return None; - } - let value = capture.get(idx + 1)?; - Some(( - param.name.as_str().into(), - match param.kind { - NamedParamKind::Single => Param::Single(value.as_str().into()), - NamedParamKind::Multi => Param::Multi( - value - .as_str() - .split('/') - .map(|segment| segment.into()) - .collect(), - ), - }, - )) - }) - .collect() - })) - } -} - -/// Builder for [PathRegex]. -pub struct PathRegexBuilder { - regex_str: String, - named_params: Vec, -} - -impl PathRegexBuilder { - /// Creates a new [PathRegexBuilder]. - pub fn new() -> Self { - Self { - regex_str: "^".to_string(), - named_params: Default::default(), - } - } - - fn include_slash(&self) -> bool { - self.regex_str.len() > 1 - } - - fn push_str(&mut self, str: &str) { - self.regex_str.push_str(str); - } - - /// Pushes an optional catch all segment to the regex. - pub fn push_optional_catch_all(&mut self, name: N, rem: R) - where - N: Into, - R: AsRef, - { - self.push_str(if self.include_slash() { - "(?:/([^?]+))?" - } else { - "([^?]+)?" - }); - self.push_str(®ex::escape(rem.as_ref())); - self.named_params.push(NamedParam { - name: name.into(), - kind: NamedParamKind::Multi, - }); - } - - /// Pushes a catch all segment to the regex. - pub fn push_catch_all(&mut self, name: N, rem: R) - where - N: Into, - R: AsRef, - { - if self.include_slash() { - self.push_str("/"); - } - self.push_str("([^?]+)"); - self.push_str(®ex::escape(rem.as_ref())); - self.named_params.push(NamedParam { - name: name.into(), - kind: NamedParamKind::Multi, - }); - } - - /// Pushes a dynamic segment to the regex. - pub fn push_dynamic_segment(&mut self, name: N, rem: R) - where - N: Into, - R: AsRef, - { - if self.include_slash() { - self.push_str("/"); - } - self.push_str("([^?/]+)"); - self.push_str(®ex::escape(rem.as_ref())); - self.named_params.push(NamedParam { - name: name.into(), - kind: NamedParamKind::Single, - }); - } - - /// Pushes a static segment to the regex. - pub fn push_static_segment(&mut self, segment: S) - where - S: AsRef, - { - if self.include_slash() { - self.push_str("/"); - } - self.push_str(®ex::escape(segment.as_ref())); - } - - /// Builds and returns the [PathRegex]. - pub fn build(mut self) -> Result { - self.regex_str += "$"; - Ok(PathRegex { - regex: Regex(regex::Regex::new(&self.regex_str).with_context(|| "invalid path regex")?), - named_params: self.named_params, - }) - } -} - -impl Default for PathRegexBuilder { - fn default() -> Self { - Self::new() - } -} diff --git a/crates/next-core/src/next_route_matcher/prefix_suffix.rs b/crates/next-core/src/next_route_matcher/prefix_suffix.rs deleted file mode 100644 index a87271c3d564e9..00000000000000 --- a/crates/next-core/src/next_route_matcher/prefix_suffix.rs +++ /dev/null @@ -1,54 +0,0 @@ -use serde::{Deserialize, Serialize}; -use turbopack_node::route_matcher::{Params, RouteMatcherRef}; - -/// A composite route matcher that matches a path if it has a given prefix and -/// suffix. -#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)] -pub struct PrefixSuffixMatcher -where - T: RouteMatcherRef, -{ - prefix: String, - suffix: String, - inner: T, -} - -impl PrefixSuffixMatcher -where - T: RouteMatcherRef, -{ - /// Creates a new [PrefixSuffixMatcher]. - pub fn new(prefix: String, suffix: String, inner: T) -> Self { - Self { - prefix, - suffix, - inner, - } - } - - fn strip_prefix_and_suffix<'b>(&self, path: &'b str) -> Option<&'b str> { - path.strip_prefix(self.prefix.as_str())? - .strip_suffix(self.suffix.as_str()) - } -} - -impl RouteMatcherRef for PrefixSuffixMatcher -where - T: RouteMatcherRef, -{ - fn matches(&self, path: &str) -> bool { - if let Some(path) = self.strip_prefix_and_suffix(path) { - self.inner.matches(path) - } else { - false - } - } - - fn params(&self, path: &str) -> Params { - if let Some(path) = self.strip_prefix_and_suffix(path) { - self.inner.params(path) - } else { - Params(None) - } - } -} diff --git a/turbopack/crates/turbopack-node/src/lib.rs b/turbopack/crates/turbopack-node/src/lib.rs index a60998b22eada5..ba0fb54f6b68e0 100644 --- a/turbopack/crates/turbopack-node/src/lib.rs +++ b/turbopack/crates/turbopack-node/src/lib.rs @@ -32,7 +32,6 @@ pub mod evaluate; pub mod execution_context; mod heap_queue; mod pool; -pub mod route_matcher; pub mod source_map; pub mod transforms; diff --git a/turbopack/crates/turbopack-node/src/route_matcher.rs b/turbopack/crates/turbopack-node/src/route_matcher.rs deleted file mode 100644 index e8807097b1d96e..00000000000000 --- a/turbopack/crates/turbopack-node/src/route_matcher.rs +++ /dev/null @@ -1,35 +0,0 @@ -use turbo_rcstr::RcStr; -use turbo_tasks::{FxIndexMap, Vc}; - -#[turbo_tasks::value] -#[derive(Debug, Clone)] -#[serde(untagged)] -pub enum Param { - Single(RcStr), - Multi(Vec), -} - -#[turbo_tasks::value(transparent)] -#[derive(Debug, Clone)] -pub struct Params(pub Option>); - -/// Extracts parameters from a URL path. -pub trait RouteMatcherRef { - /// Returns whether the given path is a match for the route. - fn matches(&self, path: &str) -> bool; - - /// Returns the parameters extracted from the given path. - fn params(&self, path: &str) -> Params; -} - -/// Extracts parameters from a URL path (Vc version) -#[turbo_tasks::value_trait] -pub trait RouteMatcher { - /// Returns whether the given path is a match for the route. - #[turbo_tasks::function] - fn matches(self: Vc, path: RcStr) -> Vc; - - /// Returns the parameters extracted from the given path. - #[turbo_tasks::function] - fn params(self: Vc, path: RcStr) -> Vc; -}