next.js / crates /next-api /src /route.rs
AbdulElahGwaith's picture
Upload folder using huggingface_hub
b91e262 verified
use std::fmt::Display;
use anyhow::Result;
use bincode::{Decode, Encode};
use turbo_rcstr::RcStr;
use turbo_tasks::{
Completion, FxIndexMap, FxIndexSet, NonLocalValue, OperationVc, ResolvedVc, TryFlatJoinIterExt,
TryJoinIterExt, Vc, debug::ValueDebugFormat, trace::TraceRawVcs,
};
use turbopack_core::{
module_graph::{GraphEntries, ModuleGraph},
output::OutputAssets,
};
use crate::{operation::OptionEndpoint, paths::ServerPath, project::Project};
#[derive(
TraceRawVcs, PartialEq, Eq, ValueDebugFormat, Clone, Debug, NonLocalValue, Encode, Decode,
)]
pub struct AppPageRoute {
pub original_name: RcStr,
pub html_endpoint: ResolvedVc<Box<dyn Endpoint>>,
pub rsc_endpoint: ResolvedVc<Box<dyn Endpoint>>,
}
#[turbo_tasks::value(shared)]
#[derive(Clone, Debug)]
pub enum Route {
Page {
html_endpoint: ResolvedVc<Box<dyn Endpoint>>,
data_endpoint: Option<ResolvedVc<Box<dyn Endpoint>>>,
},
PageApi {
endpoint: ResolvedVc<Box<dyn Endpoint>>,
},
AppPage(Vec<AppPageRoute>),
AppRoute {
original_name: RcStr,
endpoint: ResolvedVc<Box<dyn Endpoint>>,
},
Conflict,
}
#[turbo_tasks::value(transparent)]
pub struct ModuleGraphs(Vec<ResolvedVc<ModuleGraph>>);
#[turbo_tasks::value_trait]
pub trait Endpoint {
#[turbo_tasks::function]
fn output(self: Vc<Self>) -> Vc<EndpointOutput>;
// fn write_to_disk(self: Vc<Self>) -> Vc<EndpointOutputPaths>;
#[turbo_tasks::function]
fn server_changed(self: Vc<Self>) -> Vc<Completion>;
#[turbo_tasks::function]
fn client_changed(self: Vc<Self>) -> Vc<Completion>;
/// The entry modules for the modules graph.
#[turbo_tasks::function]
fn entries(self: Vc<Self>) -> Vc<GraphEntries>;
/// Additional entry modules for the module graph.
/// This may read the module graph and return additional modules.
#[turbo_tasks::function]
fn additional_entries(self: Vc<Self>, _graph: Vc<ModuleGraph>) -> Vc<GraphEntries> {
GraphEntries::empty()
}
#[turbo_tasks::function]
fn module_graphs(self: Vc<Self>) -> Vc<ModuleGraphs>;
}
#[derive(
TraceRawVcs, PartialEq, Eq, ValueDebugFormat, Clone, Debug, NonLocalValue, Encode, Decode,
)]
pub enum EndpointGroupKey {
Instrumentation,
InstrumentationEdge,
Middleware,
PagesError,
PagesApp,
PagesDocument,
Route(RcStr),
}
impl EndpointGroupKey {
pub fn as_str(&self) -> &str {
match self {
EndpointGroupKey::Instrumentation => "instrumentation",
EndpointGroupKey::InstrumentationEdge => "instrumentation-edge",
EndpointGroupKey::Middleware => "middleware",
EndpointGroupKey::PagesError => "_error",
EndpointGroupKey::PagesApp => "_app",
EndpointGroupKey::PagesDocument => "_document",
EndpointGroupKey::Route(route) => route,
}
}
}
impl Display for EndpointGroupKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
EndpointGroupKey::Instrumentation => write!(f, "instrumentation"),
EndpointGroupKey::InstrumentationEdge => write!(f, "instrumentation-edge"),
EndpointGroupKey::Middleware => write!(f, "middleware"),
EndpointGroupKey::PagesError => write!(f, "_error"),
EndpointGroupKey::PagesApp => write!(f, "_app"),
EndpointGroupKey::PagesDocument => write!(f, "_document"),
EndpointGroupKey::Route(route) => write!(f, "{}", route),
}
}
}
#[derive(
TraceRawVcs, PartialEq, Eq, ValueDebugFormat, Clone, Debug, NonLocalValue, Encode, Decode,
)]
pub struct EndpointGroupEntry {
pub endpoint: ResolvedVc<Box<dyn Endpoint>>,
pub sub_name: Option<RcStr>,
}
#[derive(
TraceRawVcs, PartialEq, Eq, ValueDebugFormat, Clone, Debug, NonLocalValue, Encode, Decode,
)]
pub struct EndpointGroup {
pub primary: Vec<EndpointGroupEntry>,
pub additional: Vec<EndpointGroupEntry>,
}
impl EndpointGroup {
pub fn from(endpoint: ResolvedVc<Box<dyn Endpoint>>) -> Self {
Self {
primary: vec![EndpointGroupEntry {
endpoint,
sub_name: None,
}],
additional: vec![],
}
}
pub fn output_assets(&self) -> Vc<OutputAssets> {
output_of_endpoints(
self.primary
.iter()
.map(|endpoint| *endpoint.endpoint)
.collect(),
)
}
pub fn module_graphs(&self) -> Vc<ModuleGraphs> {
module_graphs_of_endpoints(
self.primary
.iter()
.map(|endpoint| *endpoint.endpoint)
.collect(),
)
}
}
#[turbo_tasks::function]
async fn output_of_endpoints(endpoints: Vec<Vc<Box<dyn Endpoint>>>) -> Result<Vc<OutputAssets>> {
let assets = endpoints
.iter()
.map(async |endpoint| Ok(*endpoint.output().await?.output_assets))
.try_join()
.await?;
Ok(OutputAssets::concat(assets))
}
#[turbo_tasks::function]
async fn module_graphs_of_endpoints(
endpoints: Vec<Vc<Box<dyn Endpoint>>>,
) -> Result<Vc<ModuleGraphs>> {
let module_graphs = endpoints
.iter()
.map(async |endpoint| Ok(endpoint.module_graphs().await?.into_iter()))
.try_flat_join()
.await?
.into_iter()
.copied()
.collect::<FxIndexSet<_>>()
.into_iter()
.collect::<Vec<_>>();
Ok(Vc::cell(module_graphs))
}
#[turbo_tasks::value(transparent)]
pub struct EndpointGroups(Vec<(EndpointGroupKey, EndpointGroup)>);
#[turbo_tasks::value(transparent)]
pub struct Endpoints(Vec<ResolvedVc<Box<dyn Endpoint>>>);
#[turbo_tasks::function]
pub async fn endpoint_write_to_disk(
endpoint: ResolvedVc<Box<dyn Endpoint>>,
) -> Result<Vc<EndpointOutputPaths>> {
let output_op = output_assets_operation(endpoint);
let EndpointOutput {
project,
output_paths,
..
} = *output_op.connect().await?;
project
.emit_all_output_assets(endpoint_output_assets_operation(output_op))
.as_side_effect()
.await?;
Ok(*output_paths)
}
#[turbo_tasks::function(operation)]
fn output_assets_operation(endpoint: ResolvedVc<Box<dyn Endpoint>>) -> Vc<EndpointOutput> {
endpoint.output()
}
#[turbo_tasks::function(operation)]
async fn endpoint_output_assets_operation(
output: OperationVc<EndpointOutput>,
) -> Result<Vc<OutputAssets>> {
Ok(*output.connect().await?.output_assets)
}
#[turbo_tasks::function(operation)]
pub async fn endpoint_write_to_disk_operation(
endpoint: OperationVc<OptionEndpoint>,
) -> Result<Vc<EndpointOutputPaths>> {
Ok(if let Some(endpoint) = *endpoint.connect().await? {
endpoint_write_to_disk(*endpoint)
} else {
EndpointOutputPaths::NotFound.cell()
})
}
#[turbo_tasks::function(operation)]
pub async fn endpoint_server_changed_operation(
endpoint: OperationVc<OptionEndpoint>,
) -> Result<Vc<Completion>> {
Ok(if let Some(endpoint) = *endpoint.connect().await? {
endpoint.server_changed()
} else {
Completion::new()
})
}
#[turbo_tasks::function(operation)]
pub async fn endpoint_client_changed_operation(
endpoint: OperationVc<OptionEndpoint>,
) -> Result<Vc<Completion>> {
Ok(if let Some(endpoint) = *endpoint.connect().await? {
endpoint.client_changed()
} else {
Completion::new()
})
}
#[turbo_tasks::value(shared)]
#[derive(Debug, Clone)]
pub struct EndpointOutput {
pub output_assets: ResolvedVc<OutputAssets>,
pub output_paths: ResolvedVc<EndpointOutputPaths>,
pub project: ResolvedVc<Project>,
}
#[turbo_tasks::value(shared)]
#[derive(Debug, Clone)]
pub enum EndpointOutputPaths {
NodeJs {
/// Relative to the root_path
server_entry_path: RcStr,
server_paths: Vec<ServerPath>,
client_paths: Vec<RcStr>,
},
Edge {
server_paths: Vec<ServerPath>,
client_paths: Vec<RcStr>,
},
NotFound,
}
/// The routes as map from pathname to route. (pathname includes the leading
/// slash)
#[turbo_tasks::value(transparent)]
pub struct Routes(#[bincode(with = "turbo_bincode::indexmap")] FxIndexMap<RcStr, Route>);