docs(turbopack): Fix all warnings in cargo doc --no-deps --workspace, and run rustdoc as part of our CI checks (#91339)

This gets `cargo doc` clean, and enables it in CI so that we won't regress it (I'm open to removing this if it proves to be annoying).

I also cleaned up some documentation and even found some dead code (deleted `turbopack/crates/turbopack-dev-server/src/source/conditional.rs`).
This commit is contained in:
Benjamin Woodruff
2026-03-16 16:42:24 -07:00
committed by GitHub
parent 0f867bb219
commit 924d39dcef
51 changed files with 357 additions and 487 deletions
@@ -98,6 +98,12 @@ pub fn root_task_dispose(
Ok(())
}
/// [Peeks] at the [`Issue`] held by the given source and returns it as a [`PlainDiagnostic`].
/// It does not [consume] any [`Issue`]s held by the source.
///
/// [Peeks]: turbo_tasks::CollectiblesSource::peek_collectibles
/// [`Issue`]: turbopack_core::issue::Issue
/// [consume]: turbo_tasks::CollectiblesSource::take_collectibles
pub async fn get_issues<T: Send>(
source: OperationVc<T>,
filter: Vc<IssueFilter>,
@@ -107,10 +113,11 @@ pub async fn get_issues<T: Send>(
))
}
/// Reads the [turbopack_core::diagnostics::Diagnostic] held
/// by the given source and returns it as a
/// [turbopack_core::diagnostics::PlainDiagnostic]. It does
/// not consume any Diagnostics held by the source.
/// [Peeks] at the [`Diagnostic`]s held by the given source and returns it as a [`PlainDiagnostic`].
/// It does not [consume] any [`Diagnostic`]s held by the source.
///
/// [Peeks]: turbo_tasks::CollectiblesSource::peek_collectibles
/// [consume]: turbo_tasks::CollectiblesSource::take_collectibles
pub async fn get_diagnostics<T: Send>(
source: OperationVc<T>,
) -> Result<Arc<Vec<ReadRef<PlainDiagnostic>>>> {
+7 -4
View File
@@ -70,10 +70,13 @@ pub const NODE_EXTERNALS: [&str; 68] = [
"zlib",
];
/// List of node.js internals that are supported by edge runtime.
/// If anything Node.js builtin module apart from these these imports are
/// used and user does not provide alias for the polyfill, a runtime error will be thrown.
/// See https://vercel.com/docs/functions/runtimes/edge-runtime#compatible-node.js-modules
/// The Node.js built-in modules that are supported by edge runtime.
///
/// If any Node.js builtin module apart from these these imports are used and the user does not
/// provide an alias for it (i.e. a polyfill), a runtime error will be thrown.
///
/// See <https://vercel.com/docs/functions/runtimes/edge-runtime#compatible-node.js-modules>
//
// SAFETY: This has to be sorted alphabetically since we are doing binary search on it
pub const EDGE_NODE_EXTERNALS: [&str; 7] = [
"assert",
+2 -1
View File
@@ -16,8 +16,9 @@
"build-native-wasi": "npx --package=@napi-rs/[email protected] napi build --platform --target wasm32-wasip1-threads -p next-napi-bindings --cwd ../../ --output-dir packages/next-swc/native --no-default-features",
"build-wasm": "wasm-pack build ../../crates/wasm --scope=next",
"cache-build-native": "[ -d native ] && echo $(ls native)",
"rust-check-fmt": "cd ../..; cargo fmt -- --check",
"rust-check-clippy": "cargo clippy --workspace --all-targets -- -D warnings -A deprecated",
"rust-check-doc": "RUSTDOCFLAGS='-Zunstable-options --output-format=json' cargo doc --no-deps --workspace",
"rust-check-fmt": "cd ../..; cargo fmt -- --check",
"rust-check-napi": "cargo check -p next-napi-bindings",
"test-cargo-unit": "cargo nextest run --workspace --exclude next-napi-bindings --exclude turbo-tasks-macros --cargo-profile release-with-assertions-no-lto --no-fail-fast"
},
+28 -12
View File
@@ -136,7 +136,34 @@
"outputs": ["native/*.node", "native/index.d.ts"],
},
"rust-check": {
"dependsOn": ["rust-check-fmt", "rust-check-clippy", "rust-check-napi"],
"dependsOn": [
"rust-check-clippy",
"rust-check-doc",
"rust-check-fmt",
"rust-check-napi",
],
},
"rust-check-clippy": {
"inputs": [
"../../.cargo/**",
"../../crates/**",
"../../turbopack/crates/**",
"../../**/Cargo.toml",
"../../**/Cargo.lock",
"../../.github/workflows/build_and_deploy.yml",
"../../rust-toolchain.toml",
],
},
"rust-check-doc": {
"inputs": [
"../../.cargo/**",
"../../crates/**",
"../../turbopack/crates/**",
"../../**/Cargo.toml",
"../../**/Cargo.lock",
"../../.github/workflows/build_and_deploy.yml",
"../../rust-toolchain.toml",
],
},
"rust-check-fmt": {
"inputs": [
@@ -150,17 +177,6 @@
],
"cache": false,
},
"rust-check-clippy": {
"inputs": [
"../../.cargo/**",
"../../crates/**",
"../../turbopack/crates/**",
"../../**/Cargo.toml",
"../../**/Cargo.lock",
"../../.github/workflows/build_and_deploy.yml",
"../../rust-toolchain.toml",
],
},
"rust-check-napi": {
"inputs": [
"../../.cargo/**",
@@ -37,13 +37,12 @@ pub trait BackingStorage: BackingStorageSealed {
///
/// This typically means that we'll restart the process or `turbo-tasks` soon with a fresh
/// database. If this happens, there's no point in writing anything else to disk, or flushing
/// during [`KeyValueDatabase::shutdown`].
/// during [`TurboTasksBackend::stop`].
///
/// This can be implemented by calling [`invalidate_db`] with
/// the database's non-versioned base path.
///
/// [`KeyValueDatabase::shutdown`]: crate::database::key_value_database::KeyValueDatabase::shutdown
/// [`invalidate_db`]: crate::database::db_invalidation::invalidate_db
/// [`TurboTasksBackend::stop`]: turbo_tasks::backend::Backend::stop
//
// This can be implemented by calling `database::db_invalidation::invalidate_db` with the
// database's non-versioned base path.
fn invalidate(&self, reason_code: &str) -> Result<()>;
}
@@ -48,9 +48,10 @@ impl Deref for Bytes {
}
}
/// Types that implement From<X> for Bytes {}
/// Unfortunately, we cannot just use the more generic `Into<Bytes>` without
/// running afoul of the `From<X> for X` base case, causing conflicting impls.
/// Types that `impl From<CustomType> for Bytes {}`
///
/// Unfortunately, we cannot just use the more generic `Into<Bytes>` without running afoul of the
/// `From<X> for X` base case, causing conflicting impls.
pub trait IntoBytes: Into<CBytes> {}
impl IntoBytes for &'static [u8] {}
impl IntoBytes for &'static str {}
@@ -25,17 +25,17 @@ pub fn directory_from_include_dir(
Vc::upcast(EmbeddedFileSystem::new(name, dir))
}
/// Returns an embedded [Vc<Box<dyn FileSystem>>] for the given path.
/// Returns an embedded [`Vc<Box<dyn FileSystem>>`][FileSystem] for the given path.
///
/// This will embed a directory's content into the binary and
/// create an [Vc<EmbeddedFileSystem>].
/// This will embed a directory's content into the binary and create an
/// [`Vc<EmbeddedFileSystem>`][EmbeddedFileSystem].
///
/// If you enable the `dynamic_embed_contents` feature, calling
/// the macro will return a [Vc<DiskFileSystem>].
/// If you enable the `dynamic_embed_contents` feature, calling the macro will return a
/// [`Vc<DiskFileSystem>`][DiskFileSystem].
///
/// This enables dynamic linking (and hot reloading) of embedded files/dirs.
/// A binary built with `dynamic_embed_contents` enabled is **is not portable**,
/// only the directory path will be embedded into the binary.
/// This enables dynamic linking (and hot reloading) of embedded files/dirs. A binary built with
/// `dynamic_embed_contents` enabled is **is not portable**, only the directory path will be
/// embedded into the binary.
#[macro_export]
macro_rules! embed_directory {
($name:tt, $path:tt) => {{ // make sure the path contains `$CARGO_MANIFEST_DIR`
+12 -25
View File
@@ -91,19 +91,6 @@ use crate::{
};
pub use crate::{read_glob::ReadGlobResult, virtual_fs::VirtualFileSystem};
/// A (somewhat arbitrary) filename limit that we should try to keep output file names below.
///
/// For the sake of consistency, this is a fixed constant that is likely to be safe across all
/// platforms.
///
/// Different operating systems have different limits on file name and file path. See
/// [`validate_path_length`] for details. Because this only accounts for a single path segment, and
/// not the total path length, this cannot not guarantee a full file path is safe.
///
/// To ensure file names are kept within this limit, call
/// [`FileSystemPath::truncate_file_name_with_hash`].
pub const MAX_SAFE_FILE_NAME_LENGTH: usize = 200;
/// Validate the path, returning the valid path, a modified-but-now-valid path, or bailing with an
/// error.
///
@@ -1553,9 +1540,8 @@ impl FileSystemPath {
FileSystemPath { fs, path }
}
/// Adds a subpath to the current path. The /-separate path argument might
/// contain ".." or "." segments, but it must not leave the root of the
/// filesystem.
/// Adds a subpath to the current path. The /-separated `path` argument might contain ".." or
/// "." segments, but it must not leave the root of the filesystem.
pub fn join(&self, path: &str) -> Result<Self> {
if let Some(path) = join_path(&self.path, path) {
Ok(Self::new_normalized(self.fs, path.into()))
@@ -1568,7 +1554,7 @@ impl FileSystemPath {
}
}
/// Adds a suffix to the filename. [path] must not contain `/`.
/// Adds a suffix to the filename. `path` must not contain `/`.
pub fn append(&self, path: &str) -> Result<Self> {
if path.contains('/') {
bail!(
@@ -1583,12 +1569,12 @@ impl FileSystemPath {
))
}
/// Adds a suffix to the basename of the filename. [appending] must not
/// contain `/`. Extension will stay intact.
/// Adds a suffix to the basename of the file path. `appending` must not contain `/`. The [file
/// extension][FileSystemPath::extension] will stay intact.
pub fn append_to_stem(&self, appending: &str) -> Result<Self> {
if appending.contains('/') {
bail!(
"FileSystemPath(\"{}\").append_to_stem(\"{}\") must not append '/'",
"FileSystemPath({:?}).append_to_stem({:?}) must not append '/'",
self.path,
appending,
)
@@ -1628,14 +1614,15 @@ impl FileSystemPath {
None
}
/// DETERMINISM: Result is in random order. Either sort result or do not depend
/// on the order.
/// DETERMINISM: Result is in random order. Either sort the result or do not depend on the
/// order.
pub fn read_glob(&self, glob: Vc<Glob>) -> Vc<ReadGlobResult> {
read_glob(self.clone(), glob)
}
// Tracks all files and directories matching the glob
// Follows symlinks as though they were part of the original hierarchy.
// Tracks all files and directories matching the glob using the filesystem watcher. Follows
// symlinks as though they were part of the original hierarchy. The returned [`Vc`] will be
// invalidated if a file or directory changes.
pub fn track_glob(&self, glob: Vc<Glob>, include_dot_files: bool) -> Vc<Completion> {
track_glob(self.clone(), glob, include_dot_files)
}
@@ -2046,7 +2033,7 @@ pub enum LinkContent {
///
/// We don't use the [`FileSystemPath`] to store the target, because the [`FileSystemPath`] is
/// always normalized. In [`FileSystemPath::write_symbolic_link_dir`] we need to compare
/// `target` with the value returned by [`sys::fs::read_link`].
/// `target` with the value returned by [`std::fs::read_link`].
Link {
target: RcStr,
link_type: LinkType,
+4 -4
View File
@@ -159,8 +159,8 @@ impl<T: Into<Bytes>> From<T> for Rope {
impl RopeBuilder {
/// Push owned bytes into the Rope.
///
/// If possible use [push_static_bytes] or `+=` operation instead, as they
/// will create a reference to shared memory instead of cloning the bytes.
/// If possible, use [`RopeBuilder::push_static_bytes`] or `+=` operation instead. That will
/// create a reference to shared memory instead of cloning the bytes.
pub fn push_bytes(&mut self, bytes: &[u8]) {
if bytes.is_empty() {
return;
@@ -414,7 +414,7 @@ impl DeterministicHash for RopeBytesOnlyHash<'_> {
/// [`Rope::to_bytes`] instead would be easier, but would require copying to an intermediate buffer.
///
/// This len + bytes format is similar to how bincode would normally encode a `&[u8]`:
/// https://docs.rs/bincode/latest/bincode/spec/index.html#collections
/// <https://docs.rs/bincode/latest/bincode/spec/index.html#collections>
impl Encode for Rope {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.length.encode(encoder)?;
@@ -882,7 +882,7 @@ impl BufRead for RopeReader<'_> {
}
impl<'a> Stream for RopeReader<'a> {
/// This is efficiently streamable into a [`Hyper::Body`] if each item is cloned into an owned
/// This is efficiently streamable into a `Hyper::Body` if each item is cloned into an owned
/// `Bytes` instance.
type Item = Result<&'a Bytes>;
+3 -3
View File
@@ -8,9 +8,9 @@ use turbo_tasks::ResolvedVc;
use crate::{DiskFileSystem, FileSystemPath};
/// Converts a disk access Result<T> into a Result<Some<T>>, where a NotFound
/// error results in a None value. This is purely to reduce boilerplate code
/// comparing NotFound errors against all other errors.
/// Converts a disk access `Result<T>` into a `Result<Some<T>>`, where a [`ErrorKind::NotFound`] (or
/// [`ErrorKind::InvalidFilename`]) error results in a [`None`] value. This is purely to reduce
/// boilerplate code comparing [`ErrorKind::NotFound`] errors against all other errors.
pub fn extract_disk_access<T>(value: io::Result<T>, path: &Path) -> Result<Option<T>> {
match value {
Ok(v) => Ok(Some(v)),
+9 -3
View File
@@ -24,11 +24,17 @@ pub enum HashAlgorithm {
Xxh3Hash64Base40,
/// xxh3 128-bit hash encoded as a 25-character base40 string (0-9 a-z _ - ~ .)
Xxh3Hash128Base40,
/// Used for https://nextjs.org/docs/app/guides/content-security-policy#enabling-sri
/// Used for [Subresource Integrity (SRI)][sri].
///
/// [sri]: https://nextjs.org/docs/app/guides/content-security-policy#enabling-sri
Sha256Base64,
/// Used for https://nextjs.org/docs/app/guides/content-security-policy#enabling-sri
/// Used for [Subresource Integrity (SRI)][sri].
///
/// [sri]: https://nextjs.org/docs/app/guides/content-security-policy#enabling-sri
Sha384Base64,
/// Used for https://nextjs.org/docs/app/guides/content-security-policy#enabling-sri
/// Used for [Subresource Integrity (SRI)][sri].
///
/// [sri]: https://nextjs.org/docs/app/guides/content-security-policy#enabling-sri
Sha512Base64,
}
+1 -1
View File
@@ -28,7 +28,7 @@ The `#[turbo_tasks::function]` macro **rewrites the arguments and return values*
- Method arguments of **`&self`** are **rewritten to `self: Vc<Self>`**.
[`ResolvedVc<T>`]: crate::ResolvedVc
[`FromTaskInput`]: crate::FromTaskInput
[`FromTaskInput`]: crate::task::FromTaskInput
### Return Type Rewrite Rules
+2 -1
View File
@@ -2,7 +2,8 @@
//!
//! This avoid the problem of sleeping threads with mimalloc when using rayon in combination with
//! tokio. It also avoid having multiple thread pools.
//! see also https://pwy.io/posts/mimalloc-cigarette/
//!
//! See also: <https://pwy.io/posts/mimalloc-cigarette/>
use crate::{
scope::scope_and_block,
+3 -3
View File
@@ -155,10 +155,10 @@ pub struct Scope<'scope, 'env: 'scope, R: Send + 'env> {
handle: Handle,
turbo_tasks: Option<Arc<dyn TurboTasksApi>>,
span: Span,
/// Invariance over 'env, to make sure 'env cannot shrink,
/// which is necessary for soundness.
/// Invariance over 'env, to make sure 'env cannot shrink, which is necessary for soundness.
///
/// see https://doc.rust-lang.org/src/std/thread/scoped.rs.html#12-29
/// See the comment in the stdlib implementation:
/// <https://github.com/rust-lang/rust/blob/3b1b0ef4d8/library/std/src/thread/scoped.rs#L12-L33>
env: PhantomData<&'env mut &'env ()>,
}
+10 -4
View File
@@ -8,20 +8,26 @@ use turbo_tasks_hash::{HashAlgorithm, Xxh3Hash64Hasher};
use crate::version::{VersionedAssetContent, VersionedContent};
/// An asset. It also forms a graph when following [Asset::references].
/// A file or intermediate result containing content as a [`Rope`] or a symlink.
///
/// This is a supertrait for [`Source`], [`OutputAsset`], and [`OutputChunk`].
///
/// [`Rope`]: turbo_tasks_fs::rope::Rope
/// [`Source`]: crate::source::Source
/// [`OutputAsset`]: crate::output::OutputAsset
/// [`OutputChunk`]: crate::chunk::OutputChunk
#[turbo_tasks::value_trait]
pub trait Asset {
/// The content of the [Asset].
#[turbo_tasks::function]
fn content(self: Vc<Self>) -> Vc<AssetContent>;
/// The content of the [Asset] alongside its version.
/// The content of the `Asset` alongside its version.
#[turbo_tasks::function]
fn versioned_content(self: Vc<Self>) -> Result<Vc<Box<dyn VersionedContent>>> {
Ok(Vc::upcast(VersionedAssetContent::new(self.content())))
}
/// Hash of the content of the [Asset]
/// Hash of the content of the `Asset`.
#[turbo_tasks::function]
fn content_hash(self: Vc<Self>, algorithm: HashAlgorithm) -> Vc<Option<RcStr>> {
self.content().content_hash(algorithm)
@@ -202,25 +202,25 @@ pub struct Chunks(Vec<ResolvedVc<Box<dyn Chunk>>>);
#[turbo_tasks::value_impl]
impl Chunks {
/// Creates a new empty [Vc<Chunks>].
#[turbo_tasks::function]
pub fn empty() -> Vc<Self> {
Vc::cell(vec![])
}
}
/// A [Chunk] group chunk items together into something that will become an [OutputAsset].
/// It usually contains multiple chunk items.
// TODO This could be simplified to and merged with [OutputChunk]
/// Groups chunk items together into something that will become an [`OutputAsset`]. It usually
/// contains multiple chunk items.
///
/// [`OutputAsset`]: crate::output::OutputAsset
//
// TODO: This could be simplified to and merged with OutputChunk
#[turbo_tasks::value_trait]
pub trait Chunk: OutputAssetsReference {
#[turbo_tasks::function]
fn ident(self: Vc<Self>) -> Vc<AssetIdent>;
#[turbo_tasks::function]
fn chunking_context(self: Vc<Self>) -> Vc<Box<dyn ChunkingContext>>;
// fn path(self: Vc<Self>) -> Vc<FileSystemPath> {
// self.ident().path()
// }
#[turbo_tasks::function]
fn chunk_items(self: Vc<Self>) -> Vc<ChunkItems> {
@@ -49,16 +49,13 @@ pub struct DiagnosticPayload(
#[bincode(with = "turbo_bincode::indexmap")] pub FxIndexMap<RcStr, RcStr>,
);
/// An arbitrary payload can be used to analyze, diagnose
/// Turbopack's behavior.
/// An arbitrary payload can be used to analyze, diagnose Turbopack's behavior.
#[turbo_tasks::value_trait]
pub trait Diagnostic {
/// [NOTE]: Pseudo-reserved; this is not being used currently.
/// The `type` of the diagnostics that can be used selectively filtered by
/// consumers. For example, this could be `telemetry`, or
/// `slow_perf_event`, or something else. This is not strongly typed
/// though; since consumer or implementation may need to define own
/// category.
/// **NOTE:** Pseudo-reserved; this is not being used currently. The `type` of the diagnostics
/// that can be used selectively filtered by consumers. For example, this could be `telemetry`,
/// or `slow_perf_event`, or something else. This is not strongly typed though; since consumer
/// or implementation may need to define own category.
#[turbo_tasks::function]
fn category(&self) -> Vc<RcStr>;
/// Name of the specific diagnostic event.
@@ -113,8 +110,7 @@ where
}
}
/// A list of diagnostics captured with
/// [`DiagnosticsVc::peek_diagnostics_with_path`] and
/// A list of diagnostics captured with [`DiagnosticContextExt::peek_diagnostics`] and
#[derive(Debug)]
#[turbo_tasks::value]
pub struct CapturedDiagnostics {
@@ -35,7 +35,7 @@ pub enum ChunkLoading {
Edge,
/// CommonJS in Node.js
NodeJs,
/// <script> and <link> tags in the browser
/// `<script>` and `<link>` tags in the browser
Dom,
}
@@ -405,8 +405,7 @@ impl IssueFilter {
}
}
/// A list of issues captured with [`Issue::peek_issues_with_path`] and
/// [`Issue::take_issues`].
/// A list of issues captured with [`CollectibleIssuesExt::peek_issues`].
#[turbo_tasks::value(shared)]
#[derive(Debug)]
pub struct CapturedIssues {
@@ -414,26 +413,7 @@ pub struct CapturedIssues {
tracer: ResolvedVc<DelegatingImportTracer>,
}
#[turbo_tasks::value_impl]
impl CapturedIssues {
#[turbo_tasks::function]
pub fn is_empty(&self) -> Vc<bool> {
Vc::cell(self.is_empty_ref())
}
}
impl CapturedIssues {
/// Returns true if there are no issues.
pub fn is_empty_ref(&self) -> bool {
self.issues.is_empty()
}
/// Returns the number of issues.
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.issues.len()
}
/// Returns an iterator over the issues.
pub fn iter(&self) -> impl Iterator<Item = ResolvedVc<Box<dyn Issue>>> + '_ {
self.issues.iter().copied()
@@ -976,14 +956,13 @@ fn hash_plain_issue(issue: &PlainIssue, hasher: &mut Xxh3Hash64Hasher, full: boo
}
impl PlainIssue {
/// We need deduplicate issues that can come from unique paths, but
/// represent the same underlying problem. Eg, a parse error for a file
/// that is compiled in both client and server contexts.
/// We need deduplicate issues that can come from unique paths, but represent the same
/// underlying problem. E.g., a parse error for a file that is compiled in both client and
/// server contexts.
///
/// Passing [full] will also hash any sub-issues and processing paths. While
/// useful for generating exact matching hashes, it's possible for the
/// same issue to pass from multiple processing paths, making for overly
/// verbose logging.
/// Passing `full` will also hash any sub-issues and processing paths. While useful for
/// generating exact matching hashes, it's possible for the same issue to pass from multiple
/// processing paths, making for overly verbose logging.
pub fn internal_hash_ref(&self, full: bool) -> u64 {
let mut hasher = Xxh3Hash64Hasher::new();
hash_plain_issue(self, &mut hasher, full);
+20 -13
View File
@@ -13,13 +13,15 @@ pub enum StyleType {
#[derive(Hash, Debug, Copy, Clone)]
#[turbo_tasks::value(shared)]
pub enum ModuleSideEffects {
/// Analysis determined that the module evaluation is side effect free
/// the module may still be side effectful based on its imports.
/// Analysis determined that the module evaluation is free of side effects. The module may still
/// have side effects based on its imports.
///
/// This module might not be chunked after Turbopack performed a global analysis on the module
/// graph.
ModuleEvaluationIsSideEffectFree,
/// Is known to be side effect free either due to static analysis or some kind of configuration.
/// Is known to be free of side effects either due to static analysis or some kind of
/// configuration.
///
/// ```js
/// "use turbopack no side effects"
/// ```
@@ -31,28 +33,30 @@ pub enum ModuleSideEffects {
SideEffectful,
}
/// A module. This usually represents parsed source code, which has references
/// to other modules.
/// A module. This usually represents parsed source code, which has references to other modules.
#[turbo_tasks::value_trait]
pub trait Module {
/// The identifier of the [Module]. It's expected to be unique and capture
/// all properties of the [Module].
/// The identifier of the [`Module`]. It's expected to be unique and capture all properties of
/// the [`Module`].
#[turbo_tasks::function]
fn ident(&self) -> Vc<AssetIdent>;
/// The identifier of the [Module] as string. It's expected to be unique and capture
/// all properties of the [Module].
/// The identifier of the [`Module`] as string. It's expected to be unique and capture all
/// properties of the [`Module`].
#[turbo_tasks::function]
fn ident_string(self: Vc<Self>) -> Vc<RcStr> {
self.ident().to_string()
}
/// The source of the [Module].
/// The source of the [`Module`].
#[turbo_tasks::function]
fn source(&self) -> Vc<OptionSource>;
/// Other [Module]s or [OutputAsset]s referenced from this [Module].
// TODO refactor to avoid returning [OutputAsset]s here
/// Other [`Module`]s or [`OutputAsset`]s referenced from this [`Module`].
///
/// [`OutputAsset`]: crate::output::OutputAsset
//
// TODO: refactor to avoid returning OutputAssets here
#[turbo_tasks::function]
fn references(self: Vc<Self>) -> Vc<ModuleReferences> {
ModuleReferences::empty()
@@ -64,7 +68,10 @@ pub trait Module {
Vc::cell(false)
}
/// Returns true if the module is marked as side effect free in package.json or by other means.
/// Returns `true` if the module is marked as [free of side effects in
/// `package.json`][packagejson] or by other means.
///
/// [packagejson]: https://webpack.js.org/guides/tree-shaking/#mark-the-file-as-side-effect-free
#[turbo_tasks::function]
fn side_effects(self: Vc<Self>) -> Vc<ModuleSideEffects>;
}
@@ -14,7 +14,7 @@ pub struct OptionOutputAsset(Option<ResolvedVc<Box<dyn OutputAsset>>>);
#[turbo_tasks::value_trait]
pub trait OutputAssetsReference {
/// References to other [OutputAsset]s from this [OutputAssetReference].
/// References to other [`OutputAsset`]s from this [`OutputAssetsReference`].
#[turbo_tasks::function]
fn references(self: Vc<Self>) -> Vc<OutputAssetsWithReferenced> {
OutputAssetsWithReferenced {
@@ -75,14 +75,13 @@ impl ModuleReference for SingleModuleReference {
#[turbo_tasks::value_impl]
impl SingleModuleReference {
/// Create a new [Vc<SingleModuleReference>] that resolves to the given
/// asset.
/// Create a new instance that resolves to the given asset.
#[turbo_tasks::function]
pub fn new(asset: ResolvedVc<Box<dyn Module>>, description: RcStr) -> Vc<Self> {
Self::cell(SingleModuleReference { asset, description })
}
/// The [Vc<Box<dyn Asset>>] that this reference resolves to.
/// The [`Vc<Box<dyn Module>>`][Module] that this reference resolves to.
#[turbo_tasks::function]
pub fn asset(&self) -> Vc<Box<dyn Module>> {
*self.asset
@@ -155,14 +154,13 @@ impl ModuleReference for SingleOutputAssetReference {
#[turbo_tasks::value_impl]
impl SingleOutputAssetReference {
/// Create a new [Vc<SingleOutputAssetReference>] that resolves to the given
/// asset.
/// Create a new `Vc<SingleOutputAssetReference>` that resolves to the given asset.
#[turbo_tasks::function]
pub fn new(asset: ResolvedVc<Box<dyn OutputAsset>>, description: RcStr) -> Vc<Self> {
Self::cell(SingleOutputAssetReference { asset, description })
}
/// The [Vc<Box<dyn Asset>>] that this reference resolves to.
/// The [`Vc<Box<dyn OutputAsset>>`][OutputAsset] that this reference resolves to.
#[turbo_tasks::function]
pub fn asset(&self) -> Vc<Box<dyn OutputAsset>> {
*self.asset
@@ -233,11 +231,10 @@ impl TracedModuleReference {
}
}
/// Aggregates all primary [Module]s referenced by an [Module]. [AssetReference]
/// This does not include transitively references [Module]s, only includes
/// primary [Module]s referenced.
/// Aggregates all primary [`Module`]s referenced by an [`Module`]. This does not include
/// transitively references [`Module`]s, only includes primary [`Module`]s referenced.
///
/// [Module]: crate::module::Module
/// [`Module`]: crate::module::Module
#[turbo_tasks::function]
pub async fn primary_referenced_modules(module: Vc<Box<dyn Module>>) -> Result<Vc<Modules>> {
let mut set = HashSet::new();
@@ -351,9 +351,9 @@ impl Display for ReferenceType {
}
impl ReferenceType {
/// Returns true if this reference type is internal. This will be used in
/// combination with [`ModuleRuleCondition::Internal`] to determine if a
/// rule should be applied to an internal asset/reference.
/// Returns `true` if this reference type is internal. This is used by
/// `turbopack::module_options::module_rule::ModuleRule::new_internal` to determine if a rule
/// should be applied to an internal reference.
pub fn is_internal(&self) -> bool {
matches!(
self,
@@ -17,7 +17,7 @@ use turbo_tasks::{
use crate::resolve::pattern::Pattern;
/// A map of [`AliasPattern`]s to the [`Template`]s they resolve to.
/// A map of [`AliasPattern`]s as keys implemented using [`PatriciaMap`].
///
/// If a pattern has a wildcard character (*) within it, it will capture any
/// number of characters, including path separators. The result of the capture
@@ -578,7 +578,10 @@ where
}
}
/// An alias pattern.
/// An alias pattern commonly used for import paths. This should support [the functionality used in
/// Typescript's tsconfig file][tsconfig].
///
/// [tsconfig]: https://www.typescriptlang.org/tsconfig/#paths
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub enum AliasPattern {
/// Will match an exact string.
@@ -658,8 +658,8 @@ pub struct ResolveOptions {
#[turbo_tasks::value_impl]
impl ResolveOptions {
/// Returns a new [Vc<ResolveOptions>] with its import map extended to
/// include the given import map.
/// Returns a new `Vc<ResolveOptions>` with its import map extended to include the given import
/// map.
#[turbo_tasks::function]
pub async fn with_extended_import_map(
self: Vc<Self>,
@@ -677,8 +677,8 @@ impl ResolveOptions {
Ok(resolve_options.cell())
}
/// Returns a new [Vc<ResolveOptions>] with its fallback import map extended
/// to include the given import map.
/// Returns a new `Vc<ResolveOptions>` with its fallback import map extended to include the
/// given import map.
#[turbo_tasks::function]
pub async fn with_extended_fallback_import_map(
self: Vc<Self>,
@@ -45,7 +45,9 @@ pub enum SubpathValue {
/// allow remapping based on certain predefined conditions. Eg, if using
/// ESM import syntax, the `import` condition allows you to remap to a
/// file that uses ESM syntax.
/// Node defines several conditions in https://nodejs.org/api/packages.html#conditional-exports
///
/// Node defines several conditions in
/// <https://nodejs.org/api/packages.html#conditional-exports>
/// TODO: Should this use an enum of predefined keys?
Conditional(Vec<(RcStr, SubpathValue)>),
@@ -3,8 +3,11 @@ use turbo_tasks::{ResolvedVc, Vc};
use crate::{asset::Asset, ident::AssetIdent};
/// (Unparsed) Source Code. Source Code is processed into [Module]s by the
/// [AssetContext]. All [Source]s have content and an identifier.
/// Unparsed input source code. Source code is processed into [`Module`]s by the [`AssetContext`].
/// All `Source`s have content and an identifier.
///
/// [`Module`]: crate::module::Module
/// [`AssetContext`]: crate::context::AssetContext
#[turbo_tasks::value_trait]
pub trait Source: Asset {
/// The identifier of the [Source]. It's expected to be unique and capture
@@ -48,16 +48,8 @@ pub trait GenerateSourceMap {
}
}
/// Implements the source map specification as either a decoded or sectioned sourcemap.
///
/// - A "decoded" map represents a source map as if it was came out of a JSON
/// decode.
/// - A "sectioned" source map is a tree of many [SourceMap]
/// covering regions of an output file.
///
/// The distinction between the source map spec's [sourcemap::Index] and our
/// [SourceMap::Sectioned] is whether the sections are represented with Vcs
/// pointers.
/// Implements the source map specification as a [decoded][`DecodedMap`] sourcemap. A "decoded" map
/// represents a source map as if it was came out of a JSON decode.
#[turbo_tasks::value(shared, cell = "new", eq = "manual")]
#[derive(Debug)]
pub struct SourceMap {
@@ -236,12 +228,10 @@ impl TryInto<swc_sourcemap::RawToken> for Token {
}
impl SourceMap {
/// Creates a new SourceMap::Decoded Vc out of a [RegularMap] instance.
fn new_regular(map: RegularMap) -> Self {
Self::new_decoded(DecodedMap::Regular(map))
}
/// Creates a new SourceMap::Decoded Vc out of a [DecodedMap] instance.
fn new_decoded(map: DecodedMap) -> Self {
SourceMap {
map: Arc::new(CrateMapWrapper(map)),
@@ -52,7 +52,7 @@ impl SourcePos {
/// Line terminators are the classic "\n", "\r", "\r\n" (which counts as
/// a single terminator), and JSON LINE/PARAGRAPH SEPARATORs.
///
/// See https://tc39.es/ecma262/multipage/ecmascript-language-lexical-grammar.html#sec-line-terminators
/// See <https://tc39.es/ecma262/multipage/ecmascript-language-lexical-grammar.html#sec-line-terminators>
pub fn update(&mut self, code: &[u8]) {
// JS source text is interpreted as UCS-2, which is basically UTF-16 with less
// restrictions. We cannot iterate UTF-8 bytes here, 2-byte UTF-8 octets
@@ -13,10 +13,15 @@ use crate::asset::AssetContent;
#[turbo_tasks::value(transparent)]
pub struct OptionVersionedContent(Option<ResolvedVc<Box<dyn VersionedContent>>>);
/// The content of an [Asset] alongside its version.
/// The content of an [`Asset`] alongside its version, returned by [`Asset::versioned_content`].
///
/// [`Asset`]: crate::asset::Asset
/// [`Asset::versioned_content`]: crate::asset::Asset::versioned_content
#[turbo_tasks::value_trait]
pub trait VersionedContent {
/// The content of the [Asset].
/// The content of the [`Asset`].
///
/// [`Asset`]: crate::asset::Asset
#[turbo_tasks::function]
fn content(self: Vc<Self>) -> Vc<AssetContent>;
@@ -85,7 +90,7 @@ impl VersionedContent for VersionedAssetContent {
#[turbo_tasks::value_impl]
impl VersionedAssetContent {
#[turbo_tasks::function]
/// Creates a new [Vc<VersionedAssetContent>] from a [Vc<FileContent>].
/// Creates a new instance from a [`Vc<AssetContent>`][AssetContent].
pub async fn new(asset_content: Vc<AssetContent>) -> Result<Vc<Self>> {
let asset_content = asset_content.await?;
Ok(Self::cell(VersionedAssetContent { asset_content }))
@@ -48,9 +48,8 @@ pub enum EffectMode {
None,
/// As a direct `useEffect` hook in the component's body.
Hook,
/// Rendering an <Effect /> client-side component that has the `useEffect`
/// hook instead. Good for testing React Server Components, as they can't
/// use `useEffect` hooks directly.
/// Rendering an `<Effect />` client-side component that has the `useEffect` hook instead. Good
/// for testing React Server Components, as they can't use `useEffect` hooks directly.
Component,
}
+4 -2
View File
@@ -30,10 +30,12 @@ use crate::{
},
};
/// A global CSS module. Notably not a `.module.css` module, which is [`EcmascriptCssModule`]
/// instead.
///
/// [`EcmascriptCssModule`]: crate::EcmascriptCssModule
#[turbo_tasks::value]
#[derive(Clone)]
/// A global CSS asset. Notably not a `.module.css` module, which is [`EcmascriptCssModule`]
/// instead.
pub struct CssModule {
source: ResolvedVc<Box<dyn Source>>,
asset_context: ResolvedVc<Box<dyn AssetContext>>,
@@ -36,9 +36,12 @@ use crate::{
references::{compose::CssModuleComposeReference, internal::InternalCssAssetReference},
};
/// A [CSS Module, as in `.module.css`][spec]. For a global CSS module, see [`CssModule`].
///
/// [spec]: https://github.com/css-modules/css-modules
/// [`CssModule`]: crate::CssModule
#[turbo_tasks::value]
#[derive(Clone)]
/// A CSS Module asset, as in `.module.css`. For a global CSS module, see [`CssModule`].
pub struct EcmascriptCssModule {
pub source: ResolvedVc<Box<dyn Source>>,
pub asset_context: ResolvedVc<Box<dyn AssetContext>>,
@@ -8,10 +8,7 @@ use crate::source::{
route_tree::{RouteTree, RouteTrees},
};
/// Combines multiple [ContentSource]s by trying all content sources in order.
///
/// The content source which responds with the most specific response (that is
/// not a [ContentSourceContent::NotFound]) will be returned.
/// Combines multiple [`ContentSource`]s by [merging][RouteTrees::merge] [`RouteTree`]s.
#[turbo_tasks::value(shared)]
pub struct CombinedContentSource {
pub sources: Vec<ResolvedVc<Box<dyn ContentSource>>>,
@@ -1,165 +0,0 @@
use anyhow::Result;
use turbo_rcstr::{RcStr, rcstr};
use turbo_tasks::{Completion, ResolvedVc, State, Vc};
use turbopack_core::introspect::{Introspectable, IntrospectableChildren};
use crate::source::{
ContentSource, ContentSourceContent, ContentSourceData, ContentSourceDataVary,
ContentSourceSideEffect, ContentSources, GetContentSourceContent,
route_tree::{MapGetContentSourceContent, RouteTree, RouteTrees},
};
/// Combines two [ContentSource]s like the [CombinedContentSource], but only
/// allows to serve from the second source when the first source has
/// successfully served something once.
///
/// This is a laziness optimization when the content of the second source can
/// only be reached via references from the first source.
///
/// For example, we use that in the content source that handles SSR rendering of
/// pages. Here HTML and "other assets" are in different content sources. So we
/// use this source to only serve (and process) "other assets" when the HTML was
/// served once.
#[turbo_tasks::value(serialization = "none", eq = "manual", cell = "new")]
pub struct ConditionalContentSource {
activator: ResolvedVc<Box<dyn ContentSource>>,
action: ResolvedVc<Box<dyn ContentSource>>,
activated: State<bool>,
}
#[turbo_tasks::value_impl]
impl ConditionalContentSource {
#[turbo_tasks::function]
pub fn new(
activator: ResolvedVc<Box<dyn ContentSource>>,
action: ResolvedVc<Box<dyn ContentSource>>,
) -> Vc<Self> {
ConditionalContentSource {
activator,
action,
activated: State::new(false),
}
.cell()
}
}
#[turbo_tasks::value_impl]
impl ContentSource for ConditionalContentSource {
#[turbo_tasks::function]
async fn get_routes(self: ResolvedVc<Self>) -> Result<Vc<RouteTree>> {
let this = self.await?;
Ok(if !*this.activated.get() {
this.activator.get_routes().map_routes(Vc::upcast(
ConditionalContentSourceMapper { source: self }.cell(),
))
} else {
Vc::<RouteTrees>::cell(vec![
this.activator.get_routes().to_resolved().await?,
this.action.get_routes().to_resolved().await?,
])
.merge()
})
}
#[turbo_tasks::function]
fn get_children(&self) -> Vc<ContentSources> {
Vc::cell(vec![self.activator, self.action])
}
}
#[turbo_tasks::value]
struct ConditionalContentSourceMapper {
source: ResolvedVc<ConditionalContentSource>,
}
#[turbo_tasks::value_impl]
impl MapGetContentSourceContent for ConditionalContentSourceMapper {
#[turbo_tasks::function]
fn map_get_content(
&self,
get_content: ResolvedVc<Box<dyn GetContentSourceContent>>,
) -> Vc<Box<dyn GetContentSourceContent>> {
Vc::upcast(
ActivateOnGetContentSource {
source: self.source,
get_content,
}
.cell(),
)
}
}
#[turbo_tasks::value_impl]
impl Introspectable for ConditionalContentSource {
#[turbo_tasks::function]
fn ty(&self) -> Vc<RcStr> {
Vc::cell(rcstr!("conditional content source"))
}
#[turbo_tasks::function]
fn details(&self) -> Vc<RcStr> {
Vc::cell(if *self.activated.get() {
rcstr!("activated")
} else {
rcstr!("not activated")
})
}
#[turbo_tasks::function]
fn title(&self) -> Result<Vc<RcStr>> {
if let Some(activator) = ResolvedVc::try_sidecast::<Box<dyn Introspectable>>(self.activator)
{
Ok(activator.title())
} else {
Ok(Vc::<RcStr>::default())
}
}
#[turbo_tasks::function]
fn children(&self) -> Result<Vc<IntrospectableChildren>> {
Ok(Vc::cell(
[
ResolvedVc::try_sidecast::<Box<dyn Introspectable>>(self.activator)
.map(|i| (rcstr!("activator"), i)),
ResolvedVc::try_sidecast::<Box<dyn Introspectable>>(self.action)
.map(|i| (rcstr!("action"), i)),
]
.into_iter()
.flatten()
.collect(),
))
}
}
#[turbo_tasks::value(serialization = "none", eq = "manual", cell = "new")]
struct ActivateOnGetContentSource {
source: ResolvedVc<ConditionalContentSource>,
get_content: ResolvedVc<Box<dyn GetContentSourceContent>>,
}
#[turbo_tasks::value_impl]
impl GetContentSourceContent for ActivateOnGetContentSource {
#[turbo_tasks::function]
fn vary(&self) -> Vc<ContentSourceDataVary> {
self.get_content.vary()
}
#[turbo_tasks::function]
async fn get(
self: ResolvedVc<Self>,
path: RcStr,
data: ContentSourceData,
) -> Result<Vc<ContentSourceContent>> {
turbo_tasks::emit(ResolvedVc::upcast::<Box<dyn ContentSourceSideEffect>>(self));
Ok(self.await?.get_content.get(path, data))
}
}
#[turbo_tasks::value_impl]
impl ContentSourceSideEffect for ActivateOnGetContentSource {
#[turbo_tasks::function]
async fn apply(&self) -> Result<Vc<Completion>> {
self.source.await?.activated.set(true);
Ok(Completion::new())
}
}
@@ -1,12 +1,11 @@
pub mod asset_graph;
pub mod combined;
pub mod conditional;
pub mod headers;
pub mod issue_context;
pub mod lazy_instantiated;
pub mod query;
pub mod request;
pub(crate) mod resolve;
pub mod resolve;
pub mod route_tree;
pub mod router;
pub mod static_assets;
@@ -62,17 +61,16 @@ impl Version for ProxyResult {
}
}
/// A functor to receive the actual content of a content source result.
/// Receives the actual content for a [`ContentSource`].
#[turbo_tasks::value_trait]
pub trait GetContentSourceContent {
/// Specifies data requirements for the get function. Restricting data
/// passed allows to cache the get method.
/// Specifies data requirements for the [`get`][Self::get] function. Restricting data passed
/// allows improved caching of the [`get`][Self::get] method.
#[turbo_tasks::function]
fn vary(self: Vc<Self>) -> Vc<ContentSourceDataVary> {
ContentSourceDataVary::default().cell()
}
/// Get the content
#[turbo_tasks::function]
fn get(self: Vc<Self>, path: RcStr, data: ContentSourceData) -> Vc<ContentSourceContent>;
}
@@ -88,8 +86,8 @@ pub struct StaticContent {
}
#[turbo_tasks::value(shared)]
// TODO add Dynamic variant in future to allow streaming and server responses
/// The content of a result that is returned by a content source.
/// The content of a result that is returned by [`GetContentSourceContent::get`].
// TODO: add a `Dynamic` variant in future to allow streaming and server responses
pub enum ContentSourceContent {
NotFound,
Static(ResolvedVc<StaticContent>),
@@ -156,12 +154,10 @@ impl HeaderList {
}
}
/// Additional info passed to the ContentSource. It was extracted from the http
/// request.
/// Additional info passed to the [`ContentSource`]. It was extracted from the http request.
///
/// Note that you might not receive information that has not been requested via
/// `ContentSource::vary()`. So make sure to request all information that's
/// needed.
/// [`GetContentSourceContent::vary`]. So make sure to request all information that's needed.
#[derive(
PartialEq,
Eq,
@@ -263,7 +259,8 @@ impl ContentSourceDataFilter {
}
/// Merges the filtering to get a filter that covers both filters. Works on
/// Option<DataFilter> where None is considers as empty filter.
/// [`Option<ContentSourceDataFilter>`][ContentSourceDataFilter] where [`None`] behaves as a
/// no-op empty filter.
pub fn extend_options(
this: &mut Option<ContentSourceDataFilter>,
other: &Option<ContentSourceDataFilter>,
@@ -305,9 +302,9 @@ impl ContentSourceDataFilter {
}
}
/// Describes additional information that need to be sent to requests to
/// ContentSource. By sending these information ContentSource responses are
/// cached-keyed by them and they can access them.
/// Describes additional information that need to be sent to requests to [`ContentSource`]. By
/// sending these information [`ContentSource`] responses are cached-keyed by them and they can
/// access them.
#[turbo_tasks::value(shared)]
#[derive(Debug, Default, Clone, Hash)]
pub struct ContentSourceDataVary {
@@ -327,8 +324,8 @@ pub struct ContentSourceDataVary {
}
impl ContentSourceDataVary {
/// Merges two vary specification to create a combination of both that cover
/// all information requested by either one
/// Merges two vary specification to create a combination of both that cover all information
/// requested by either one
pub fn extend(&mut self, other: &ContentSourceDataVary) {
let ContentSourceDataVary {
method,
@@ -353,8 +350,7 @@ impl ContentSourceDataVary {
ContentSourceDataFilter::extend_options(headers, &other.headers);
}
/// Returns true if `self` at least contains all values that the
/// argument would contain.
/// Returns true if `self` at least contains all values that the argument would contain.
pub fn fulfills(&self, other: &ContentSourceDataVary) -> bool {
// All fields must be used!
let ContentSourceDataVary {
@@ -21,9 +21,8 @@ use crate::source::{
route_tree::RouteTree,
};
/// The result of [`resolve_source_request`]. Similar to a
/// `ContentSourceContent`, but without the `Rewrite` variant as this is taken
/// care in the function.
/// The result of [`resolve_source_request`]. Similar to a [`ContentSourceContent`], but without the
/// [`Rewrite`][ContentSourceContent::Rewrite] variant, as this is taken care in the function.
#[turbo_tasks::value(serialization = "none", shared)]
pub enum ResolveSourceRequestResult {
NotFound,
@@ -62,14 +61,22 @@ fn get_content_source_content_get_operation(
get_content.get(path, data)
}
/// Resolves a [SourceRequest] within a [super::ContentSource], returning the
/// corresponding content.
/// Resolves a [`SourceRequest`] within a [`ContentSource`], returning the corresponding content.
///
/// This function is the boundary of consistency. All invoked methods should be
/// invoked strongly consistent. This ensures that all requests serve the latest
/// version of the content. We don't make resolve_source_request strongly
/// consistent as we want get_routes and get to be independent consistent and
/// any side effect in get should not wait for recomputing of get_routes.
/// Matches the first [`ContentSourceContent`] in the [`RouteTree`] returned by
/// [`ContentSource::get_routes`] that does not generate [`ContentSourceContent::Next`].
///
/// *In the future*, this function may be used at the boundary of consistency. All invoked methods
/// should be read using [strong consistency][OperationVc::read_strongly_consistent]. This ensures
/// that all requests serve the latest version of the content.
///
/// If this function is not called/read with strong consistency, [`ContentSource::get_routes`] would
/// be allowed to be independently consistent. Side effects should not need to wait for
/// recomputation of [`ContentSource::get_routes`].
///
/// TODO: The callers of this function now read this operation using strong consistency. This may
/// have re-introduced performance issues that were solved in
/// <https://github.com/vercel/turborepo/pull/5360>.
#[turbo_tasks::function(operation)]
pub async fn resolve_source_request(
source: OperationVc<Box<dyn ContentSource>>,
@@ -39,17 +39,16 @@ impl BaseSegment {
}
}
/// This struct allows to cell a list of RouteTrees and merge them into one.
/// This struct allows to cell a list of [`RouteTree`]s and merge them into one.
///
/// This can't be a single method `fn merge(Vec<Vc<RouteTree>>)` as this would
/// lead to creating new tasks over and over. A celled list leads to task reuse
/// and faster operation.
/// This can't be a single method `fn merge(Vec<Vc<RouteTree>>)` as this would lead to creating new
/// tasks over and over. A celled list leads to task reuse and faster operation.
#[turbo_tasks::value(transparent)]
pub struct RouteTrees(Vec<ResolvedVc<RouteTree>>);
#[turbo_tasks::value_impl]
impl RouteTrees {
/// Merges the list of RouteTrees into one RouteTree.
/// Merges the list of [`RouteTree`]s into one [`RouteTree`].
#[turbo_tasks::function]
pub async fn merge(&self) -> Result<Vc<RouteTree>> {
let trees = &self.0;
@@ -7,23 +7,21 @@ use crate::source::{
GetContentSourceContents, Rewrite, RewriteType,
};
/// A ContentSourceProcessor handles the final processing of an eventual
/// [ContentSourceContent].
/// Handles the final processing of an eventual [`ContentSourceContent`].
///
/// Used in conjunction with [WrappedGetContentSourceContent], this allows a
/// [ContentSource] implementation to easily register a final process step over
/// some inner ContentSource's fully resolved [ContentSourceResult] and
/// [ContentSourceContent].
/// Used in conjunction with [`WrappedGetContentSourceContent`], this allows a [`ContentSource`]
/// implementation to easily register a final process step over some inner [`ContentSource`]'s fully
/// resolved [`ContentSourceContent`].
///
/// [`ContentSource`]: crate::source::ContentSource
#[turbo_tasks::value_trait]
pub trait ContentSourceProcessor {
#[turbo_tasks::function]
fn process(self: Vc<Self>, content: Vc<ContentSourceContent>) -> Vc<ContentSourceContent>;
}
/// A WrappedGetContentSourceContent simply wraps the get_content of a
/// [ContentSourceResult], allowing us to process whatever
/// [ContentSourceContent] it would have returned.
/// Wraps the `get_content` of a [`GetContentSourceContent`], allowing us to
/// [post-process][ContentSourceProcessor] whatever [`ContentSourceContent`] it returns.
#[turbo_tasks::value]
pub struct WrappedGetContentSourceContent {
inner: ResolvedVc<Box<dyn GetContentSourceContent>>,
@@ -356,8 +356,11 @@ impl DeclUsage {
#[derive(Debug)]
pub struct VarGraph {
pub values: FxHashMap<Id, VarMeta>,
/// Map FreeVar names to their Id to facilitate lookups into [values]
/// Doesn't necessarily contain every FreeVar, just those who have non trivial values.
/// Map [`JsValue::FreeVar`] names to their [`Id`] to facilitate lookups into [`Self::values`].
///
/// Doesn't necessarily contain every [`FreeVar`][JsValue::FreeVar], just those who have
/// non-trivial values.
pub free_var_ids: FxHashMap<Atom, Id>,
pub effects: Vec<Effect>,
@@ -381,8 +384,6 @@ impl VarGraph {
}
}
/// You should use same [Mark] for this function and
/// [swc_ecma_transforms_base::resolver::resolver_with_mark]
pub fn create_graph(
m: &Program,
eval_context: &EvalContext,
@@ -417,16 +418,22 @@ pub fn create_graph(
/// A context used for assembling the evaluation graph.
#[derive(Debug)]
pub struct EvalContext {
/// Should be the same [`Mark`] used by [`swc_core::ecma::transforms::base::resolver`].
pub(crate) unresolved_mark: Mark,
/// Should be the same [`Mark`] used by [`swc_core::ecma::transforms::base::resolver`].
pub(crate) top_level_mark: Mark,
pub(crate) imports: ImportMap,
pub(crate) force_free_values: Arc<FxHashSet<Id>>,
}
impl EvalContext {
/// Produce a new [EvalContext] from a [Program]. If you wish to support
/// webpackIgnore or turbopackIgnore comments, you must pass those in,
/// since the AST does not include comments by default.
/// Produce a new [`EvalContext`] from a [`Program`].
///
/// If you wish to support `webpackIgnore` or `turbopackIgnore` comments, you must pass those
/// in, since the AST does not include comments by default.
///
/// You should use the same `unresolved_mark` and `top_level_mark` [Mark] values for this
/// context that you passed to [`swc_core::ecma::transforms::base::resolver`].
pub fn new(
module: Option<&Program>,
unresolved_mark: Mark,
@@ -379,9 +379,10 @@ impl Display for LogicalProperty {
}
/// TODO: Use `Arc`
///
/// There are 4 kinds of values: Leaves, Nested, Operations, and Placeholders
/// (see [JsValueMetaKind] for details). Values are processed in two phases:
/// - Analyze phase: We convert AST into [JsValue]s. We don't have contextual information so we need
/// (see `JsValueMetaKind` for details). Values are processed in two phases:
/// - Analyze phase: We convert AST into `JsValue`s. We don't have contextual information so we need
/// to insert placeholders to represent that.
/// - Link phase: We try to reduce a value to a constant value. The link phase has 5 substeps that
/// are executed on each node in the graph depth-first. When a value is modified, we need to visit
@@ -24,7 +24,7 @@ use crate::utils::inline_source_map_comment;
/// { a } from './data.json'`). This matches webpack's historical behavior.
///
/// For JSON files larger than 10KB, we use `JSON.parse()` for better performance.
/// See: https://v8.dev/blog/cost-of-javascript-2019#json
/// See: <https://v8.dev/blog/cost-of-javascript-2019#json>
#[turbo_tasks::value]
pub struct JsonSourceTransform {
/// If true, generate spec-compliant ESM with only an esm default export.
@@ -33,7 +33,9 @@ use crate::{
/// A module derived from an original ecmascript module that contains all
/// the reexports from that module and also reexports the locals from
/// [EcmascriptModuleLocalsModule].
/// [`EcmascriptModuleLocalsModule`].
///
/// [`EcmascriptModuleLocalsModule`]: crate::side_effect_optimization::locals::module::EcmascriptModuleLocalsModule
#[turbo_tasks::value]
pub struct EcmascriptModuleFacadeModule {
module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
@@ -28,9 +28,11 @@ use crate::{
},
};
/// A module derived from an original ecmascript module that only contains the
/// local declarations, but excludes all reexports. These reexports are exposed
/// from [EcmascriptModuleFacadeModule] instead.
/// A module derived from an original ecmascript module that only contains the local declarations,
/// but excludes all reexports. These reexports are exposed from [`EcmascriptModuleFacadeModule`]
/// instead.
///
/// [`EcmascriptModuleFacadeModule`]: crate::side_effect_optimization::facade::module::EcmascriptModuleFacadeModule
#[turbo_tasks::value]
pub struct EcmascriptModuleLocalsModule {
pub module: ResolvedVc<EcmascriptModuleAsset>,
+3 -2
View File
@@ -6,8 +6,9 @@ use turbo_tasks_fs::FileSystemPath;
use crate::TryDotenvProcessEnv;
/// Loads a series of dotenv files according to the precedence rules set by
/// https://nextjs.org/docs/app/building-your-application/configuring/environment-variables#environment-variable-load-order
/// Loads a series of dotenv files according to the [precedence rules set by Next.js][precedence].
///
/// [precedence]: https://nextjs.org/docs/app/building-your-application/configuring/environment-variables#environment-variable-load-order
#[turbo_tasks::function]
pub async fn load_env(project_path: FileSystemPath) -> Result<Vc<Box<dyn ProcessEnv>>> {
let env: Vc<Box<dyn ProcessEnv>> = Vc::upcast(CommandLineProcessEnv::new());
@@ -523,15 +523,14 @@ impl ProcessArgs {
}
}
/// A pool of Node.js workers operating on [entrypoint] with specific [cwd] and
/// [env].
/// A pool of Node.js workers operating on an `entrypoint` with specific `cwd` and `env`.
///
/// The pool will spawn processes when needed and reuses old ones. It will never
/// spawn more then a certain number of concurrent processes. This is specified
/// with the `concurrency` argument in the constructor.
/// The pool will spawn processes when needed and reuses old ones. It will never spawn more then a
/// certain number of concurrent processes. This is specified with the `concurrency` argument in the
/// constructor.
///
/// The worker will *not* use the env of the parent process by default. All env
/// vars need to be provided to make the execution as pure as possible.
/// The worker will *not* use the `env` of the parent process by default. All environment variables
/// need to be provided to make the execution as pure as possible.
#[turbo_tasks::value(cell = "new", serialization = "none", eq = "manual", shared)]
pub struct ChildProcessPool {
cwd: PathBuf,
@@ -14,22 +14,22 @@ use turbopack_core::{
#[derive(Default, Debug, Clone, TraceRawVcs, PartialEq, Eq, NonLocalValue, Encode, Decode)]
pub enum TsConfigHandling {
/// Ignore tsconfig and jsconfig files
/// Ignore tsconfig and jsconfig files.
Disabled,
#[default]
/// Find corresponding tsconfig files based on the location of the file
/// Find corresponding tsconfig files based on the location of the file.
ContextFile,
/// Use the provided config file for all files (if it exists, otherwise fall back to
/// ContextFile)
/// Use the provided config file for all files if it exists, otherwise fall back to the
/// [`Self::ContextFile`] behavior.
Fixed(FileSystemPath),
}
#[turbo_tasks::value(shared)]
#[derive(Default, Clone)]
pub struct ResolveOptionsContext {
/// 1. override options.node_externals and
/// 2. append environment.resolve_conditions
/// 3. override options.extensions
/// - Overrides `options.node_externals`
/// - Appends `environment.resolve_conditions`
/// - Overrides `options.extensions`
pub emulate_environment: Option<ResolvedVc<Environment>>,
pub enable_types: bool,
pub enable_typescript: bool,
@@ -93,8 +93,8 @@ impl ResolveOptionsContext {
Ok(Self::cell(clone))
}
/// Returns a new [Vc<ResolveOptionsContext>] with its import map extended
/// to include the given import map.
/// Returns a new [`Vc<ResolveOptionsContext>`][Self] with its import map extended to include
/// the given import map.
#[turbo_tasks::function]
pub async fn with_extended_import_map(
self: Vc<Self>,
@@ -112,8 +112,8 @@ impl ResolveOptionsContext {
Ok(resolve_options_context.cell())
}
/// Returns a new [Vc<ResolveOptionsContext>] with its fallback import map
/// extended to include the given import map.
/// Returns a new [`Vc<ResolveOptionsContext>`][Self] with its fallback import map extended to
/// include the given import map.
#[turbo_tasks::function]
pub async fn with_extended_fallback_import_map(
self: Vc<Self>,
@@ -35,13 +35,12 @@ impl<T: Send + 'static> ExitGuard<T> {
type BoxExitFuture = Pin<Box<dyn Future<Output = ()> + Send + 'static>>;
/// The singular global ExitHandler. This is primarily used to ensure
/// `ExitHandler::listen` is only called once.
/// The singular global ExitHandler. This is primarily used to ensure `ExitHandler::listen` is only
/// called once.
///
/// The global handler is intentionally not exposed, so that APIs that depend on
/// exit behavior are required to take the `ExitHandler`. This ensures that the
/// `ExitHandler` is configured before these APIs are run, and that these
/// consumers can be used with a callback (e.g. a mock) instead.
/// The global handler is intentionally not exposed, so that APIs that depend on exit behavior are
/// required to take the `ExitHandler`. This ensures that the `ExitHandler` is configured before
/// these APIs are run, and that these consumers can be used with a callback (e.g. a mock) instead.
static GLOBAL_EXIT_HANDLER: OnceLock<Arc<ExitHandler>> = OnceLock::new();
pub struct ExitHandler {
@@ -49,19 +48,16 @@ pub struct ExitHandler {
}
impl ExitHandler {
/// Waits for `SIGINT` using [`tokio::signal::ctrl_c`], and exits the
/// process with exit code `0` after running any futures scheduled with
/// [`ExitHandler::on_exit`].
/// Waits for `SIGINT` using [`tokio::signal::ctrl_c`], and exits the process with exit code `0`
/// after running any futures scheduled with [`ExitHandler::on_exit`].
///
/// As this uses global process signals, this must only be called once, and
/// will panic if called multiple times. Use this when you own the
/// process (e.g. `turbopack-cli`).
/// As this uses global process signals, this must only be called once, and will panic if called
/// multiple times. Use this when you own the process (e.g. `turbopack-cli`).
///
/// If you don't own the process (e.g. you're called as a library, such as
/// in `next-swc`), use [`ExitHandler::new_trigger`] instead.
/// If you don't own the process (e.g. you're called as a library, such as in `next-swc`), use
/// [`ExitHandler::new_receiver`] instead.
///
/// This may listen for other signals, like `SIGTERM` or `SIGPIPE` in the
/// future.
/// This may listen for other signals, like `SIGTERM` or `SIGPIPE` in the future.
pub fn listen() -> &'static Arc<ExitHandler> {
let (handler, receiver) = Self::new_receiver();
if GLOBAL_EXIT_HANDLER.set(handler).is_err() {
@@ -77,15 +73,13 @@ impl ExitHandler {
GLOBAL_EXIT_HANDLER.get().expect("value is set")
}
/// Creates an [`ExitHandler`] that can be manually controlled with an
/// [`ExitReceiver`].
/// Creates an [`ExitHandler`] that can be manually controlled with an [`ExitReceiver`].
///
/// This does not actually exit the process or listen for any signals. If
/// you'd like that behavior, use [`ExitHandler::listen`].
/// This does not actually exit the process or listen for any signals. If you'd like that
/// behavior, use [`ExitHandler::listen`].
///
/// Because this API has no global side-effects and can be called many times
/// within the same process, it is possible to use it to provide a mock
/// [`ExitHandler`] inside unit tests.
/// Because this API has no global side-effects and can be called many times within the same
/// process, it is possible to use it to provide a mock [`ExitHandler`] inside unit tests.
pub fn new_receiver() -> (Arc<ExitHandler>, ExitReceiver) {
let (tx, rx) = mpsc::unbounded_channel();
(Arc::new(ExitHandler { tx }), ExitReceiver { rx })
@@ -93,9 +87,8 @@ impl ExitHandler {
/// Register this given [`Future`] to run upon process exit.
///
/// As there are many ways for a process be killed that are outside of a
/// process's own control (e.g. `SIGKILL` or `SIGSEGV`), this API is
/// provided on a best-effort basis.
/// As there are many ways for a process be killed that are outside of a process's own control
/// (e.g. `SIGKILL` or `SIGSEGV`), this API is provided on a best-effort basis.
pub fn on_exit(&self, fut: impl Future<Output = ()> + Send + 'static) {
// realistically, this error case can only happen with the `new_receiver` API.
self.tx
@@ -110,16 +103,14 @@ pub struct ExitReceiver {
}
impl ExitReceiver {
/// Call this when the process exits to run the futures scheduled via
/// [`ExitHandler::on_exit`].
/// Call this when the process exits to run the futures scheduled via [`ExitHandler::on_exit`].
///
/// As this is intended to be used in a library context, this does not exit
/// the process. It is expected that the process will not exit until
/// this async method finishes executing.
/// As this is intended to be used in a library context, this does not exit the process. It is
/// expected that the process will not exit until this async method finishes executing.
///
/// Additional work can be scheduled using [`ExitHandler::on_exit`] even
/// while this is running, and it will execute before this function
/// finishes. Work attempted to be scheduled after this finishes will panic.
/// Additional work can be scheduled using [`ExitHandler::on_exit`] even while this is running,
/// and it will execute before this function finishes. Work attempted to be scheduled after this
/// finishes will panic.
pub async fn run_exit_handler(mut self) {
let mut set = JoinSet::new();
while let Ok(fut) = self.rx.try_recv() {
@@ -49,8 +49,8 @@ fn get_id<S: Subscriber + for<'a> LookupSpan<'a>>(
.id
}
/// A tracing layer that writes raw trace data to a writer. The data format is
/// defined by [FullTraceRow].
/// A tracing layer that writes raw trace data to a writer. We store data using the [`TraceRow`],
/// serialized with [`postcard`].
pub struct RawTraceLayer<S: Subscriber + for<'a> LookupSpan<'a>> {
trace_writer: TraceWriter,
start: Instant,
@@ -48,10 +48,10 @@ impl TraceWriter {
/// This is a non-blocking writer that writes a file in a background thread.
/// This is inspired by tracing-appender non_blocking, but has some
/// differences:
/// * It allows writing an owned Vec<u8> instead of a reference, so avoiding additional
/// * It allows writing an owned [`Vec<u8>`] instead of a reference, so avoiding additional
/// allocation.
/// * It uses an unbounded channel to avoid slowing down the application at all (memory) cost.
/// * It issues less writes by buffering the data into chunks of WRITE_BUFFER_SIZE, when
/// * It issues less writes by buffering the data into chunks of `WRITE_BUFFER_SIZE`, when
/// possible.
pub fn new<W: Write + Send + 'static>(mut writer: W) -> (Self, TraceWriterGuard) {
let (data_tx, data_rx) = unbounded::<Option<TraceInfoBuffer>>();
@@ -121,32 +121,54 @@ impl WebpackLoaderBuiltinConditionSet for EmptyWebpackLoaderBuiltinConditionSet
}
}
/// The kind of decorators transform to use.
/// [TODO]: might need bikeshed for the name (Ecma)
/// The kind of ECMAScript class decorators transform to use.
///
/// TODO: might need bikeshed for the name (Ecma)
#[derive(Clone, PartialEq, Eq, Debug, TraceRawVcs, NonLocalValue, Encode, Decode)]
pub enum DecoratorsKind {
Legacy,
/// Enables the syntax and behavior of the modern [stage 3 proposal]. This is the recommended
/// transform with JavaScript or [TypeScript 5.0][ts5] or later.
///
/// [stage 3 proposal]: https://github.com/tc39/proposal-decorators
/// [ts5]: https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/#differences-with-experimental-legacy-decorators
Ecma,
/// Enables the legacy class decorator syntax and behavior, as it was defined during the [stage
/// 1 proposal].
///
/// This is the same as setting [`jsx.transform.legacyDecorator` in SWC][swc].
///
/// This option exists for compatibility with the TypeScript compiler's legacy
/// `--experimentalDecorators` feature.
///
/// [stage 1 proposal]: https://github.com/wycats/javascript-decorators/blob/e1bf8d41bfa2591d9/README.md
/// [swc]: https://swc.rs/docs/configuration/compilation#jsctransformlegacydecorator
Legacy,
}
/// Configuration options for the decorators transform.
/// Configuration for the ECMAScript class decorators transform.
///
/// This is not part of Typescript transform: while there are typescript
/// specific transforms (legay decorators), there is an ecma decorator transform
/// as well for the JS.
/// This is not part of TypeScript transform. It can be used with or without TypeScript.
///
/// There is a [legacy TypeScript-specific transform][DecoratorsKind::Legacy] available for when
/// decorators are used with TypeScript.
#[turbo_tasks::value(shared)]
#[derive(Default, Clone, Debug)]
pub struct DecoratorsOptions {
pub decorators_kind: Option<DecoratorsKind>,
/// Option to control whether to emit decorator metadata.
/// (https://www.typescriptlang.org/tsconfig#emitDecoratorMetadata)
/// This'll be applied only if `decorators_type` and
/// `enable_typescript_transform` is enabled.
/// Option to control whether to [emit decorator metadata]. This will be applied only when
/// using [`DecoratorsKind::Legacy`].
///
/// [emit decorator metadata]: https://www.typescriptlang.org/tsconfig#emitDecoratorMetadata
pub emit_decorators_metadata: bool,
/// Mimic babel's `decorators.decoratorsBeforeExport` option.
/// This'll be applied only if `decorators_type` is enabled.
/// ref: https://github.com/swc-project/swc/blob/d4ebb5e6efbed0758f25e46e8f74d7c47ec6cb8f/crates/swc_ecma_parser/src/lib.rs#L327
/// [TODO]: this option is not actively being used currently.
/// Mimic [Babel's `decorators.decoratorsBeforeExport` option][babel]. This'll be applied only
/// if `decorators_type` is enabled.
///
/// TODO: this option is not currently used.
///
/// Ref: <https://github.com/swc-project/swc/blob/d4ebb5e6efbed0/crates/swc_ecma_parser/src/lib.rs#L327>
///
/// [babel]: https://babeljs.io/docs/babel-plugin-proposal-decorators#decoratorsbeforeexport
pub decorators_before_export: bool,
pub use_define_for_class_fields: bool,
}