From b92fc85a256a4b13a6a4b3e0dbaf1a9956509d0b Mon Sep 17 00:00:00 2001 From: elrrrrrrr Date: Sat, 2 May 2026 23:09:21 +0800 Subject: [PATCH 01/16] =?UTF-8?q?perf(pm):=20install=20hot-path=20?= =?UTF-8?q?=E2=80=94=20TTY-gate=20progress,=20stream=20layer=20joins,=20ze?= =?UTF-8?q?ro-copy=20tar=20entries?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three independent install-path changes that compound on cold installs. 1. **TTY-gate `PROGRESS_BAR.inc`/`set_length`** — `install.rs` had 8 raw `PROGRESS_BAR.inc(1)` plus a `set_length` that bypassed the `IS_TTY` short-circuit already present in `ProgressReceiver`. indicatif always takes the internal `Mutex` write-lock even with a hidden draw target, so non-TTY runs (CI, piped output) were paying ~9k Mutex acquisitions per install. Wrapped them in `progress_inc` / `progress_set_length` helpers that match the receiver's gating pattern. 2. **`install_packages` per-layer streaming** — replaced `for task in clone_tasks { task.await?? }` with `FuturesUnordered`. The previous serial join walked tasks in spawn order, so a single slow tarball blocked the layer's `await` loop while later finishers piled up unobserved — pure idle latency between layers on deep trees. Now the layer drains in completion order and propagates the first error early. 3. **Zero-copy tar entries in `extract_tarball_sync`** — `ExtractedEntry` previously held an owned `Vec` copied via `read_to_end` for every file. Each tarball with N files paid N allocs + N memcpys before the parallel-write phase even started. Switched to `(data_offset, data_len)` indices into the decompressed buffer; the rayon write phase slices into the shared `&[u8]` directly. Tar Slip + path-traversal guards untouched, plus a buffer-overrun check on the recorded offsets. Built on top of #2874 to compound with the rayon offload + h1+pool+dns network layer. CI bench-phases-linux will validate the deltas. --- crates/pm/src/service/install.rs | 35 ++++++--- crates/pm/src/util/extractor.rs | 131 ++++++++++++++++++++----------- crates/pm/src/util/logger.rs | 21 +++++ 3 files changed, 127 insertions(+), 60 deletions(-) diff --git a/crates/pm/src/service/install.rs b/crates/pm/src/service/install.rs index 0390a17af1..d1c28fc431 100644 --- a/crates/pm/src/service/install.rs +++ b/crates/pm/src/service/install.rs @@ -1,6 +1,7 @@ use crate::util::cli_enum::ScriptPolicy; use anyhow::Context; use anyhow::Result; +use futures::stream::{FuturesUnordered, StreamExt}; use std::collections::{HashMap, HashSet}; use std::path::Path; use std::time::Instant; @@ -21,7 +22,8 @@ use crate::util::downloader::download_stats; use crate::util::json::load_package_lock_json_from_path; use crate::util::linker::link; use crate::util::logger::{ - PROGRESS_BAR, finish_progress_bar, log_progress, print_install_counts, start_progress_bar, + finish_progress_bar, log_progress, print_install_counts, progress_inc, progress_set_length, + start_progress_bar, }; use utoo_ruborist::compat::{is_cpu_compatible, is_os_compatible}; @@ -83,13 +85,20 @@ pub async fn install_packages( depths.sort_unstable(); for depth in depths.iter() { - let mut clone_tasks: Vec>> = Vec::new(); + // Stream task completion within a layer instead of joining serially. + // The previous `for task in clone_tasks { task.await?? }` walks tasks + // in spawn order — slow tasks block the pop of already-finished + // ones, leaving idle latency between layers on deep trees. With + // FuturesUnordered we drain in completion order, propagating the + // first error early. + let mut clone_tasks: FuturesUnordered>> = + FuturesUnordered::new(); if let Some(packages) = groups.get(depth) { for (path, package) in packages.iter() { // Skip packages based on omit config if should_omit_package(package, omit) { - PROGRESS_BAR.inc(1); + progress_inc(1); continue; } let path = path.clone(); @@ -108,13 +117,13 @@ pub async fn install_packages( if package.link.is_some() { let link_name = extract_package_name(&path); if link_name.is_empty() { - PROGRESS_BAR.inc(1); + progress_inc(1); continue; } link(Path::new(&resolved), Path::new(&path)) .await .with_context(|| format!("Link failed: {resolved} -> {path}"))?; - PROGRESS_BAR.inc(1); + progress_inc(1); continue; } @@ -122,14 +131,14 @@ pub async fn install_packages( if let Some(ref cpu) = package.cpu && !is_cpu_compatible(cpu) { - PROGRESS_BAR.inc(1); + progress_inc(1); continue; } if let Some(ref os) = package.os && !is_os_compatible(os) { - PROGRESS_BAR.inc(1); + progress_inc(1); continue; } @@ -153,24 +162,24 @@ pub async fn install_packages( tracing::warn!( "Optional dependency {name} failed (ignored): {e:#}" ); - PROGRESS_BAR.inc(1); + progress_inc(1); return Ok(()); } return Err(e); } - PROGRESS_BAR.inc(1); + progress_inc(1); log_progress(&format!("{name} resolved")); update_package_binary(&target_path, &name).await }); clone_tasks.push(task); } else { - PROGRESS_BAR.inc(1); + progress_inc(1); } } } - for task in clone_tasks { - task.await??; + while let Some(joined) = clone_tasks.next().await { + joined??; } } @@ -260,7 +269,7 @@ impl InstallService { if !package_lock.packages.is_empty() { start_progress_bar(); - PROGRESS_BAR.set_length(package_lock.packages.len() as u64); + progress_set_length(package_lock.packages.len() as u64); } let link_start = Instant::now(); diff --git a/crates/pm/src/util/extractor.rs b/crates/pm/src/util/extractor.rs index 29b71149b0..a77bf5afc1 100644 --- a/crates/pm/src/util/extractor.rs +++ b/crates/pm/src/util/extractor.rs @@ -41,9 +41,15 @@ fn estimate_uncompressed_size(gzip_data: &[u8]) -> usize { } } +/// Tarball entry recorded during the parse pass, deferred until parallel +/// write. `data_offset`/`data_len` index into the decompressed buffer +/// (lifetime-erased from the buffer for reuse during `par_iter`); avoids +/// the per-file `Vec` allocation+copy that `read_to_end` previously +/// did for every file in the archive. struct ExtractedEntry { path: PathBuf, - content: Vec, + data_offset: usize, + data_len: usize, mode: u32, } @@ -70,7 +76,7 @@ fn extract_tarball_sync(gzip_bytes: Bytes, estimated_size: usize, dest: &Path) - use rayon::prelude::*; use std::collections::HashSet; use std::fs; - use std::io::{Cursor, Read, Write}; + use std::io::Write; // Decompress gzip using libdeflate let mut output = vec![0u8; estimated_size]; @@ -90,49 +96,11 @@ fn extract_tarball_sync(gzip_bytes: Bytes, estimated_size: usize, dest: &Path) - }; output.truncate(actual_size); - // Parse tar entries - let cursor = Cursor::new(&output[..]); - let mut archive = tar::Archive::new(cursor); - let mut entries = Vec::new(); - - for entry_result in archive.entries()? { - let mut entry = entry_result.with_context(|| "Failed to read tar entry")?; - let path = entry - .path() - .with_context(|| "Failed to get entry path")? - .into_owned(); - - // Guard against path traversal (Tar Slip): reject absolute paths - // and entries containing ".." components. - if path.is_absolute() - || path - .components() - .any(|c| matches!(c, std::path::Component::ParentDir)) - { - tracing::warn!("Skipping tar entry with unsafe path: {}", path.display()); - continue; - } - - let full_path = dest.join(&path); - - if !entry.header().entry_type().is_dir() { - let mut content = Vec::new(); - entry - .read_to_end(&mut content) - .with_context(|| format!("Failed to read tar entry: {}", path.display()))?; - - // Normalize to npm/pnpm convention: 0o755 if any exec bit is set, - // else 0o644. Preserving raw tar modes (e.g. 0o640 in google-protobuf) - // breaks world-readability in containers and multi-user setups. - let raw_mode = entry.header().mode().unwrap_or(0o644); - let mode = if raw_mode & 0o111 != 0 { 0o755 } else { 0o644 }; - entries.push(ExtractedEntry { - path: full_path, - content, - mode, - }); - } - } + // Parse tar entries — record offsets into `output` instead of copying + // each file's bytes. The buffer outlives the parallel write phase and + // is read-only after the parse loop, so concurrent slice reads are + // safe. + let entries = parse_tar_entries(&output, dest)?; // Collect every ancestor directory (up to `dest`), then create them // shallowest-first so a single mkdir() per dir is sufficient. @@ -152,11 +120,14 @@ fn extract_tarball_sync(gzip_bytes: Bytes, estimated_size: usize, dest: &Path) - fs::create_dir(dir).ok(); } - // Write files in parallel using rayon + // Write files in parallel using rayon. Each task slices into the + // shared `output` buffer (immutable borrow) — no per-file copy. + let buf: &[u8] = &output; entries.par_iter().try_for_each(|entry| -> Result<()> { let mut file = fs::File::create(&entry.path) .with_context(|| format!("Failed to create: {}", entry.path.display()))?; - file.write_all(&entry.content) + let data = &buf[entry.data_offset..entry.data_offset + entry.data_len]; + file.write_all(data) .with_context(|| format!("Failed to write: {}", entry.path.display()))?; // Skip chmod for 0o644 (most files) — File::create() already produces @@ -181,3 +152,69 @@ fn extract_tarball_sync(gzip_bytes: Bytes, estimated_size: usize, dest: &Path) - Ok(()) } + +/// Walk the tar stream and collect file entries as `(path, offset, len, mode)` +/// tuples into the decompressed `buf`. Skips directories, ignores any +/// path-traversal entries. +fn parse_tar_entries(buf: &[u8], dest: &Path) -> Result> { + use std::io::Cursor; + + let cursor = Cursor::new(buf); + let mut archive = tar::Archive::new(cursor); + let mut entries = Vec::new(); + + for entry_result in archive.entries()? { + let entry = entry_result.with_context(|| "Failed to read tar entry")?; + let path = entry + .path() + .with_context(|| "Failed to get entry path")? + .into_owned(); + + // Guard against path traversal (Tar Slip): reject absolute paths + // and entries containing ".." components. + if path.is_absolute() + || path + .components() + .any(|c| matches!(c, std::path::Component::ParentDir)) + { + tracing::warn!("Skipping tar entry with unsafe path: {}", path.display()); + continue; + } + + if entry.header().entry_type().is_dir() { + continue; + } + + // tar::Entry exposes the byte offset and size inside the parsed + // stream — that's the same `buf` we'll later slice in `par_iter`. + let data_offset = entry.raw_file_position() as usize; + let data_len = entry.size() as usize; + if data_offset + .checked_add(data_len) + .is_none_or(|end| end > buf.len()) + { + anyhow::bail!( + "Tar entry {} extends past decompressed buffer ({}..+{} > {})", + path.display(), + data_offset, + data_len, + buf.len() + ); + } + + let full_path = dest.join(&path); + // Normalize to npm/pnpm convention: 0o755 if any exec bit is set, + // else 0o644. Preserving raw tar modes (e.g. 0o640 in google-protobuf) + // breaks world-readability in containers and multi-user setups. + let raw_mode = entry.header().mode().unwrap_or(0o644); + let mode = if raw_mode & 0o111 != 0 { 0o755 } else { 0o644 }; + entries.push(ExtractedEntry { + path: full_path, + data_offset, + data_len, + mode, + }); + } + + Ok(entries) +} diff --git a/crates/pm/src/util/logger.rs b/crates/pm/src/util/logger.rs index 6ba124bb24..c8570b2eca 100644 --- a/crates/pm/src/util/logger.rs +++ b/crates/pm/src/util/logger.rs @@ -161,6 +161,27 @@ pub fn log_progress(text: &str) { PROGRESS_BAR.set_message(text.to_string()); } +/// TTY-gated `PROGRESS_BAR.inc(1)`. Non-TTY callers pay no Mutex cost — +/// indicatif's `inc` always takes the internal `Mutex` +/// write-lock even with a hidden draw target, which contends across the +/// install loop's spawned tasks. +#[inline] +pub fn progress_inc(n: u64) { + if !*IS_TTY { + return; + } + PROGRESS_BAR.inc(n); +} + +/// TTY-gated `PROGRESS_BAR.set_length`. Same rationale as [`progress_inc`]. +#[inline] +pub fn progress_set_length(len: u64) { + if !*IS_TTY { + return; + } + PROGRESS_BAR.set_length(len); +} + // Global timer for log_time/log_time_end static START_TIME: OnceCell = OnceCell::new(); From 9df637ffaebbd8ed1355af0b588b601fe804e959 Mon Sep 17 00:00:00 2001 From: elrrrrrrr Date: Sun, 3 May 2026 08:41:05 +0800 Subject: [PATCH 02/16] perf(pm): release download permit before CPU-bound extract phase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `download_to_cache` previously held the `DOWNLOAD_SEMAPHORE` permit across both the network download AND the CPU-bound `extract_and_write` call (libdeflate decompress + tar parse + rayon parallel writes, ~50–200ms per package). The semaphore is meant to gate concurrent network I/O — coupling it to extract artificially limits download fan-out by ~50% on tarball-heavy installs. Drop the permit immediately after `download_bytes` returns. Extract runs on rayon's CPU pool which is independent of `DOWNLOAD_SEMAPHORE`, so the next download task can start as soon as bytes land in memory. With 64 slots, the effective concurrent download count goes from ~64 / (1 + extract_ratio) to a true 64. Compounds with the prefetch back-pressure gate: prefetch's 16-slot sub-limit still bounds it, but the slots themselves now turn over faster. --- crates/pm/src/util/downloader.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/crates/pm/src/util/downloader.rs b/crates/pm/src/util/downloader.rs index 76526eedda..727d980616 100644 --- a/crates/pm/src/util/downloader.rs +++ b/crates/pm/src/util/downloader.rs @@ -167,10 +167,17 @@ pub async fn download_to_cache(name: &str, version: &str, tarball_url: &str) -> return Some(cache_path); } - // Download (semaphore controlled) + // Download (semaphore controlled). The permit gates only + // network I/O — extract runs on rayon's CPU pool and does + // not contend with download bandwidth, so we release the + // permit before the CPU-bound phase. This lets the next + // `download_to_cache` start immediately, doubling effective + // concurrency on tarball-heavy installs (download tasks no + // longer block on a peer task's ~50–200ms libdeflate + + // tar parse + parallel writes). let semaphore = DOWNLOAD_SEMAPHORE .get_or_init(|| Semaphore::new(get_manifests_concurrency_limit_sync())); - let _permit = semaphore.acquire().await.ok()?; + let permit = semaphore.acquire().await.ok()?; let bytes = download_bytes(&tarball_url) .await .inspect_err(|e| { @@ -183,6 +190,7 @@ pub async fn download_to_cache(name: &str, version: &str, tarball_url: &str) -> ) }) .ok()?; + drop(permit); // Extract extract_and_write(bytes, &cache_path) From dff9fb2b4612e0961a8b54bc340d0db6f031f5ac Mon Sep 17 00:00:00 2001 From: elrrrrrrr Date: Sun, 3 May 2026 08:42:29 +0800 Subject: [PATCH 03/16] =?UTF-8?q?perf(pm):=20linearize=20extract=20dir=20c?= =?UTF-8?q?ollection=20=E2=80=94=20Vec=20+=20sort+dedup=20over=20per-entry?= =?UTF-8?q?=20HashSet?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `extract_tarball_sync` builds the set of ancestor directories before mkdir-ing them. Old code inserted into a `HashSet` per entry, which allocated a PathBuf for every ancestor of every file even when most entries shared the same parent dirs (the common case for npm packages — typically 50+ files under 1–3 unique dirs). Switch to: Vec::with_capacity(entries.len()) → push every ancestor → sort + dedup. Allocation pattern flips from O(unique_dirs × visit_count) PathBufs inserted into a hash table to a single Vec push + one sort pass. Same correctness (dedup before mkdir, depth-ascending order preserved via second sort_by_key on os_str length). --- crates/pm/src/util/extractor.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/crates/pm/src/util/extractor.rs b/crates/pm/src/util/extractor.rs index a77bf5afc1..f342ac2155 100644 --- a/crates/pm/src/util/extractor.rs +++ b/crates/pm/src/util/extractor.rs @@ -74,7 +74,6 @@ async fn extract_tarball(gzip_bytes: Bytes, dest: &Path) -> Result<()> { /// Synchronous extraction: decompress + parse + parallel write, all on rayon. fn extract_tarball_sync(gzip_bytes: Bytes, estimated_size: usize, dest: &Path) -> Result<()> { use rayon::prelude::*; - use std::collections::HashSet; use std::fs; use std::io::Write; @@ -104,18 +103,26 @@ fn extract_tarball_sync(gzip_bytes: Bytes, estimated_size: usize, dest: &Path) - // Collect every ancestor directory (up to `dest`), then create them // shallowest-first so a single mkdir() per dir is sufficient. - let mut seen = HashSet::new(); + // + // Push to a Vec first (cheap) and dedup once at the end via sort + // — replaces a per-entry `HashSet` insert that allocated + // a PathBuf for every ancestor on every entry, even when most + // entries share the same parent dirs (the common case). + let mut dirs: Vec = Vec::with_capacity(entries.len()); for entry in &entries { let mut p = entry.path.parent(); while let Some(dir) = p { - if dir == dest || !seen.insert(dir.to_path_buf()) { + if dir == dest { break; } + dirs.push(dir.to_path_buf()); p = dir.parent(); } } - let mut dirs: Vec<_> = seen.into_iter().collect(); - dirs.sort_unstable_by_key(|p| p.as_os_str().len()); + dirs.sort_unstable(); + dirs.dedup(); + // Sort by depth ascending so parent exists before child mkdir. + dirs.sort_by_key(|p| p.as_os_str().len()); for dir in &dirs { fs::create_dir(dir).ok(); } From f013fcb25da1dc8188943ee873a41ed37110b974 Mon Sep 17 00:00:00 2001 From: elrrrrrrr Date: Sun, 3 May 2026 08:44:01 +0800 Subject: [PATCH 04/16] perf(pm): skip update_package_binary for npm.org registry `should_skip_binary_mirror()` already gates `get_envs()` for npm.org users, but `update_package_binary` was unconditionally: 1. Fetching `binary-mirror-config/latest` from the registry (one extra network round-trip per process; cached after). 2. Looking up the package name in the (large) China mirrors hashmap for every package in the install loop. For npm.org the mirror config is irrelevant. Add the same gate at the top of `update_package_binary`. Mirrors the existing `get_envs` flow and shaves the cold-path network call entirely. --- crates/pm/src/service/binary.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/crates/pm/src/service/binary.rs b/crates/pm/src/service/binary.rs index c6f95cb45e..33f0cda141 100644 --- a/crates/pm/src/service/binary.rs +++ b/crates/pm/src/service/binary.rs @@ -233,6 +233,15 @@ async fn handle_cypress( } pub async fn update_package_binary(dir: &Path, name: &str) -> Result<()> { + // npm.org users have no use for the China binary mirror config; + // skipping here avoids the per-process `binary-mirror-config/latest` + // fetch + per-package hashmap lookup that fires for every cloned + // package in the install loop. Mirrors `get_envs`'s gate so the + // two paths agree on when the mirror layer is active. + if should_skip_binary_mirror() { + return Ok(()); + } + let config = load_config().await?; let mirrors = config["mirrors"]["china"] From 5d0b8562ad297ff032ff8d1e193732d0af9a2a82 Mon Sep 17 00:00:00 2001 From: elrrrrrrr Date: Sun, 3 May 2026 09:05:19 +0800 Subject: [PATCH 05/16] perf(pm): find_real_src uses file_type instead of metadata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `find_real_src` is called from `clone()` for every cold-cache install to locate the wrapper subdir (npm tarballs ship under `package/`). The original implementation called `entry.metadata().await` per candidate, which always issues an `lstat` syscall. `entry.file_type().await` reads `d_type` from the cached `readdir` result on ext4/btrfs/xfs (no extra syscall when the filesystem populates it; falls back to lstat only on `DT_UNKNOWN`). For 1000 packages × 3–5 entries-per-cache-dir that's 3000–5000 fewer stat syscalls on the cold install path. --- crates/pm/src/util/cloner.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/pm/src/util/cloner.rs b/crates/pm/src/util/cloner.rs index 76c6029702..f1eba8e807 100644 --- a/crates/pm/src/util/cloner.rs +++ b/crates/pm/src/util/cloner.rs @@ -326,8 +326,12 @@ async fn validate_directory(src: &Path, dst: &Path) -> Result { pub async fn find_real_src>(src: P) -> Option { let mut read_dir = fs::read_dir(src.as_ref()).await.ok()?; while let Some(entry) = read_dir.next_entry().await.ok()? { - if let Ok(metadata) = entry.metadata().await - && metadata.is_dir() + // `file_type()` reads `d_type` from the cached readdir result on + // ext4/btrfs/xfs (no extra syscall); `metadata()` always issues + // an `lstat`. Saves ~3–5 stats per call × N packages on the + // cold install hot path. + if let Ok(file_type) = entry.file_type().await + && file_type.is_dir() && let Some(name) = entry.path().file_name() && name.to_string_lossy() != ".utoo_built" { From d688101c0e8d309be7028ddf61cfa7dc1cf4a8bc Mon Sep 17 00:00:00 2001 From: elrrrrrrr Date: Sun, 3 May 2026 08:21:09 +0800 Subject: [PATCH 06/16] perf(pm): OnceMap fast-path eliminates spawn + alloc churn on cache hit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Push the install hot-path further: when the BFS pipeline (or a sibling depth in the install loop) has already cloned/downloaded a target, the follow-up `clone_package_once` / `download_to_cache` calls were still paying: - 5 string allocs (`name.to_string()` × 3 + `format!()` + `target_path.to_path_buf()`) - a `tokio::spawn` (separate task struct + scheduler enqueue) - a future construction with all 5 captured strings …before reaching the OnceMap entry whose value is already `Done`. On ant-design (~1000 packages, 95%+ pre-cloned by pipeline at install time), that's 5000+ small allocs and 1000+ spawns of pure no-ops. This commit: 1. **`OnceMap::is_done`** (ruborist) — sync, allocation-free probe of the DashMap. Returns `false` for `Waiting` entries so we don't bypass the subscription path. 2. **`clone_package_once` fast-path** — early `is_done` short-circuit before the param clones, before the `get_or_init` future. 3. **`download_to_cache` fast-path** — same shape; reuses the cached `Arc` via a no-op `get_or_init` on the hot branch so we stay sound (no parallel `register/complete` race with prefetch). 4. **install_packages eager skip** — checks `CLONE_CACHE.is_done` before `tokio::spawn`. Skips the entire spawn + scheduler dance for already-cloned targets. Made `CLONE_CACHE` and `cache_key` `pub(crate)` so install can probe without going through the round-trip clone helper. Compounds with the existing PR stack: prefetch fans out N downloads ahead, install loop now skips the corresponding 95% of spawns when those finish first. --- crates/pm/src/service/install.rs | 11 ++++++++++- crates/pm/src/util/cloner.rs | 15 ++++++++++++--- crates/pm/src/util/downloader.rs | 15 +++++++++++++++ crates/ruborist/src/util/oncemap.rs | 16 ++++++++++++++++ 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/crates/pm/src/service/install.rs b/crates/pm/src/service/install.rs index d1c28fc431..607d74ff66 100644 --- a/crates/pm/src/service/install.rs +++ b/crates/pm/src/service/install.rs @@ -17,7 +17,7 @@ use crate::helper::workspace::init_project_root; use crate::model::package::PackageInfo; use crate::service::rebuild::RebuildService; use crate::util::cli_enum::{OmitType, PackageAction, SaveType}; -use crate::util::cloner::clone_count; +use crate::util::cloner::{CLONE_CACHE, cache_key, clone_count}; use crate::util::downloader::download_stats; use crate::util::json::load_package_lock_json_from_path; use crate::util::linker::link; @@ -150,6 +150,15 @@ pub async fn install_packages( let cwd_clone = cwd.to_path_buf(); let target_path = cwd_clone.join(&path); + // Eager skip: if the BFS pipeline (or a sibling + // depth) already cloned this target, the spawn + + // future construction below is pure overhead. Probe + // CLONE_CACHE before doing any of it. + if CLONE_CACHE.is_done(&cache_key(&target_path)) { + progress_inc(1); + continue; + } + // Check if this is an optional dependency let is_optional = package.optional == Some(true) || package.dev_optional == Some(true); diff --git a/crates/pm/src/util/cloner.rs b/crates/pm/src/util/cloner.rs index f1eba8e807..e41073fa04 100644 --- a/crates/pm/src/util/cloner.rs +++ b/crates/pm/src/util/cloner.rs @@ -22,7 +22,7 @@ use crate::fs; /// `ERROR_SHARING_VIOLATION` (os error 32) on Windows. `PathBuf` from /// `Path::components().collect()` parses both separators uniformly and /// rebuilds with the OS-preferred one, giving a stable key. -static CLONE_CACHE: Lazy> = Lazy::new(OnceMap::new); +pub(crate) static CLONE_CACHE: Lazy> = Lazy::new(OnceMap::new); /// Number of `node_modules/` directories freshly materialized this run. /// Mirrors pnpm's "added" semantic. @@ -35,12 +35,12 @@ pub fn clone_count() -> usize { /// Normalize a target path into the canonical key used by `CLONE_CACHE`. #[cfg(windows)] -fn cache_key(target_path: &Path) -> PathBuf { +pub(crate) fn cache_key(target_path: &Path) -> PathBuf { target_path.components().collect() } #[cfg(not(windows))] -fn cache_key(target_path: &Path) -> PathBuf { +pub(crate) fn cache_key(target_path: &Path) -> PathBuf { target_path.to_path_buf() } @@ -65,6 +65,15 @@ pub async fn clone_package_once( target_path: &Path, ) -> Result<()> { let key = cache_key(target_path); + + // Hot fast-path: most install-loop calls hit a target the BFS + // pipeline (or a previous depth's spawn) already cloned. Probe + // CLONE_CACHE before paying the 5 string allocs + future + // construction below. + if CLONE_CACHE.is_done(&key) { + return Ok(()); + } + let err_label = format!("{name}@{version}"); let name = name.to_string(); let version = version.to_string(); diff --git a/crates/pm/src/util/downloader.rs b/crates/pm/src/util/downloader.rs index 727d980616..7d400aa6f6 100644 --- a/crates/pm/src/util/downloader.rs +++ b/crates/pm/src/util/downloader.rs @@ -149,6 +149,21 @@ pub async fn resolve_cache_path(name: &str, version: &str, tarball_url: &str) -> /// For git-resolved packages, use [`resolve_cache_path`] instead. pub async fn download_to_cache(name: &str, version: &str, tarball_url: &str) -> Option { let key = format!("{}@{}", name, version); + + // Hot fast-path: when the prefetch (or a sibling resolve) already + // populated the OnceMap entry, skip the per-call string allocs and + // future construction by reusing the cached `Arc`. The + // pipeline path drives `download_to_cache` for every BFS-resolved + // package, and install-loop calls usually arrive after — most hit + // a `Done` slot. + if DOWNLOAD_CACHE.is_done(&key) { + return DOWNLOAD_CACHE + .get_or_init(key, || async { None }) + .await + .as_deref() + .cloned(); + } + let cache_dir = get_cache_dir(); let name = name.to_string(); let version = version.to_string(); diff --git a/crates/ruborist/src/util/oncemap.rs b/crates/ruborist/src/util/oncemap.rs index 40c4aeee20..25255e797c 100644 --- a/crates/ruborist/src/util/oncemap.rs +++ b/crates/ruborist/src/util/oncemap.rs @@ -118,6 +118,22 @@ where } } + /// Sync, allocation-free check for a completed entry. + /// + /// Lets hot-path callers short-circuit before paying string clones / + /// future construction for a key that's already been resolved by a + /// peer (e.g. install loop deduping against pipeline-pre-cloned + /// targets, where 95%+ of packages hit a `Done` slot). + /// + /// Returns `false` for both unknown keys and `Waiting` slots; only + /// `Done` is reported. Waiting entries fall through to the normal + /// `get_or_init` path which knows how to subscribe and wait. + pub fn is_done(&self, key: &K) -> bool { + self.map + .get(key) + .is_some_and(|e| matches!(e.value(), Value::Done(_))) + } + /// Wait for a key to complete. /// /// - If the key exists and is Done, returns immediately. From aaf95820fdff988dc94e4c92b09b22b1a0cc3c6e Mon Sep 17 00:00:00 2001 From: elrrrrrrr Date: Wed, 6 May 2026 11:52:43 +0800 Subject: [PATCH 07/16] perf(pm): drop PathBuf alloc + redundant len-sort in extract dir collection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two follow-ups on the prior `HashSet` → `Vec` linearization: 1. Switch the dir Vec from `Vec` to `Vec<&Path>` borrowing straight out of `entries.path`. `entries` outlives the mkdir + parallel-write phases, so the borrow lifetime is sound. Saves the per-ancestor `to_path_buf()` allocation — typical npm package has 1-3 unique dirs walked from 50+ files, so the alloc count was roughly `50 × 3 = 150 PathBufs` per package, gone now. 2. Drop the secondary `sort_by_key(|p| p.as_os_str().len())`. It was defensively sorting by byte length on top of the lex `sort_unstable`, but every dir here is a descendant of the same `dest` root — a parent's path is a strict byte prefix of any descendant's, so it sorts before in lex order regardless. Save one full sort pass on the deduped slice. --- crates/pm/src/util/extractor.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/pm/src/util/extractor.rs b/crates/pm/src/util/extractor.rs index f342ac2155..45276f7304 100644 --- a/crates/pm/src/util/extractor.rs +++ b/crates/pm/src/util/extractor.rs @@ -101,28 +101,28 @@ fn extract_tarball_sync(gzip_bytes: Bytes, estimated_size: usize, dest: &Path) - // safe. let entries = parse_tar_entries(&output, dest)?; - // Collect every ancestor directory (up to `dest`), then create them - // shallowest-first so a single mkdir() per dir is sufficient. + // Collect every ancestor directory (up to `dest`) by borrowing + // straight out of `entries.path` — no per-entry PathBuf allocation. + // `entries` outlives the mkdir + parallel-write phases, so the + // `&Path` references stay valid. // - // Push to a Vec first (cheap) and dedup once at the end via sort - // — replaces a per-entry `HashSet` insert that allocated - // a PathBuf for every ancestor on every entry, even when most - // entries share the same parent dirs (the common case). - let mut dirs: Vec = Vec::with_capacity(entries.len()); + // Lex sort + dedup is all we need: every dir here is a descendant + // of the same `dest` root, so a parent's path is a strict byte + // prefix of any descendant's path → it sorts before. The previous + // secondary `sort_by_key(len)` is redundant. + let mut dirs: Vec<&Path> = Vec::with_capacity(entries.len()); for entry in &entries { let mut p = entry.path.parent(); while let Some(dir) = p { if dir == dest { break; } - dirs.push(dir.to_path_buf()); + dirs.push(dir); p = dir.parent(); } } dirs.sort_unstable(); dirs.dedup(); - // Sort by depth ascending so parent exists before child mkdir. - dirs.sort_by_key(|p| p.as_os_str().len()); for dir in &dirs { fs::create_dir(dir).ok(); } From d3e73637f967ab8360e94b6d07d2cb27acaaafb1 Mon Sep 17 00:00:00 2001 From: elrrrrrrr Date: Wed, 6 May 2026 13:59:36 +0800 Subject: [PATCH 08/16] perf(pm): add OnceMap::get for single-lookup cached value retrieval MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses two gemini-code-assist review notes on #2887: 1. `OnceMap::get(&self, &K) -> Option>` — sync, single-DashMap-lookup accessor for the value-returning case. Returns the `Arc` only when the slot is `Done`. `is_done` stays for the `V = ()` case (CLONE_CACHE) where presence is all we care about. 2. `download_to_cache` hot fast-path: replace if DOWNLOAD_CACHE.is_done(&key) { return DOWNLOAD_CACHE .get_or_init(key, || async { None }) .await .as_deref() .cloned(); } with if let Some(cache_path) = DOWNLOAD_CACHE.get(&key) { return Some((*cache_path).clone()); } Two DashMap lookups → one. No async closure allocated. No future awaited. Same semantics on the cached-path branch. --- crates/pm/src/util/downloader.rs | 8 ++------ crates/ruborist/src/util/oncemap.rs | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/crates/pm/src/util/downloader.rs b/crates/pm/src/util/downloader.rs index 7d400aa6f6..c1b8bcc14d 100644 --- a/crates/pm/src/util/downloader.rs +++ b/crates/pm/src/util/downloader.rs @@ -156,12 +156,8 @@ pub async fn download_to_cache(name: &str, version: &str, tarball_url: &str) -> // pipeline path drives `download_to_cache` for every BFS-resolved // package, and install-loop calls usually arrive after — most hit // a `Done` slot. - if DOWNLOAD_CACHE.is_done(&key) { - return DOWNLOAD_CACHE - .get_or_init(key, || async { None }) - .await - .as_deref() - .cloned(); + if let Some(cache_path) = DOWNLOAD_CACHE.get(&key) { + return Some((*cache_path).clone()); } let cache_dir = get_cache_dir(); diff --git a/crates/ruborist/src/util/oncemap.rs b/crates/ruborist/src/util/oncemap.rs index 25255e797c..903fbd37ce 100644 --- a/crates/ruborist/src/util/oncemap.rs +++ b/crates/ruborist/src/util/oncemap.rs @@ -134,6 +134,23 @@ where .is_some_and(|e| matches!(e.value(), Value::Done(_))) } + /// Sync fetch of a completed value, single map lookup. + /// + /// Lets value-returning hot-path callers (e.g. `download_to_cache`'s + /// `Arc` slot) skip the `is_done` + `get_or_init(no-op)` + /// double-lookup dance — one `DashMap::get` and we return the + /// `Arc` if the entry is `Done`, `None` otherwise. + /// + /// Returns `None` for both unknown keys and `Waiting` slots; only + /// `Done` is reported. Use `is_done` instead when `V = ()` and you + /// only care about presence. + pub fn get(&self, key: &K) -> Option> { + self.map.get(key).and_then(|e| match e.value() { + Value::Done(v) => Some(Arc::clone(v)), + Value::Waiting(_) => None, + }) + } + /// Wait for a key to complete. /// /// - If the key exists and is Done, returns immediately. From 8f5959e74c1064dcdb5f63afb01312203e373cfd Mon Sep 17 00:00:00 2001 From: elrrrrrrr Date: Wed, 6 May 2026 14:57:30 +0800 Subject: [PATCH 09/16] Revert "perf(pm): add OnceMap::get for single-lookup cached value retrieval" This reverts commit d3e73637f967ab8360e94b6d07d2cb27acaaafb1. --- crates/pm/src/util/downloader.rs | 8 ++++++-- crates/ruborist/src/util/oncemap.rs | 17 ----------------- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/crates/pm/src/util/downloader.rs b/crates/pm/src/util/downloader.rs index c1b8bcc14d..7d400aa6f6 100644 --- a/crates/pm/src/util/downloader.rs +++ b/crates/pm/src/util/downloader.rs @@ -156,8 +156,12 @@ pub async fn download_to_cache(name: &str, version: &str, tarball_url: &str) -> // pipeline path drives `download_to_cache` for every BFS-resolved // package, and install-loop calls usually arrive after — most hit // a `Done` slot. - if let Some(cache_path) = DOWNLOAD_CACHE.get(&key) { - return Some((*cache_path).clone()); + if DOWNLOAD_CACHE.is_done(&key) { + return DOWNLOAD_CACHE + .get_or_init(key, || async { None }) + .await + .as_deref() + .cloned(); } let cache_dir = get_cache_dir(); diff --git a/crates/ruborist/src/util/oncemap.rs b/crates/ruborist/src/util/oncemap.rs index 903fbd37ce..25255e797c 100644 --- a/crates/ruborist/src/util/oncemap.rs +++ b/crates/ruborist/src/util/oncemap.rs @@ -134,23 +134,6 @@ where .is_some_and(|e| matches!(e.value(), Value::Done(_))) } - /// Sync fetch of a completed value, single map lookup. - /// - /// Lets value-returning hot-path callers (e.g. `download_to_cache`'s - /// `Arc` slot) skip the `is_done` + `get_or_init(no-op)` - /// double-lookup dance — one `DashMap::get` and we return the - /// `Arc` if the entry is `Done`, `None` otherwise. - /// - /// Returns `None` for both unknown keys and `Waiting` slots; only - /// `Done` is reported. Use `is_done` instead when `V = ()` and you - /// only care about presence. - pub fn get(&self, key: &K) -> Option> { - self.map.get(key).and_then(|e| match e.value() { - Value::Done(v) => Some(Arc::clone(v)), - Value::Waiting(_) => None, - }) - } - /// Wait for a key to complete. /// /// - If the key exists and is Done, returns immediately. From b53e9c0aa995141eb725eb8cc4c511be8d7d5141 Mon Sep 17 00:00:00 2001 From: elrrrrrrr Date: Wed, 6 May 2026 15:28:12 +0800 Subject: [PATCH 10/16] Reapply "perf(pm): add OnceMap::get for single-lookup cached value retrieval" This reverts commit 8f5959e74c1064dcdb5f63afb01312203e373cfd. --- crates/pm/src/util/downloader.rs | 8 ++------ crates/ruborist/src/util/oncemap.rs | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/crates/pm/src/util/downloader.rs b/crates/pm/src/util/downloader.rs index 7d400aa6f6..c1b8bcc14d 100644 --- a/crates/pm/src/util/downloader.rs +++ b/crates/pm/src/util/downloader.rs @@ -156,12 +156,8 @@ pub async fn download_to_cache(name: &str, version: &str, tarball_url: &str) -> // pipeline path drives `download_to_cache` for every BFS-resolved // package, and install-loop calls usually arrive after — most hit // a `Done` slot. - if DOWNLOAD_CACHE.is_done(&key) { - return DOWNLOAD_CACHE - .get_or_init(key, || async { None }) - .await - .as_deref() - .cloned(); + if let Some(cache_path) = DOWNLOAD_CACHE.get(&key) { + return Some((*cache_path).clone()); } let cache_dir = get_cache_dir(); diff --git a/crates/ruborist/src/util/oncemap.rs b/crates/ruborist/src/util/oncemap.rs index 25255e797c..903fbd37ce 100644 --- a/crates/ruborist/src/util/oncemap.rs +++ b/crates/ruborist/src/util/oncemap.rs @@ -134,6 +134,23 @@ where .is_some_and(|e| matches!(e.value(), Value::Done(_))) } + /// Sync fetch of a completed value, single map lookup. + /// + /// Lets value-returning hot-path callers (e.g. `download_to_cache`'s + /// `Arc` slot) skip the `is_done` + `get_or_init(no-op)` + /// double-lookup dance — one `DashMap::get` and we return the + /// `Arc` if the entry is `Done`, `None` otherwise. + /// + /// Returns `None` for both unknown keys and `Waiting` slots; only + /// `Done` is reported. Use `is_done` instead when `V = ()` and you + /// only care about presence. + pub fn get(&self, key: &K) -> Option> { + self.map.get(key).and_then(|e| match e.value() { + Value::Done(v) => Some(Arc::clone(v)), + Value::Waiting(_) => None, + }) + } + /// Wait for a key to complete. /// /// - If the key exists and is Done, returns immediately. From 900ab16fc203846e9f5f9f58df2e2a64d33df526 Mon Sep 17 00:00:00 2001 From: elrrrrrrr Date: Wed, 6 May 2026 16:59:41 +0800 Subject: [PATCH 11/16] =?UTF-8?q?refactor(pm):=20/simplify=20cleanup=20?= =?UTF-8?q?=E2=80=94=20comment=20trim=20+=20leaky-abstraction=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three review-driven cleanups that don't change behavior: 1. **Encapsulate CLONE_CACHE**: revert the prior `pub(crate)` exposure of `CLONE_CACHE` and `cache_key`, replace the install-loop's eager skip with a small `is_target_cloned(&Path) -> bool` helper. The install loop no longer imports cache internals for one logical probe. 2. **Drop redundant `OnceMap::is_done` impl**: implement as `self.get(key).is_some()` so the two methods don't drift on the same DashMap.get + Value::Done predicate. 3. **Trim comments**: remove WHAT/narrative blocks that restate the code (extract dir collection, FuturesUnordered streaming, fast-path probes in clone_package_once / download_to_cache, npm.org binary gate, TTY-gated progress helpers, permit-drop). Keep only WHY when non-obvious (e.g. "lex sort suffices because every dir descends from `dest`", "indicatif inc takes Mutex even with hidden draw target"). Tests + clippy clean. Bench unaffected (no logic change). --- crates/pm/src/service/binary.rs | 6 +----- crates/pm/src/service/install.rs | 19 +++++++------------ crates/pm/src/util/cloner.rs | 19 ++++++++++++------- crates/pm/src/util/downloader.rs | 17 +++-------------- crates/pm/src/util/extractor.rs | 20 ++++---------------- crates/pm/src/util/logger.rs | 7 ++----- crates/ruborist/src/util/oncemap.rs | 28 +++++----------------------- next.js | 2 +- 8 files changed, 35 insertions(+), 83 deletions(-) diff --git a/crates/pm/src/service/binary.rs b/crates/pm/src/service/binary.rs index 33f0cda141..7ef28fb2af 100644 --- a/crates/pm/src/service/binary.rs +++ b/crates/pm/src/service/binary.rs @@ -233,11 +233,7 @@ async fn handle_cypress( } pub async fn update_package_binary(dir: &Path, name: &str) -> Result<()> { - // npm.org users have no use for the China binary mirror config; - // skipping here avoids the per-process `binary-mirror-config/latest` - // fetch + per-package hashmap lookup that fires for every cloned - // package in the install loop. Mirrors `get_envs`'s gate so the - // two paths agree on when the mirror layer is active. + // npm.org has no China mirror layer — skip alongside `get_envs`. if should_skip_binary_mirror() { return Ok(()); } diff --git a/crates/pm/src/service/install.rs b/crates/pm/src/service/install.rs index 607d74ff66..fc382aaa4b 100644 --- a/crates/pm/src/service/install.rs +++ b/crates/pm/src/service/install.rs @@ -17,7 +17,7 @@ use crate::helper::workspace::init_project_root; use crate::model::package::PackageInfo; use crate::service::rebuild::RebuildService; use crate::util::cli_enum::{OmitType, PackageAction, SaveType}; -use crate::util::cloner::{CLONE_CACHE, cache_key, clone_count}; +use crate::util::cloner::{clone_count, is_target_cloned}; use crate::util::downloader::download_stats; use crate::util::json::load_package_lock_json_from_path; use crate::util::linker::link; @@ -85,12 +85,8 @@ pub async fn install_packages( depths.sort_unstable(); for depth in depths.iter() { - // Stream task completion within a layer instead of joining serially. - // The previous `for task in clone_tasks { task.await?? }` walks tasks - // in spawn order — slow tasks block the pop of already-finished - // ones, leaving idle latency between layers on deep trees. With - // FuturesUnordered we drain in completion order, propagating the - // first error early. + // Drain in completion order so a slow tarball doesn't pin its + // siblings, and surface the first error early. let mut clone_tasks: FuturesUnordered>> = FuturesUnordered::new(); @@ -150,11 +146,10 @@ pub async fn install_packages( let cwd_clone = cwd.to_path_buf(); let target_path = cwd_clone.join(&path); - // Eager skip: if the BFS pipeline (or a sibling - // depth) already cloned this target, the spawn + - // future construction below is pure overhead. Probe - // CLONE_CACHE before doing any of it. - if CLONE_CACHE.is_done(&cache_key(&target_path)) { + // Eager skip: if the BFS pipeline (or a sibling depth) + // already cloned this target, skip the spawn + future + // construction altogether. + if is_target_cloned(&target_path) { progress_inc(1); continue; } diff --git a/crates/pm/src/util/cloner.rs b/crates/pm/src/util/cloner.rs index e41073fa04..58bb218d71 100644 --- a/crates/pm/src/util/cloner.rs +++ b/crates/pm/src/util/cloner.rs @@ -22,7 +22,7 @@ use crate::fs; /// `ERROR_SHARING_VIOLATION` (os error 32) on Windows. `PathBuf` from /// `Path::components().collect()` parses both separators uniformly and /// rebuilds with the OS-preferred one, giving a stable key. -pub(crate) static CLONE_CACHE: Lazy> = Lazy::new(OnceMap::new); +static CLONE_CACHE: Lazy> = Lazy::new(OnceMap::new); /// Number of `node_modules/` directories freshly materialized this run. /// Mirrors pnpm's "added" semantic. @@ -35,15 +35,22 @@ pub fn clone_count() -> usize { /// Normalize a target path into the canonical key used by `CLONE_CACHE`. #[cfg(windows)] -pub(crate) fn cache_key(target_path: &Path) -> PathBuf { +fn cache_key(target_path: &Path) -> PathBuf { target_path.components().collect() } #[cfg(not(windows))] -pub(crate) fn cache_key(target_path: &Path) -> PathBuf { +fn cache_key(target_path: &Path) -> PathBuf { target_path.to_path_buf() } +/// Check whether a target path has already been cloned this run. +/// Used by the install loop to skip `tokio::spawn` for packages the +/// pipeline already finished. +pub fn is_target_cloned(target_path: &Path) -> bool { + CLONE_CACHE.is_done(&cache_key(target_path)) +} + /// Wait for a pending clone at the given target path to complete (if any). /// /// Used by the pipeline clone worker to ensure parent packages are @@ -66,10 +73,8 @@ pub async fn clone_package_once( ) -> Result<()> { let key = cache_key(target_path); - // Hot fast-path: most install-loop calls hit a target the BFS - // pipeline (or a previous depth's spawn) already cloned. Probe - // CLONE_CACHE before paying the 5 string allocs + future - // construction below. + // Skip the param clones + future construction when the pipeline + // (or a sibling task) already cloned this target. if CLONE_CACHE.is_done(&key) { return Ok(()); } diff --git a/crates/pm/src/util/downloader.rs b/crates/pm/src/util/downloader.rs index c1b8bcc14d..494c2d1f6b 100644 --- a/crates/pm/src/util/downloader.rs +++ b/crates/pm/src/util/downloader.rs @@ -150,12 +150,7 @@ pub async fn resolve_cache_path(name: &str, version: &str, tarball_url: &str) -> pub async fn download_to_cache(name: &str, version: &str, tarball_url: &str) -> Option { let key = format!("{}@{}", name, version); - // Hot fast-path: when the prefetch (or a sibling resolve) already - // populated the OnceMap entry, skip the per-call string allocs and - // future construction by reusing the cached `Arc`. The - // pipeline path drives `download_to_cache` for every BFS-resolved - // package, and install-loop calls usually arrive after — most hit - // a `Done` slot. + // Skip the param clones + future construction on cache hit. if let Some(cache_path) = DOWNLOAD_CACHE.get(&key) { return Some((*cache_path).clone()); } @@ -178,14 +173,8 @@ pub async fn download_to_cache(name: &str, version: &str, tarball_url: &str) -> return Some(cache_path); } - // Download (semaphore controlled). The permit gates only - // network I/O — extract runs on rayon's CPU pool and does - // not contend with download bandwidth, so we release the - // permit before the CPU-bound phase. This lets the next - // `download_to_cache` start immediately, doubling effective - // concurrency on tarball-heavy installs (download tasks no - // longer block on a peer task's ~50–200ms libdeflate + - // tar parse + parallel writes). + // The semaphore gates network I/O only; extract runs on + // rayon and is released below before the CPU-bound phase. let semaphore = DOWNLOAD_SEMAPHORE .get_or_init(|| Semaphore::new(get_manifests_concurrency_limit_sync())); let permit = semaphore.acquire().await.ok()?; diff --git a/crates/pm/src/util/extractor.rs b/crates/pm/src/util/extractor.rs index 45276f7304..16b276298c 100644 --- a/crates/pm/src/util/extractor.rs +++ b/crates/pm/src/util/extractor.rs @@ -95,22 +95,12 @@ fn extract_tarball_sync(gzip_bytes: Bytes, estimated_size: usize, dest: &Path) - }; output.truncate(actual_size); - // Parse tar entries — record offsets into `output` instead of copying - // each file's bytes. The buffer outlives the parallel write phase and - // is read-only after the parse loop, so concurrent slice reads are - // safe. let entries = parse_tar_entries(&output, dest)?; - // Collect every ancestor directory (up to `dest`) by borrowing - // straight out of `entries.path` — no per-entry PathBuf allocation. - // `entries` outlives the mkdir + parallel-write phases, so the - // `&Path` references stay valid. - // - // Lex sort + dedup is all we need: every dir here is a descendant - // of the same `dest` root, so a parent's path is a strict byte - // prefix of any descendant's path → it sorts before. The previous - // secondary `sort_by_key(len)` is redundant. - let mut dirs: Vec<&Path> = Vec::with_capacity(entries.len()); + // Lex sort suffices for parent-before-child mkdir order: every dir + // is a descendant of the same `dest` root, so a parent's path is a + // strict byte prefix of any descendant's and sorts before. + let mut dirs: Vec<&Path> = Vec::new(); for entry in &entries { let mut p = entry.path.parent(); while let Some(dir) = p { @@ -127,8 +117,6 @@ fn extract_tarball_sync(gzip_bytes: Bytes, estimated_size: usize, dest: &Path) - fs::create_dir(dir).ok(); } - // Write files in parallel using rayon. Each task slices into the - // shared `output` buffer (immutable borrow) — no per-file copy. let buf: &[u8] = &output; entries.par_iter().try_for_each(|entry| -> Result<()> { let mut file = fs::File::create(&entry.path) diff --git a/crates/pm/src/util/logger.rs b/crates/pm/src/util/logger.rs index c8570b2eca..28ba5539a2 100644 --- a/crates/pm/src/util/logger.rs +++ b/crates/pm/src/util/logger.rs @@ -161,10 +161,8 @@ pub fn log_progress(text: &str) { PROGRESS_BAR.set_message(text.to_string()); } -/// TTY-gated `PROGRESS_BAR.inc(1)`. Non-TTY callers pay no Mutex cost — -/// indicatif's `inc` always takes the internal `Mutex` -/// write-lock even with a hidden draw target, which contends across the -/// install loop's spawned tasks. +/// TTY-gated `PROGRESS_BAR.inc`. indicatif's inc takes its internal +/// state Mutex even with a hidden draw target — see [`IS_TTY`]. #[inline] pub fn progress_inc(n: u64) { if !*IS_TTY { @@ -173,7 +171,6 @@ pub fn progress_inc(n: u64) { PROGRESS_BAR.inc(n); } -/// TTY-gated `PROGRESS_BAR.set_length`. Same rationale as [`progress_inc`]. #[inline] pub fn progress_set_length(len: u64) { if !*IS_TTY { diff --git a/crates/ruborist/src/util/oncemap.rs b/crates/ruborist/src/util/oncemap.rs index 903fbd37ce..7bb1e710cc 100644 --- a/crates/ruborist/src/util/oncemap.rs +++ b/crates/ruborist/src/util/oncemap.rs @@ -118,32 +118,14 @@ where } } - /// Sync, allocation-free check for a completed entry. - /// - /// Lets hot-path callers short-circuit before paying string clones / - /// future construction for a key that's already been resolved by a - /// peer (e.g. install loop deduping against pipeline-pre-cloned - /// targets, where 95%+ of packages hit a `Done` slot). - /// - /// Returns `false` for both unknown keys and `Waiting` slots; only - /// `Done` is reported. Waiting entries fall through to the normal - /// `get_or_init` path which knows how to subscribe and wait. + /// Sync presence probe — `Done` only, single `DashMap::get`. + /// Returns `false` for unknown / `Waiting` slots. pub fn is_done(&self, key: &K) -> bool { - self.map - .get(key) - .is_some_and(|e| matches!(e.value(), Value::Done(_))) + self.get(key).is_some() } - /// Sync fetch of a completed value, single map lookup. - /// - /// Lets value-returning hot-path callers (e.g. `download_to_cache`'s - /// `Arc` slot) skip the `is_done` + `get_or_init(no-op)` - /// double-lookup dance — one `DashMap::get` and we return the - /// `Arc` if the entry is `Done`, `None` otherwise. - /// - /// Returns `None` for both unknown keys and `Waiting` slots; only - /// `Done` is reported. Use `is_done` instead when `V = ()` and you - /// only care about presence. + /// Sync fetch of a completed value, single `DashMap::get`. + /// Returns `None` for unknown / `Waiting` slots. pub fn get(&self, key: &K) -> Option> { self.map.get(key).and_then(|e| match e.value() { Value::Done(v) => Some(Arc::clone(v)), diff --git a/next.js b/next.js index 8a9dac4adf..6f6135c565 160000 --- a/next.js +++ b/next.js @@ -1 +1 @@ -Subproject commit 8a9dac4adf6fb3b690e3df0b958a30980e50f756 +Subproject commit 6f6135c5651a1ac052cd7f36d9edc199e006b4d4 From d94ae10b1e9a55972e8966b9bc375b06c67fd3e4 Mon Sep 17 00:00:00 2001 From: elrrrrrrr Date: Wed, 6 May 2026 17:59:47 +0800 Subject: [PATCH 12/16] Revert "perf(pm): release download permit before CPU-bound extract phase" This reverts commit 9df637ffaebbd8ed1355af0b588b601fe804e959. --- crates/pm/src/util/downloader.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/pm/src/util/downloader.rs b/crates/pm/src/util/downloader.rs index 494c2d1f6b..ee7bf3c838 100644 --- a/crates/pm/src/util/downloader.rs +++ b/crates/pm/src/util/downloader.rs @@ -173,11 +173,12 @@ pub async fn download_to_cache(name: &str, version: &str, tarball_url: &str) -> return Some(cache_path); } - // The semaphore gates network I/O only; extract runs on - // rayon and is released below before the CPU-bound phase. + // Download (semaphore controlled). Permit held through extract + // — A/B-revert experiment to test if early permit release is + // the source of utoo p0 σ being ~2× baseline. let semaphore = DOWNLOAD_SEMAPHORE .get_or_init(|| Semaphore::new(get_manifests_concurrency_limit_sync())); - let permit = semaphore.acquire().await.ok()?; + let _permit = semaphore.acquire().await.ok()?; let bytes = download_bytes(&tarball_url) .await .inspect_err(|e| { @@ -190,7 +191,6 @@ pub async fn download_to_cache(name: &str, version: &str, tarball_url: &str) -> ) }) .ok()?; - drop(permit); // Extract extract_and_write(bytes, &cache_path) From 8ff8fb447b099ccab2049fc09d22ed9624172b6e Mon Sep 17 00:00:00 2001 From: elrrrrrrr Date: Wed, 6 May 2026 18:03:32 +0800 Subject: [PATCH 13/16] ci: trigger bench From 7d6dd81c39fbef5f6d40e821ee287e8393e96a7a Mon Sep 17 00:00:00 2001 From: elrrrrrrr Date: Wed, 6 May 2026 19:11:29 +0800 Subject: [PATCH 14/16] experiment(pm): A/B revert install_packages eager skip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A/B test #2: revert the spawn-skip in install_packages. Hypothesis: variable spawn count between runs (depending on how far BFS pipeline got) introduces the p0 σ ≈ 2-5s variance we've been seeing. Baseline (without eager skip) spawns all 1000 tasks → uniform timing. Permit-drop revert (sample 11) didn't tighten σ — confirmed permit drop isn't the cause. Next suspect: this commit. If σ collapses to baseline- tight (~0.2s), eager skip is the structural variance source. OnceMap::is_done API stays in ruborist — only the install-loop call site is removed. --- Cargo.lock | 736 ++++++++++++++++++++++++++----- crates/pm/src/service/install.rs | 10 +- crates/pm/src/util/cloner.rs | 7 - 3 files changed, 618 insertions(+), 135 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3a136807b0..d126fe965f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1690,23 +1690,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "ctor" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83cf0d42651b16c6dfe68685716d18480d18a9c39c62d76e8cf3eb6ed5d8bcbf" -dependencies = [ - "ctor-proc-macro", - "dtor", - "link-section", -] - -[[package]] -name = "ctor-proc-macro" -version = "0.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a949c44fcacbbbb7ada007dc7acb34603dd97cd47de5d054f2b6493ecebb483" - [[package]] name = "cty" version = "0.2.2" @@ -2246,21 +2229,6 @@ dependencies = [ "dtoa", ] -[[package]] -name = "dtor" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edf234dd1594d6dd434a8fb8cada51ddbbc593e40e4a01556a0b31c62da2775b" -dependencies = [ - "dtor-proc-macro", -] - -[[package]] -name = "dtor-proc-macro" -version = "0.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2647271c92754afcb174e758003cfd1cbf1e43e5a7853d7b1813e63e19e39a73" - [[package]] name = "dunce" version = "1.0.5" @@ -4824,12 +4792,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "link-section" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b685d66585d646efe09fec763d796c291049c8b6bf84e04954bffc8748341f0d" - [[package]] name = "linked-hash-map" version = "0.5.6" @@ -5380,7 +5342,7 @@ checksum = "55740c4ae1d8696773c78fdafd5d0e5fe9bc9f1b071c7ba493ba5c413a9184f3" dependencies = [ "anyhow", "bitflags 2.9.4", - "ctor 0.2.9", + "ctor", "napi-derive", "napi-sys", "once_cell", @@ -7208,9 +7170,9 @@ dependencies = [ [[package]] name = "roaring" -version = "0.11.4" +version = "0.10.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dedc5658c6ecb3bdb5ef5f3295bb9253f42dcf3fd1402c03f6b1f7659c3c4a9" +checksum = "19e8d2cfa184d94d0726d650a9f4a1be7f9b76ac9fdb954219878dc00c1c1e7b" dependencies = [ "bytemuck", "byteorder", @@ -8115,9 +8077,9 @@ dependencies = [ [[package]] name = "styled_components" -version = "4.0.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72418ea605a423c70ffa8590196c83b04b04636fd25aaceabe0fa7f1e15f66f0" +checksum = "99aeadac58111060ad883c7e7a01917bcecc6572243c06d41315f200cbaa9240" dependencies = [ "Inflector", "once_cell", @@ -8134,9 +8096,9 @@ dependencies = [ [[package]] name = "styled_jsx" -version = "4.0.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc5352e19f02be3ba10fb9ecbcd0d72e9b2d9762965712f1cbe737d1f428ec" +checksum = "c3917b257122e7cf3f46f95557af3178edaa9a3fd89fc1469768e05f01901e98" dependencies = [ "anyhow", "lightningcss", @@ -8155,9 +8117,9 @@ dependencies = [ "swc_css_prefixer", "swc_css_visit", "swc_ecma_ast 23.0.0", - "swc_ecma_minifier", - "swc_ecma_parser 39.0.2", - "swc_ecma_transforms_base 42.0.0", + "swc_ecma_minifier 51.1.0", + "swc_ecma_parser 38.0.2", + "swc_ecma_transforms_base 41.0.1", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", "swc_plugin_macro", @@ -8170,6 +8132,57 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "swc" +version = "61.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb7d502b72d0b5e059cefe3a55825c43587a2e3c81025862694e52deecddc3de" +dependencies = [ + "anyhow", + "base64 0.22.1", + "bytes-str", + "dashmap 5.5.3", + "either", + "indexmap 2.13.0", + "jsonc-parser", + "once_cell", + "par-core", + "par-iter", + "parking_lot", + "regex", + "rustc-hash 2.1.1", + "serde", + "serde_json", + "swc_atoms", + "swc_common 21.0.1", + "swc_compiler_base 54.0.0", + "swc_config", + "swc_ecma_ast 23.0.0", + "swc_ecma_codegen 26.0.1", + "swc_ecma_ext_transforms", + "swc_ecma_loader", + "swc_ecma_minifier 51.1.0", + "swc_ecma_parser 38.0.2", + "swc_ecma_preset_env 52.0.0", + "swc_ecma_transforms 51.0.0", + "swc_ecma_transforms_base 41.0.1", + "swc_ecma_transforms_compat 47.0.0", + "swc_ecma_transforms_optimization 43.0.0", + "swc_ecma_utils 29.1.0", + "swc_ecma_visit 23.0.0", + "swc_error_reporters", + "swc_node_comments", + "swc_plugin_proxy", + "swc_plugin_runner", + "swc_sourcemap", + "swc_timer", + "swc_transform_common", + "swc_visit", + "tokio", + "tracing", + "url", +] + [[package]] name = "swc" version = "63.0.0" @@ -8193,19 +8206,19 @@ dependencies = [ "serde_json", "swc_atoms", "swc_common 21.0.1", - "swc_compiler_base", + "swc_compiler_base 55.0.0", "swc_config", "swc_ecma_ast 23.0.0", "swc_ecma_codegen 26.0.1", "swc_ecma_ext_transforms", "swc_ecma_loader", - "swc_ecma_minifier", + "swc_ecma_minifier 52.0.4", "swc_ecma_parser 39.0.2", - "swc_ecma_preset_env", - "swc_ecma_transforms", + "swc_ecma_preset_env 53.0.0", + "swc_ecma_transforms 52.0.0", "swc_ecma_transforms_base 42.0.0", - "swc_ecma_transforms_compat", - "swc_ecma_transforms_optimization", + "swc_ecma_transforms_compat 48.0.0", + "swc_ecma_transforms_optimization 44.0.0", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", "swc_error_reporters", @@ -8322,6 +8335,32 @@ dependencies = [ "url", ] +[[package]] +name = "swc_compiler_base" +version = "54.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "386c6121a98d7630ef5a07b79acee964c778568d61d3b76a188be17f19418a9c" +dependencies = [ + "anyhow", + "base64 0.22.1", + "bytes-str", + "once_cell", + "pathdiff", + "rustc-hash 2.1.1", + "serde", + "serde_json", + "swc_atoms", + "swc_common 21.0.1", + "swc_config", + "swc_ecma_ast 23.0.0", + "swc_ecma_codegen 26.0.1", + "swc_ecma_minifier 51.1.0", + "swc_ecma_parser 38.0.2", + "swc_ecma_visit 23.0.0", + "swc_sourcemap", + "swc_timer", +] + [[package]] name = "swc_compiler_base" version = "55.0.0" @@ -8341,7 +8380,7 @@ dependencies = [ "swc_config", "swc_ecma_ast 23.0.0", "swc_ecma_codegen 26.0.1", - "swc_ecma_minifier", + "swc_ecma_minifier 52.0.4", "swc_ecma_parser 39.0.2", "swc_ecma_visit 23.0.0", "swc_sourcemap", @@ -8398,6 +8437,38 @@ dependencies = [ "vergen", ] +[[package]] +name = "swc_core" +version = "63.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb9470306b0d532da617be037de878f64ec0f04cb364d920e8cee05d658d66de" +dependencies = [ + "par-core", + "swc 61.0.0", + "swc_allocator", + "swc_atoms", + "swc_common 21.0.1", + "swc_ecma_ast 23.0.0", + "swc_ecma_codegen 26.0.1", + "swc_ecma_lints", + "swc_ecma_loader", + "swc_ecma_minifier 51.1.0", + "swc_ecma_parser 38.0.2", + "swc_ecma_preset_env 52.0.0", + "swc_ecma_quote_macros", + "swc_ecma_transforms_base 41.0.1", + "swc_ecma_transforms_optimization 43.0.0", + "swc_ecma_transforms_proposal 41.0.3", + "swc_ecma_transforms_react 45.0.0", + "swc_ecma_transforms_typescript 45.0.2", + "swc_ecma_utils 29.1.0", + "swc_ecma_visit 23.0.0", + "swc_plugin_proxy", + "swc_plugin_runner", + "testing", + "vergen", +] + [[package]] name = "swc_core" version = "65.0.3" @@ -8405,28 +8476,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "898413141c6d3e1fed24ac3a4c57cc61ef98194df2a7957820d48ad158a318f6" dependencies = [ "par-core", - "swc", + "swc 63.0.0", "swc_allocator", "swc_atoms", "swc_common 21.0.1", "swc_ecma_ast 23.0.0", "swc_ecma_codegen 26.0.1", - "swc_ecma_lints", "swc_ecma_loader", - "swc_ecma_minifier", + "swc_ecma_minifier 52.0.4", "swc_ecma_parser 39.0.2", - "swc_ecma_preset_env", - "swc_ecma_quote_macros", + "swc_ecma_preset_env 53.0.0", "swc_ecma_transforms_base 42.0.0", - "swc_ecma_transforms_optimization", - "swc_ecma_transforms_proposal", - "swc_ecma_transforms_react", - "swc_ecma_transforms_typescript", + "swc_ecma_transforms_optimization 44.0.0", + "swc_ecma_transforms_react 46.0.1", + "swc_ecma_transforms_typescript 46.0.1", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", "swc_plugin_proxy", "swc_plugin_runner", - "testing", "vergen", ] @@ -8656,6 +8723,24 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "swc_ecma_compat_bugfixes" +version = "46.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22d4da77f7014b5efd416bb5208ab6e3d005ad5d532df8ced2904e50ca233d44" +dependencies = [ + "rustc-hash 2.1.1", + "swc_atoms", + "swc_common 21.0.1", + "swc_ecma_ast 23.0.0", + "swc_ecma_compat_es2015 45.0.0", + "swc_ecma_transforms_base 41.0.1", + "swc_ecma_utils 29.1.0", + "swc_ecma_visit 23.0.0", + "swc_trace_macro", + "tracing", +] + [[package]] name = "swc_ecma_compat_bugfixes" version = "47.0.0" @@ -8666,7 +8751,7 @@ dependencies = [ "swc_atoms", "swc_common 21.0.1", "swc_ecma_ast 23.0.0", - "swc_ecma_compat_es2015", + "swc_ecma_compat_es2015 46.0.0", "swc_ecma_transforms_base 42.0.0", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", @@ -8674,6 +8759,18 @@ dependencies = [ "tracing", ] +[[package]] +name = "swc_ecma_compat_common" +version = "37.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d72d7d499e4bd4059ccfe432c1a52111a28fdd2b49b3882f18108fddfa3f6b4f" +dependencies = [ + "swc_common 21.0.1", + "swc_ecma_ast 23.0.0", + "swc_ecma_transformer 13.0.0", + "swc_ecma_utils 29.1.0", +] + [[package]] name = "swc_ecma_compat_common" version = "38.0.0" @@ -8682,10 +8779,38 @@ checksum = "04b936fe418e2bd707298357f560d269c1bdedc86a2325f7163307fe140806bd" dependencies = [ "swc_common 21.0.1", "swc_ecma_ast 23.0.0", - "swc_ecma_transformer", + "swc_ecma_transformer 14.0.0", "swc_ecma_utils 29.1.0", ] +[[package]] +name = "swc_ecma_compat_es2015" +version = "45.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5095800ee11e7c37df38a2e0fae2caa9d98b7801121d5f5ce70710ab65e21ec7" +dependencies = [ + "arrayvec", + "indexmap 2.13.0", + "is-macro", + "rustc-hash 2.1.1", + "serde", + "serde_derive", + "smallvec", + "swc_atoms", + "swc_common 21.0.1", + "swc_config", + "swc_ecma_ast 23.0.0", + "swc_ecma_compat_common 37.0.0", + "swc_ecma_transformer 13.0.0", + "swc_ecma_transforms_base 41.0.1", + "swc_ecma_transforms_classes 41.0.1", + "swc_ecma_transforms_macros", + "swc_ecma_utils 29.1.0", + "swc_ecma_visit 23.0.0", + "swc_trace_macro", + "tracing", +] + [[package]] name = "swc_ecma_compat_es2015" version = "46.0.0" @@ -8703,10 +8828,10 @@ dependencies = [ "swc_common 21.0.1", "swc_config", "swc_ecma_ast 23.0.0", - "swc_ecma_compat_common", - "swc_ecma_transformer", + "swc_ecma_compat_common 38.0.0", + "swc_ecma_transformer 14.0.0", "swc_ecma_transforms_base 42.0.0", - "swc_ecma_transforms_classes", + "swc_ecma_transforms_classes 42.0.0", "swc_ecma_transforms_macros", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", @@ -8714,6 +8839,19 @@ dependencies = [ "tracing", ] +[[package]] +name = "swc_ecma_compat_es2016" +version = "42.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1358f912b0b5bdb6509f64dada8dc9ac8dc9233175b1d033c571cd34ad0bbec" +dependencies = [ + "swc_ecma_ast 23.0.0", + "swc_ecma_transformer 13.0.0", + "swc_ecma_transforms_base 41.0.1", + "swc_ecma_utils 29.1.0", + "tracing", +] + [[package]] name = "swc_ecma_compat_es2016" version = "43.0.0" @@ -8721,12 +8859,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4402a84df86ebd3723decdd041743ba8e48c7903bfe7f5c7c712bac46642ac90" dependencies = [ "swc_ecma_ast 23.0.0", - "swc_ecma_transformer", + "swc_ecma_transformer 14.0.0", "swc_ecma_transforms_base 42.0.0", "swc_ecma_utils 29.1.0", "tracing", ] +[[package]] +name = "swc_ecma_compat_es2017" +version = "42.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65a437c6a98cbfed7b355e2da721a52b1731537b6debf81cadccc9f196bbdbba" +dependencies = [ + "serde", + "swc_common 21.0.1", + "swc_ecma_ast 23.0.0", + "swc_ecma_transformer 13.0.0", + "swc_ecma_transforms_base 41.0.1", + "swc_ecma_utils 29.1.0", + "tracing", +] + [[package]] name = "swc_ecma_compat_es2017" version = "43.0.0" @@ -8736,12 +8889,26 @@ dependencies = [ "serde", "swc_common 21.0.1", "swc_ecma_ast 23.0.0", - "swc_ecma_transformer", + "swc_ecma_transformer 14.0.0", "swc_ecma_transforms_base 42.0.0", "swc_ecma_utils 29.1.0", "tracing", ] +[[package]] +name = "swc_ecma_compat_es2018" +version = "43.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27ffcf499581d598250e4d93d45ef64fe81b16f83c3bcb8c21d27af2004e6f54" +dependencies = [ + "serde", + "swc_ecma_ast 23.0.0", + "swc_ecma_transformer 13.0.0", + "swc_ecma_transforms_base 41.0.1", + "swc_ecma_utils 29.1.0", + "tracing", +] + [[package]] name = "swc_ecma_compat_es2018" version = "44.0.0" @@ -8750,12 +8917,26 @@ checksum = "757acfefd8ececa3fd3491e7dcbf6da1b7b5fba602b70b8f2b36af30fac35eea" dependencies = [ "serde", "swc_ecma_ast 23.0.0", - "swc_ecma_transformer", + "swc_ecma_transformer 14.0.0", "swc_ecma_transforms_base 42.0.0", "swc_ecma_utils 29.1.0", "tracing", ] +[[package]] +name = "swc_ecma_compat_es2019" +version = "42.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5125766d7ca9c4789eefdb68fd9d1bc9eba1119df21ad3d1fd7b0ac2808893d0" +dependencies = [ + "swc_common 21.0.1", + "swc_ecma_ast 23.0.0", + "swc_ecma_transformer 13.0.0", + "swc_ecma_transforms_base 41.0.1", + "swc_ecma_utils 29.1.0", + "tracing", +] + [[package]] name = "swc_ecma_compat_es2019" version = "43.0.0" @@ -8764,12 +8945,29 @@ checksum = "3a0f39d1ebadade7d0a0a137cedec958cfd38fe99c5c69c762d879650b5e9848" dependencies = [ "swc_common 21.0.1", "swc_ecma_ast 23.0.0", - "swc_ecma_transformer", + "swc_ecma_transformer 14.0.0", "swc_ecma_transforms_base 42.0.0", "swc_ecma_utils 29.1.0", "tracing", ] +[[package]] +name = "swc_ecma_compat_es2020" +version = "44.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eba7cf139b36cdf75daf9f1fc9096f566c8034d774ce040f09f0fccd4ffe02e" +dependencies = [ + "serde", + "swc_common 21.0.1", + "swc_ecma_ast 23.0.0", + "swc_ecma_compat_es2022 44.0.0", + "swc_ecma_transformer 13.0.0", + "swc_ecma_transforms_base 41.0.1", + "swc_ecma_utils 29.1.0", + "swc_ecma_visit 23.0.0", + "tracing", +] + [[package]] name = "swc_ecma_compat_es2020" version = "45.0.0" @@ -8779,14 +8977,27 @@ dependencies = [ "serde", "swc_common 21.0.1", "swc_ecma_ast 23.0.0", - "swc_ecma_compat_es2022", - "swc_ecma_transformer", + "swc_ecma_compat_es2022 45.0.0", + "swc_ecma_transformer 14.0.0", "swc_ecma_transforms_base 42.0.0", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", "tracing", ] +[[package]] +name = "swc_ecma_compat_es2021" +version = "42.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f64ee2ff23cdc2bb9749f3fb730bd4a95cc26cdea84b384b85574a1ab43f78af" +dependencies = [ + "swc_ecma_ast 23.0.0", + "swc_ecma_transformer 13.0.0", + "swc_ecma_transforms_base 41.0.1", + "swc_ecma_utils 29.1.0", + "tracing", +] + [[package]] name = "swc_ecma_compat_es2021" version = "43.0.0" @@ -8794,12 +9005,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfef1313a8410a2229aca737b65bb82c4aa45bdd6cedc0a0083688da0b960b20" dependencies = [ "swc_ecma_ast 23.0.0", - "swc_ecma_transformer", + "swc_ecma_transformer 14.0.0", "swc_ecma_transforms_base 42.0.0", "swc_ecma_utils 29.1.0", "tracing", ] +[[package]] +name = "swc_ecma_compat_es2022" +version = "44.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9e0499dc93f8eb04c88d5cf6aefc4ce34fdcca9dd69155d6882eb011339c9dd" +dependencies = [ + "rustc-hash 2.1.1", + "swc_atoms", + "swc_common 21.0.1", + "swc_ecma_ast 23.0.0", + "swc_ecma_transformer 13.0.0", + "swc_ecma_transforms_base 41.0.1", + "swc_ecma_transforms_classes 41.0.1", + "swc_ecma_transforms_macros", + "swc_ecma_utils 29.1.0", + "swc_ecma_visit 23.0.0", + "swc_trace_macro", + "tracing", +] + [[package]] name = "swc_ecma_compat_es2022" version = "45.0.0" @@ -8810,9 +9041,9 @@ dependencies = [ "swc_atoms", "swc_common 21.0.1", "swc_ecma_ast 23.0.0", - "swc_ecma_transformer", + "swc_ecma_transformer 14.0.0", "swc_ecma_transforms_base 42.0.0", - "swc_ecma_transforms_classes", + "swc_ecma_transforms_classes 42.0.0", "swc_ecma_transforms_macros", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", @@ -8899,6 +9130,42 @@ dependencies = [ "tracing", ] +[[package]] +name = "swc_ecma_minifier" +version = "51.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c25a685c2efe2f88ba359dde0a17382b28a206ea21b23bda612f97b2c423b2f2" +dependencies = [ + "arrayvec", + "bitflags 2.9.4", + "indexmap 2.13.0", + "num-bigint", + "num_cpus", + "once_cell", + "par-core", + "par-iter", + "parking_lot", + "phf", + "radix_fmt", + "rustc-hash 2.1.1", + "ryu-js", + "serde", + "serde_json", + "swc_atoms", + "swc_common 21.0.1", + "swc_config", + "swc_ecma_ast 23.0.0", + "swc_ecma_codegen 26.0.1", + "swc_ecma_hooks", + "swc_ecma_parser 38.0.2", + "swc_ecma_transforms_base 41.0.1", + "swc_ecma_transforms_optimization 43.0.0", + "swc_ecma_utils 29.1.0", + "swc_ecma_visit 23.0.0", + "swc_timer", + "tracing", +] + [[package]] name = "swc_ecma_minifier" version = "52.0.4" @@ -8928,7 +9195,7 @@ dependencies = [ "swc_ecma_hooks", "swc_ecma_parser 39.0.2", "swc_ecma_transforms_base 42.0.0", - "swc_ecma_transforms_optimization", + "swc_ecma_transforms_optimization 44.0.0", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", "swc_timer", @@ -8955,6 +9222,27 @@ dependencies = [ "tracing", ] +[[package]] +name = "swc_ecma_parser" +version = "38.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7c251d44e048647b5335861d1585b3e95fa8bc74f6e7a40570b0ea95d27ba66" +dependencies = [ + "bitflags 2.9.4", + "either", + "num-bigint", + "phf", + "rustc-hash 2.1.1", + "seq-macro", + "serde", + "smartstring", + "stacker", + "swc_atoms", + "swc_common 21.0.1", + "swc_ecma_ast 23.0.0", + "tracing", +] + [[package]] name = "swc_ecma_parser" version = "39.0.2" @@ -8969,13 +9257,37 @@ dependencies = [ "seq-macro", "serde", "smartstring", - "stacker", "swc_atoms", "swc_common 21.0.1", "swc_ecma_ast 23.0.0", "tracing", ] +[[package]] +name = "swc_ecma_preset_env" +version = "52.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5132d5890cddc4e47feb29c3388b4b0ca2251173c2c859c4b48b896794767c54" +dependencies = [ + "anyhow", + "foldhash 0.1.5", + "indexmap 2.13.0", + "once_cell", + "precomputed-map", + "preset_env_base", + "rustc-hash 2.1.1", + "serde", + "serde_json", + "string_enum", + "swc_atoms", + "swc_common 21.0.1", + "swc_ecma_ast 23.0.0", + "swc_ecma_transformer 13.0.0", + "swc_ecma_transforms 51.0.0", + "swc_ecma_utils 29.1.0", + "swc_ecma_visit 23.0.0", +] + [[package]] name = "swc_ecma_preset_env" version = "53.0.0" @@ -8995,17 +9307,17 @@ dependencies = [ "swc_atoms", "swc_common 21.0.1", "swc_ecma_ast 23.0.0", - "swc_ecma_transformer", - "swc_ecma_transforms", + "swc_ecma_transformer 14.0.0", + "swc_ecma_transforms 52.0.0", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", ] [[package]] name = "swc_ecma_quote_macros" -version = "39.0.0" +version = "38.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54e4d28106d86d9c45d187687688d03bab7064bd8480d8bc783df9ff2a5d5a9a" +checksum = "16896c184ff6915c85ee4bffd08db32e010b1c1a9628e6c4ee49a233653c20a7" dependencies = [ "anyhow", "proc-macro2", @@ -9014,7 +9326,7 @@ dependencies = [ "swc_atoms", "swc_common 21.0.1", "swc_ecma_ast 23.0.0", - "swc_ecma_parser 39.0.2", + "swc_ecma_parser 38.0.2", "swc_macros_common", "syn 2.0.106", ] @@ -9067,6 +9379,25 @@ dependencies = [ "swc_visit", ] +[[package]] +name = "swc_ecma_transformer" +version = "13.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c334a42d7d8252e5a80dbae85a1230144d29f7ed4aa7feada2a47167f9282e" +dependencies = [ + "rustc-hash 2.1.1", + "swc_atoms", + "swc_common 21.0.1", + "swc_ecma_ast 23.0.0", + "swc_ecma_compat_regexp", + "swc_ecma_hooks", + "swc_ecma_regexp", + "swc_ecma_transforms_base 41.0.1", + "swc_ecma_utils 29.1.0", + "swc_ecma_visit 23.0.0", + "tracing", +] + [[package]] name = "swc_ecma_transformer" version = "14.0.0" @@ -9086,6 +9417,24 @@ dependencies = [ "tracing", ] +[[package]] +name = "swc_ecma_transforms" +version = "51.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94503bbcd555d82cb33ff0e591e935bb925b79b254e94e706521f15d762b473" +dependencies = [ + "par-core", + "swc_common 21.0.1", + "swc_ecma_ast 23.0.0", + "swc_ecma_transforms_base 41.0.1", + "swc_ecma_transforms_compat 47.0.0", + "swc_ecma_transforms_optimization 43.0.0", + "swc_ecma_transforms_proposal 41.0.3", + "swc_ecma_transforms_react 45.0.0", + "swc_ecma_transforms_typescript 45.0.2", + "swc_ecma_utils 29.1.0", +] + [[package]] name = "swc_ecma_transforms" version = "52.0.0" @@ -9096,11 +9445,11 @@ dependencies = [ "swc_common 21.0.1", "swc_ecma_ast 23.0.0", "swc_ecma_transforms_base 42.0.0", - "swc_ecma_transforms_compat", - "swc_ecma_transforms_optimization", - "swc_ecma_transforms_proposal", - "swc_ecma_transforms_react", - "swc_ecma_transforms_typescript", + "swc_ecma_transforms_compat 48.0.0", + "swc_ecma_transforms_optimization 44.0.0", + "swc_ecma_transforms_proposal 42.0.0", + "swc_ecma_transforms_react 46.0.1", + "swc_ecma_transforms_typescript 46.0.1", "swc_ecma_utils 29.1.0", ] @@ -9126,6 +9475,28 @@ dependencies = [ "tracing", ] +[[package]] +name = "swc_ecma_transforms_base" +version = "41.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6be824dc326da1f7673d1e241790626e5f39f09e1d896175134143408eeaa081" +dependencies = [ + "better_scoped_tls", + "indexmap 2.13.0", + "once_cell", + "par-core", + "phf", + "rustc-hash 2.1.1", + "serde", + "swc_atoms", + "swc_common 21.0.1", + "swc_ecma_ast 23.0.0", + "swc_ecma_parser 38.0.2", + "swc_ecma_utils 29.1.0", + "swc_ecma_visit 23.0.0", + "tracing", +] + [[package]] name = "swc_ecma_transforms_base" version = "42.0.0" @@ -9148,6 +9519,19 @@ dependencies = [ "tracing", ] +[[package]] +name = "swc_ecma_transforms_classes" +version = "41.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ffae23e996fa1a7b20b77ff599aa0e4997a6eb21369e2e5e906c91b89fdffaa" +dependencies = [ + "swc_common 21.0.1", + "swc_ecma_ast 23.0.0", + "swc_ecma_transforms_base 41.0.1", + "swc_ecma_utils 29.1.0", + "swc_ecma_visit 23.0.0", +] + [[package]] name = "swc_ecma_transforms_classes" version = "42.0.0" @@ -9161,6 +9545,34 @@ dependencies = [ "swc_ecma_visit 23.0.0", ] +[[package]] +name = "swc_ecma_transforms_compat" +version = "47.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd54b7d82f0037f03367b4c9052a4ba2913e044df009fbeac388b2142c3ddd8a" +dependencies = [ + "indexmap 2.13.0", + "par-core", + "serde", + "swc_atoms", + "swc_common 21.0.1", + "swc_ecma_ast 23.0.0", + "swc_ecma_compat_bugfixes 46.0.0", + "swc_ecma_compat_common 37.0.0", + "swc_ecma_compat_es2015 45.0.0", + "swc_ecma_compat_es2016 42.0.0", + "swc_ecma_compat_es2017 42.0.0", + "swc_ecma_compat_es2018 43.0.0", + "swc_ecma_compat_es2019 42.0.0", + "swc_ecma_compat_es2020 44.0.0", + "swc_ecma_compat_es2021 42.0.0", + "swc_ecma_compat_es2022 44.0.0", + "swc_ecma_transforms_base 41.0.1", + "swc_ecma_utils 29.1.0", + "swc_ecma_visit 23.0.0", + "tracing", +] + [[package]] name = "swc_ecma_transforms_compat" version = "48.0.0" @@ -9173,16 +9585,16 @@ dependencies = [ "swc_atoms", "swc_common 21.0.1", "swc_ecma_ast 23.0.0", - "swc_ecma_compat_bugfixes", - "swc_ecma_compat_common", - "swc_ecma_compat_es2015", - "swc_ecma_compat_es2016", - "swc_ecma_compat_es2017", - "swc_ecma_compat_es2018", - "swc_ecma_compat_es2019", - "swc_ecma_compat_es2020", - "swc_ecma_compat_es2021", - "swc_ecma_compat_es2022", + "swc_ecma_compat_bugfixes 47.0.0", + "swc_ecma_compat_common 38.0.0", + "swc_ecma_compat_es2015 46.0.0", + "swc_ecma_compat_es2016 43.0.0", + "swc_ecma_compat_es2017 43.0.0", + "swc_ecma_compat_es2018 44.0.0", + "swc_ecma_compat_es2019 43.0.0", + "swc_ecma_compat_es2020 45.0.0", + "swc_ecma_compat_es2021 43.0.0", + "swc_ecma_compat_es2022 45.0.0", "swc_ecma_transforms_base 42.0.0", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", @@ -9201,6 +9613,30 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "swc_ecma_transforms_optimization" +version = "43.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae12179c92f0690850bae8932dfac2b7f191b8bfc6bac80dd81abfe6b0c014aa" +dependencies = [ + "bytes-str", + "dashmap 5.5.3", + "indexmap 2.13.0", + "once_cell", + "par-core", + "petgraph 0.7.1", + "rustc-hash 2.1.1", + "serde_json", + "swc_atoms", + "swc_common 21.0.1", + "swc_ecma_ast 23.0.0", + "swc_ecma_parser 38.0.2", + "swc_ecma_transforms_base 41.0.1", + "swc_ecma_utils 29.1.0", + "swc_ecma_visit 23.0.0", + "tracing", +] + [[package]] name = "swc_ecma_transforms_optimization" version = "44.0.0" @@ -9225,6 +9661,24 @@ dependencies = [ "tracing", ] +[[package]] +name = "swc_ecma_transforms_proposal" +version = "41.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02c49fd90ad7ef87cfacb9e15eb939bfecac83fe6638fdd4f94a31eff56b8276" +dependencies = [ + "either", + "rustc-hash 2.1.1", + "serde", + "swc_atoms", + "swc_common 21.0.1", + "swc_ecma_ast 23.0.0", + "swc_ecma_transforms_base 41.0.1", + "swc_ecma_transforms_classes 41.0.1", + "swc_ecma_utils 29.1.0", + "swc_ecma_visit 23.0.0", +] + [[package]] name = "swc_ecma_transforms_proposal" version = "42.0.0" @@ -9238,7 +9692,32 @@ dependencies = [ "swc_common 21.0.1", "swc_ecma_ast 23.0.0", "swc_ecma_transforms_base 42.0.0", - "swc_ecma_transforms_classes", + "swc_ecma_transforms_classes 42.0.0", + "swc_ecma_utils 29.1.0", + "swc_ecma_visit 23.0.0", +] + +[[package]] +name = "swc_ecma_transforms_react" +version = "45.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b41b35e76a78a01650dcfb92889d37fdebbc3b86932a052259c2a99e7955e699" +dependencies = [ + "base64 0.22.1", + "bytes-str", + "indexmap 2.13.0", + "once_cell", + "rustc-hash 2.1.1", + "serde", + "sha1", + "string_enum", + "swc_atoms", + "swc_common 21.0.1", + "swc_config", + "swc_ecma_ast 23.0.0", + "swc_ecma_hooks", + "swc_ecma_parser 38.0.2", + "swc_ecma_transforms_base 41.0.1", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", ] @@ -9268,6 +9747,24 @@ dependencies = [ "swc_ecma_visit 23.0.0", ] +[[package]] +name = "swc_ecma_transforms_typescript" +version = "45.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d25026f22efe873b50c97b3aaca6bfd178f954031effd14394e7b3add1e95fb" +dependencies = [ + "bytes-str", + "rustc-hash 2.1.1", + "serde", + "swc_atoms", + "swc_common 21.0.1", + "swc_ecma_ast 23.0.0", + "swc_ecma_transforms_base 41.0.1", + "swc_ecma_transforms_react 45.0.0", + "swc_ecma_utils 29.1.0", + "swc_ecma_visit 23.0.0", +] + [[package]] name = "swc_ecma_transforms_typescript" version = "46.0.1" @@ -9281,7 +9778,7 @@ dependencies = [ "swc_common 21.0.1", "swc_ecma_ast 23.0.0", "swc_ecma_transforms_base 42.0.0", - "swc_ecma_transforms_react", + "swc_ecma_transforms_react 46.0.1", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", ] @@ -9357,9 +9854,9 @@ dependencies = [ [[package]] name = "swc_emotion" -version = "4.0.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7077db4cd3dc9908a860c2e55b40ae6de8d6ce41d919867f2e58eb81b4019718" +checksum = "11d8058e754b05eb672671b71974c4f79673b32bc2a2763706ba6970f8d2c86f" dependencies = [ "base64 0.22.1", "byteorder", @@ -9373,7 +9870,7 @@ dependencies = [ "swc_common 21.0.1", "swc_ecma_ast 23.0.0", "swc_ecma_codegen 26.0.1", - "swc_ecma_transforms", + "swc_ecma_transforms 51.0.0", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", "swc_sourcemap", @@ -9506,9 +10003,9 @@ dependencies = [ [[package]] name = "swc_relay" -version = "4.0.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b592abba81c24baad593d6130a162beaa50699b5c2ba791a5b0db7be2dff1db4" +checksum = "d1a0e98d0497d914f2a0736be9be050af6c3c0fbb2a9d911dae40379fffcc7c8" dependencies = [ "once_cell", "regex", @@ -10465,7 +10962,6 @@ dependencies = [ "auto-hash-map", "bincode 2.0.1", "concurrent-queue", - "ctor 0.10.1", "dashmap 6.1.0", "either", "erased-serde", @@ -10638,10 +11134,8 @@ dependencies = [ name = "turbo-tasks-malloc" version = "0.1.0" dependencies = [ - "libc", "libmimalloc-sys", "mimalloc", - "windows-sys 0.60.2", ] [[package]] @@ -10741,6 +11235,7 @@ dependencies = [ "either", "indexmap 2.13.0", "num-bigint", + "once_cell", "patricia_tree", "petgraph 0.8.3", "ref-cast", @@ -10750,7 +11245,7 @@ dependencies = [ "serde", "serde_json", "smallvec", - "swc_core 65.0.3", + "swc_core 63.1.3", "swc_sourcemap", "tracing", "turbo-bincode", @@ -10782,7 +11277,7 @@ dependencies = [ "rustc-hash 2.1.1", "serde", "smallvec", - "swc_core 65.0.3", + "swc_core 63.1.3", "tokio", "tracing", "turbo-bincode", @@ -10849,6 +11344,7 @@ dependencies = [ "itertools 0.10.5", "num-bigint", "num-traits", + "once_cell", "parking_lot", "petgraph 0.8.3", "phf", @@ -10858,7 +11354,7 @@ dependencies = [ "serde_json", "smallvec", "strsim 0.11.1", - "swc_core 65.0.3", + "swc_core 63.1.3", "swc_sourcemap", "tokio", "tracing", @@ -10873,7 +11369,6 @@ dependencies = [ "turbopack-resolve", "turbopack-swc-utils", "url", - "urlencoding", ] [[package]] @@ -10901,7 +11396,7 @@ dependencies = [ "serde_json", "styled_components", "styled_jsx", - "swc_core 65.0.3", + "swc_core 63.1.3", "swc_emotion", "swc_plugin_backend_wasmtime", "swc_relay", @@ -10951,8 +11446,9 @@ dependencies = [ "bincode 2.0.1", "image", "mime", - "phf", + "once_cell", "regex", + "rustc-hash 2.1.1", "serde", "turbo-bincode", "turbo-rcstr", @@ -10996,6 +11492,7 @@ dependencies = [ "js-sys", "napi", "napi-derive", + "once_cell", "owo-colors", "parking_lot", "regex", @@ -11081,7 +11578,7 @@ version = "0.1.0" dependencies = [ "anyhow", "parking_lot", - "swc_core 65.0.3", + "swc_core 63.1.3", "turbo-rcstr", "turbo-tasks", "turbopack-core", @@ -11093,6 +11590,7 @@ version = "0.1.0" dependencies = [ "anyhow", "bincode 2.0.1", + "once_cell", "regex", "rustc-hash 2.1.1", "serde", @@ -11121,7 +11619,6 @@ dependencies = [ "rustc-hash 2.1.1", "serde", "serde_json", - "smallvec", "tungstenite 0.21.0", "turbo-rcstr", "turbo-tasks-malloc", @@ -11136,6 +11633,7 @@ dependencies = [ "anyhow", "crossbeam-channel", "crossbeam-utils", + "once_cell", "parking_lot", "postcard", "rustc-hash 2.1.1", diff --git a/crates/pm/src/service/install.rs b/crates/pm/src/service/install.rs index fc382aaa4b..322c1d2d1d 100644 --- a/crates/pm/src/service/install.rs +++ b/crates/pm/src/service/install.rs @@ -17,7 +17,7 @@ use crate::helper::workspace::init_project_root; use crate::model::package::PackageInfo; use crate::service::rebuild::RebuildService; use crate::util::cli_enum::{OmitType, PackageAction, SaveType}; -use crate::util::cloner::{clone_count, is_target_cloned}; +use crate::util::cloner::clone_count; use crate::util::downloader::download_stats; use crate::util::json::load_package_lock_json_from_path; use crate::util::linker::link; @@ -146,14 +146,6 @@ pub async fn install_packages( let cwd_clone = cwd.to_path_buf(); let target_path = cwd_clone.join(&path); - // Eager skip: if the BFS pipeline (or a sibling depth) - // already cloned this target, skip the spawn + future - // construction altogether. - if is_target_cloned(&target_path) { - progress_inc(1); - continue; - } - // Check if this is an optional dependency let is_optional = package.optional == Some(true) || package.dev_optional == Some(true); diff --git a/crates/pm/src/util/cloner.rs b/crates/pm/src/util/cloner.rs index 58bb218d71..e15c69b95d 100644 --- a/crates/pm/src/util/cloner.rs +++ b/crates/pm/src/util/cloner.rs @@ -44,13 +44,6 @@ fn cache_key(target_path: &Path) -> PathBuf { target_path.to_path_buf() } -/// Check whether a target path has already been cloned this run. -/// Used by the install loop to skip `tokio::spawn` for packages the -/// pipeline already finished. -pub fn is_target_cloned(target_path: &Path) -> bool { - CLONE_CACHE.is_done(&cache_key(target_path)) -} - /// Wait for a pending clone at the given target path to complete (if any). /// /// Used by the pipeline clone worker to ensure parent packages are From 5e1c42408a028d81058a66abcb7291f5a515e5ce Mon Sep 17 00:00:00 2001 From: elrrrrrrr Date: Wed, 6 May 2026 19:52:32 +0800 Subject: [PATCH 15/16] experiment(pm): A/B revert install hot-path triplet (TTY-gate + streaming + zero-copy) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A/B test #3: bundle-revert b92fc85a's three changes (TTY-gate progress helpers, FuturesUnordered layer streaming, zero-copy tar entries). Tests if the p0 σ ~2× baseline is from this triplet. Permit drop revert (sample 11) and eager skip revert (sample 12) each failed to tighten σ. Per user direction, lump remaining suspects into one revert rather than tease them apart commit by commit. If σ collapses to baseline-tight, the source is somewhere in this triplet — narrow further if needed. If σ stays wide, the PR's σ cost is structural to OnceMap fast-paths or fundamental and not isolable to a single commit. Reverts only the install.rs / extractor.rs / logger.rs portions; keeps the rest of the PR (find_real_src file_type, OnceMap is_done/get, binary mirror gate, dir collection refactor, downloader fast-path) intact. --- crates/pm/src/service/install.rs | 31 +++---- crates/pm/src/util/extractor.rs | 140 ++++++++++++------------------- crates/pm/src/util/logger.rs | 18 ---- 3 files changed, 67 insertions(+), 122 deletions(-) diff --git a/crates/pm/src/service/install.rs b/crates/pm/src/service/install.rs index 322c1d2d1d..0390a17af1 100644 --- a/crates/pm/src/service/install.rs +++ b/crates/pm/src/service/install.rs @@ -1,7 +1,6 @@ use crate::util::cli_enum::ScriptPolicy; use anyhow::Context; use anyhow::Result; -use futures::stream::{FuturesUnordered, StreamExt}; use std::collections::{HashMap, HashSet}; use std::path::Path; use std::time::Instant; @@ -22,8 +21,7 @@ use crate::util::downloader::download_stats; use crate::util::json::load_package_lock_json_from_path; use crate::util::linker::link; use crate::util::logger::{ - finish_progress_bar, log_progress, print_install_counts, progress_inc, progress_set_length, - start_progress_bar, + PROGRESS_BAR, finish_progress_bar, log_progress, print_install_counts, start_progress_bar, }; use utoo_ruborist::compat::{is_cpu_compatible, is_os_compatible}; @@ -85,16 +83,13 @@ pub async fn install_packages( depths.sort_unstable(); for depth in depths.iter() { - // Drain in completion order so a slow tarball doesn't pin its - // siblings, and surface the first error early. - let mut clone_tasks: FuturesUnordered>> = - FuturesUnordered::new(); + let mut clone_tasks: Vec>> = Vec::new(); if let Some(packages) = groups.get(depth) { for (path, package) in packages.iter() { // Skip packages based on omit config if should_omit_package(package, omit) { - progress_inc(1); + PROGRESS_BAR.inc(1); continue; } let path = path.clone(); @@ -113,13 +108,13 @@ pub async fn install_packages( if package.link.is_some() { let link_name = extract_package_name(&path); if link_name.is_empty() { - progress_inc(1); + PROGRESS_BAR.inc(1); continue; } link(Path::new(&resolved), Path::new(&path)) .await .with_context(|| format!("Link failed: {resolved} -> {path}"))?; - progress_inc(1); + PROGRESS_BAR.inc(1); continue; } @@ -127,14 +122,14 @@ pub async fn install_packages( if let Some(ref cpu) = package.cpu && !is_cpu_compatible(cpu) { - progress_inc(1); + PROGRESS_BAR.inc(1); continue; } if let Some(ref os) = package.os && !is_os_compatible(os) { - progress_inc(1); + PROGRESS_BAR.inc(1); continue; } @@ -158,24 +153,24 @@ pub async fn install_packages( tracing::warn!( "Optional dependency {name} failed (ignored): {e:#}" ); - progress_inc(1); + PROGRESS_BAR.inc(1); return Ok(()); } return Err(e); } - progress_inc(1); + PROGRESS_BAR.inc(1); log_progress(&format!("{name} resolved")); update_package_binary(&target_path, &name).await }); clone_tasks.push(task); } else { - progress_inc(1); + PROGRESS_BAR.inc(1); } } } - while let Some(joined) = clone_tasks.next().await { - joined??; + for task in clone_tasks { + task.await??; } } @@ -265,7 +260,7 @@ impl InstallService { if !package_lock.packages.is_empty() { start_progress_bar(); - progress_set_length(package_lock.packages.len() as u64); + PROGRESS_BAR.set_length(package_lock.packages.len() as u64); } let link_start = Instant::now(); diff --git a/crates/pm/src/util/extractor.rs b/crates/pm/src/util/extractor.rs index 16b276298c..29b71149b0 100644 --- a/crates/pm/src/util/extractor.rs +++ b/crates/pm/src/util/extractor.rs @@ -41,15 +41,9 @@ fn estimate_uncompressed_size(gzip_data: &[u8]) -> usize { } } -/// Tarball entry recorded during the parse pass, deferred until parallel -/// write. `data_offset`/`data_len` index into the decompressed buffer -/// (lifetime-erased from the buffer for reuse during `par_iter`); avoids -/// the per-file `Vec` allocation+copy that `read_to_end` previously -/// did for every file in the archive. struct ExtractedEntry { path: PathBuf, - data_offset: usize, - data_len: usize, + content: Vec, mode: u32, } @@ -74,8 +68,9 @@ async fn extract_tarball(gzip_bytes: Bytes, dest: &Path) -> Result<()> { /// Synchronous extraction: decompress + parse + parallel write, all on rayon. fn extract_tarball_sync(gzip_bytes: Bytes, estimated_size: usize, dest: &Path) -> Result<()> { use rayon::prelude::*; + use std::collections::HashSet; use std::fs; - use std::io::Write; + use std::io::{Cursor, Read, Write}; // Decompress gzip using libdeflate let mut output = vec![0u8; estimated_size]; @@ -95,34 +90,73 @@ fn extract_tarball_sync(gzip_bytes: Bytes, estimated_size: usize, dest: &Path) - }; output.truncate(actual_size); - let entries = parse_tar_entries(&output, dest)?; + // Parse tar entries + let cursor = Cursor::new(&output[..]); + let mut archive = tar::Archive::new(cursor); + let mut entries = Vec::new(); + + for entry_result in archive.entries()? { + let mut entry = entry_result.with_context(|| "Failed to read tar entry")?; + let path = entry + .path() + .with_context(|| "Failed to get entry path")? + .into_owned(); + + // Guard against path traversal (Tar Slip): reject absolute paths + // and entries containing ".." components. + if path.is_absolute() + || path + .components() + .any(|c| matches!(c, std::path::Component::ParentDir)) + { + tracing::warn!("Skipping tar entry with unsafe path: {}", path.display()); + continue; + } + + let full_path = dest.join(&path); - // Lex sort suffices for parent-before-child mkdir order: every dir - // is a descendant of the same `dest` root, so a parent's path is a - // strict byte prefix of any descendant's and sorts before. - let mut dirs: Vec<&Path> = Vec::new(); + if !entry.header().entry_type().is_dir() { + let mut content = Vec::new(); + entry + .read_to_end(&mut content) + .with_context(|| format!("Failed to read tar entry: {}", path.display()))?; + + // Normalize to npm/pnpm convention: 0o755 if any exec bit is set, + // else 0o644. Preserving raw tar modes (e.g. 0o640 in google-protobuf) + // breaks world-readability in containers and multi-user setups. + let raw_mode = entry.header().mode().unwrap_or(0o644); + let mode = if raw_mode & 0o111 != 0 { 0o755 } else { 0o644 }; + entries.push(ExtractedEntry { + path: full_path, + content, + mode, + }); + } + } + + // Collect every ancestor directory (up to `dest`), then create them + // shallowest-first so a single mkdir() per dir is sufficient. + let mut seen = HashSet::new(); for entry in &entries { let mut p = entry.path.parent(); while let Some(dir) = p { - if dir == dest { + if dir == dest || !seen.insert(dir.to_path_buf()) { break; } - dirs.push(dir); p = dir.parent(); } } - dirs.sort_unstable(); - dirs.dedup(); + let mut dirs: Vec<_> = seen.into_iter().collect(); + dirs.sort_unstable_by_key(|p| p.as_os_str().len()); for dir in &dirs { fs::create_dir(dir).ok(); } - let buf: &[u8] = &output; + // Write files in parallel using rayon entries.par_iter().try_for_each(|entry| -> Result<()> { let mut file = fs::File::create(&entry.path) .with_context(|| format!("Failed to create: {}", entry.path.display()))?; - let data = &buf[entry.data_offset..entry.data_offset + entry.data_len]; - file.write_all(data) + file.write_all(&entry.content) .with_context(|| format!("Failed to write: {}", entry.path.display()))?; // Skip chmod for 0o644 (most files) — File::create() already produces @@ -147,69 +181,3 @@ fn extract_tarball_sync(gzip_bytes: Bytes, estimated_size: usize, dest: &Path) - Ok(()) } - -/// Walk the tar stream and collect file entries as `(path, offset, len, mode)` -/// tuples into the decompressed `buf`. Skips directories, ignores any -/// path-traversal entries. -fn parse_tar_entries(buf: &[u8], dest: &Path) -> Result> { - use std::io::Cursor; - - let cursor = Cursor::new(buf); - let mut archive = tar::Archive::new(cursor); - let mut entries = Vec::new(); - - for entry_result in archive.entries()? { - let entry = entry_result.with_context(|| "Failed to read tar entry")?; - let path = entry - .path() - .with_context(|| "Failed to get entry path")? - .into_owned(); - - // Guard against path traversal (Tar Slip): reject absolute paths - // and entries containing ".." components. - if path.is_absolute() - || path - .components() - .any(|c| matches!(c, std::path::Component::ParentDir)) - { - tracing::warn!("Skipping tar entry with unsafe path: {}", path.display()); - continue; - } - - if entry.header().entry_type().is_dir() { - continue; - } - - // tar::Entry exposes the byte offset and size inside the parsed - // stream — that's the same `buf` we'll later slice in `par_iter`. - let data_offset = entry.raw_file_position() as usize; - let data_len = entry.size() as usize; - if data_offset - .checked_add(data_len) - .is_none_or(|end| end > buf.len()) - { - anyhow::bail!( - "Tar entry {} extends past decompressed buffer ({}..+{} > {})", - path.display(), - data_offset, - data_len, - buf.len() - ); - } - - let full_path = dest.join(&path); - // Normalize to npm/pnpm convention: 0o755 if any exec bit is set, - // else 0o644. Preserving raw tar modes (e.g. 0o640 in google-protobuf) - // breaks world-readability in containers and multi-user setups. - let raw_mode = entry.header().mode().unwrap_or(0o644); - let mode = if raw_mode & 0o111 != 0 { 0o755 } else { 0o644 }; - entries.push(ExtractedEntry { - path: full_path, - data_offset, - data_len, - mode, - }); - } - - Ok(entries) -} diff --git a/crates/pm/src/util/logger.rs b/crates/pm/src/util/logger.rs index 28ba5539a2..6ba124bb24 100644 --- a/crates/pm/src/util/logger.rs +++ b/crates/pm/src/util/logger.rs @@ -161,24 +161,6 @@ pub fn log_progress(text: &str) { PROGRESS_BAR.set_message(text.to_string()); } -/// TTY-gated `PROGRESS_BAR.inc`. indicatif's inc takes its internal -/// state Mutex even with a hidden draw target — see [`IS_TTY`]. -#[inline] -pub fn progress_inc(n: u64) { - if !*IS_TTY { - return; - } - PROGRESS_BAR.inc(n); -} - -#[inline] -pub fn progress_set_length(len: u64) { - if !*IS_TTY { - return; - } - PROGRESS_BAR.set_length(len); -} - // Global timer for log_time/log_time_end static START_TIME: OnceCell = OnceCell::new(); From d513dbbd570cc8fbf730a8818d5073d761c12893 Mon Sep 17 00:00:00 2001 From: elrrrrrrr Date: Wed, 6 May 2026 23:05:09 +0800 Subject: [PATCH 16/16] chore: restore Cargo.lock to origin/next baseline Earlier compio experiment churned the lockfile; this PR ships no new crate deps so the lockfile diff was leftover noise. Reset to match next. --- Cargo.lock | 736 +++++++++-------------------------------------------- 1 file changed, 119 insertions(+), 617 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d126fe965f..3a136807b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1690,6 +1690,23 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "ctor" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83cf0d42651b16c6dfe68685716d18480d18a9c39c62d76e8cf3eb6ed5d8bcbf" +dependencies = [ + "ctor-proc-macro", + "dtor", + "link-section", +] + +[[package]] +name = "ctor-proc-macro" +version = "0.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a949c44fcacbbbb7ada007dc7acb34603dd97cd47de5d054f2b6493ecebb483" + [[package]] name = "cty" version = "0.2.2" @@ -2229,6 +2246,21 @@ dependencies = [ "dtoa", ] +[[package]] +name = "dtor" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edf234dd1594d6dd434a8fb8cada51ddbbc593e40e4a01556a0b31c62da2775b" +dependencies = [ + "dtor-proc-macro", +] + +[[package]] +name = "dtor-proc-macro" +version = "0.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2647271c92754afcb174e758003cfd1cbf1e43e5a7853d7b1813e63e19e39a73" + [[package]] name = "dunce" version = "1.0.5" @@ -4792,6 +4824,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "link-section" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b685d66585d646efe09fec763d796c291049c8b6bf84e04954bffc8748341f0d" + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -5342,7 +5380,7 @@ checksum = "55740c4ae1d8696773c78fdafd5d0e5fe9bc9f1b071c7ba493ba5c413a9184f3" dependencies = [ "anyhow", "bitflags 2.9.4", - "ctor", + "ctor 0.2.9", "napi-derive", "napi-sys", "once_cell", @@ -7170,9 +7208,9 @@ dependencies = [ [[package]] name = "roaring" -version = "0.10.12" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e8d2cfa184d94d0726d650a9f4a1be7f9b76ac9fdb954219878dc00c1c1e7b" +checksum = "1dedc5658c6ecb3bdb5ef5f3295bb9253f42dcf3fd1402c03f6b1f7659c3c4a9" dependencies = [ "bytemuck", "byteorder", @@ -8077,9 +8115,9 @@ dependencies = [ [[package]] name = "styled_components" -version = "3.0.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99aeadac58111060ad883c7e7a01917bcecc6572243c06d41315f200cbaa9240" +checksum = "72418ea605a423c70ffa8590196c83b04b04636fd25aaceabe0fa7f1e15f66f0" dependencies = [ "Inflector", "once_cell", @@ -8096,9 +8134,9 @@ dependencies = [ [[package]] name = "styled_jsx" -version = "3.0.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3917b257122e7cf3f46f95557af3178edaa9a3fd89fc1469768e05f01901e98" +checksum = "98cc5352e19f02be3ba10fb9ecbcd0d72e9b2d9762965712f1cbe737d1f428ec" dependencies = [ "anyhow", "lightningcss", @@ -8117,9 +8155,9 @@ dependencies = [ "swc_css_prefixer", "swc_css_visit", "swc_ecma_ast 23.0.0", - "swc_ecma_minifier 51.1.0", - "swc_ecma_parser 38.0.2", - "swc_ecma_transforms_base 41.0.1", + "swc_ecma_minifier", + "swc_ecma_parser 39.0.2", + "swc_ecma_transforms_base 42.0.0", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", "swc_plugin_macro", @@ -8132,57 +8170,6 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" -[[package]] -name = "swc" -version = "61.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb7d502b72d0b5e059cefe3a55825c43587a2e3c81025862694e52deecddc3de" -dependencies = [ - "anyhow", - "base64 0.22.1", - "bytes-str", - "dashmap 5.5.3", - "either", - "indexmap 2.13.0", - "jsonc-parser", - "once_cell", - "par-core", - "par-iter", - "parking_lot", - "regex", - "rustc-hash 2.1.1", - "serde", - "serde_json", - "swc_atoms", - "swc_common 21.0.1", - "swc_compiler_base 54.0.0", - "swc_config", - "swc_ecma_ast 23.0.0", - "swc_ecma_codegen 26.0.1", - "swc_ecma_ext_transforms", - "swc_ecma_loader", - "swc_ecma_minifier 51.1.0", - "swc_ecma_parser 38.0.2", - "swc_ecma_preset_env 52.0.0", - "swc_ecma_transforms 51.0.0", - "swc_ecma_transforms_base 41.0.1", - "swc_ecma_transforms_compat 47.0.0", - "swc_ecma_transforms_optimization 43.0.0", - "swc_ecma_utils 29.1.0", - "swc_ecma_visit 23.0.0", - "swc_error_reporters", - "swc_node_comments", - "swc_plugin_proxy", - "swc_plugin_runner", - "swc_sourcemap", - "swc_timer", - "swc_transform_common", - "swc_visit", - "tokio", - "tracing", - "url", -] - [[package]] name = "swc" version = "63.0.0" @@ -8206,19 +8193,19 @@ dependencies = [ "serde_json", "swc_atoms", "swc_common 21.0.1", - "swc_compiler_base 55.0.0", + "swc_compiler_base", "swc_config", "swc_ecma_ast 23.0.0", "swc_ecma_codegen 26.0.1", "swc_ecma_ext_transforms", "swc_ecma_loader", - "swc_ecma_minifier 52.0.4", + "swc_ecma_minifier", "swc_ecma_parser 39.0.2", - "swc_ecma_preset_env 53.0.0", - "swc_ecma_transforms 52.0.0", + "swc_ecma_preset_env", + "swc_ecma_transforms", "swc_ecma_transforms_base 42.0.0", - "swc_ecma_transforms_compat 48.0.0", - "swc_ecma_transforms_optimization 44.0.0", + "swc_ecma_transforms_compat", + "swc_ecma_transforms_optimization", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", "swc_error_reporters", @@ -8335,32 +8322,6 @@ dependencies = [ "url", ] -[[package]] -name = "swc_compiler_base" -version = "54.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "386c6121a98d7630ef5a07b79acee964c778568d61d3b76a188be17f19418a9c" -dependencies = [ - "anyhow", - "base64 0.22.1", - "bytes-str", - "once_cell", - "pathdiff", - "rustc-hash 2.1.1", - "serde", - "serde_json", - "swc_atoms", - "swc_common 21.0.1", - "swc_config", - "swc_ecma_ast 23.0.0", - "swc_ecma_codegen 26.0.1", - "swc_ecma_minifier 51.1.0", - "swc_ecma_parser 38.0.2", - "swc_ecma_visit 23.0.0", - "swc_sourcemap", - "swc_timer", -] - [[package]] name = "swc_compiler_base" version = "55.0.0" @@ -8380,7 +8341,7 @@ dependencies = [ "swc_config", "swc_ecma_ast 23.0.0", "swc_ecma_codegen 26.0.1", - "swc_ecma_minifier 52.0.4", + "swc_ecma_minifier", "swc_ecma_parser 39.0.2", "swc_ecma_visit 23.0.0", "swc_sourcemap", @@ -8437,38 +8398,6 @@ dependencies = [ "vergen", ] -[[package]] -name = "swc_core" -version = "63.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb9470306b0d532da617be037de878f64ec0f04cb364d920e8cee05d658d66de" -dependencies = [ - "par-core", - "swc 61.0.0", - "swc_allocator", - "swc_atoms", - "swc_common 21.0.1", - "swc_ecma_ast 23.0.0", - "swc_ecma_codegen 26.0.1", - "swc_ecma_lints", - "swc_ecma_loader", - "swc_ecma_minifier 51.1.0", - "swc_ecma_parser 38.0.2", - "swc_ecma_preset_env 52.0.0", - "swc_ecma_quote_macros", - "swc_ecma_transforms_base 41.0.1", - "swc_ecma_transforms_optimization 43.0.0", - "swc_ecma_transforms_proposal 41.0.3", - "swc_ecma_transforms_react 45.0.0", - "swc_ecma_transforms_typescript 45.0.2", - "swc_ecma_utils 29.1.0", - "swc_ecma_visit 23.0.0", - "swc_plugin_proxy", - "swc_plugin_runner", - "testing", - "vergen", -] - [[package]] name = "swc_core" version = "65.0.3" @@ -8476,24 +8405,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "898413141c6d3e1fed24ac3a4c57cc61ef98194df2a7957820d48ad158a318f6" dependencies = [ "par-core", - "swc 63.0.0", + "swc", "swc_allocator", "swc_atoms", "swc_common 21.0.1", "swc_ecma_ast 23.0.0", "swc_ecma_codegen 26.0.1", + "swc_ecma_lints", "swc_ecma_loader", - "swc_ecma_minifier 52.0.4", + "swc_ecma_minifier", "swc_ecma_parser 39.0.2", - "swc_ecma_preset_env 53.0.0", + "swc_ecma_preset_env", + "swc_ecma_quote_macros", "swc_ecma_transforms_base 42.0.0", - "swc_ecma_transforms_optimization 44.0.0", - "swc_ecma_transforms_react 46.0.1", - "swc_ecma_transforms_typescript 46.0.1", + "swc_ecma_transforms_optimization", + "swc_ecma_transforms_proposal", + "swc_ecma_transforms_react", + "swc_ecma_transforms_typescript", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", "swc_plugin_proxy", "swc_plugin_runner", + "testing", "vergen", ] @@ -8723,24 +8656,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "swc_ecma_compat_bugfixes" -version = "46.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22d4da77f7014b5efd416bb5208ab6e3d005ad5d532df8ced2904e50ca233d44" -dependencies = [ - "rustc-hash 2.1.1", - "swc_atoms", - "swc_common 21.0.1", - "swc_ecma_ast 23.0.0", - "swc_ecma_compat_es2015 45.0.0", - "swc_ecma_transforms_base 41.0.1", - "swc_ecma_utils 29.1.0", - "swc_ecma_visit 23.0.0", - "swc_trace_macro", - "tracing", -] - [[package]] name = "swc_ecma_compat_bugfixes" version = "47.0.0" @@ -8751,7 +8666,7 @@ dependencies = [ "swc_atoms", "swc_common 21.0.1", "swc_ecma_ast 23.0.0", - "swc_ecma_compat_es2015 46.0.0", + "swc_ecma_compat_es2015", "swc_ecma_transforms_base 42.0.0", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", @@ -8759,18 +8674,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "swc_ecma_compat_common" -version = "37.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d72d7d499e4bd4059ccfe432c1a52111a28fdd2b49b3882f18108fddfa3f6b4f" -dependencies = [ - "swc_common 21.0.1", - "swc_ecma_ast 23.0.0", - "swc_ecma_transformer 13.0.0", - "swc_ecma_utils 29.1.0", -] - [[package]] name = "swc_ecma_compat_common" version = "38.0.0" @@ -8779,38 +8682,10 @@ checksum = "04b936fe418e2bd707298357f560d269c1bdedc86a2325f7163307fe140806bd" dependencies = [ "swc_common 21.0.1", "swc_ecma_ast 23.0.0", - "swc_ecma_transformer 14.0.0", + "swc_ecma_transformer", "swc_ecma_utils 29.1.0", ] -[[package]] -name = "swc_ecma_compat_es2015" -version = "45.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5095800ee11e7c37df38a2e0fae2caa9d98b7801121d5f5ce70710ab65e21ec7" -dependencies = [ - "arrayvec", - "indexmap 2.13.0", - "is-macro", - "rustc-hash 2.1.1", - "serde", - "serde_derive", - "smallvec", - "swc_atoms", - "swc_common 21.0.1", - "swc_config", - "swc_ecma_ast 23.0.0", - "swc_ecma_compat_common 37.0.0", - "swc_ecma_transformer 13.0.0", - "swc_ecma_transforms_base 41.0.1", - "swc_ecma_transforms_classes 41.0.1", - "swc_ecma_transforms_macros", - "swc_ecma_utils 29.1.0", - "swc_ecma_visit 23.0.0", - "swc_trace_macro", - "tracing", -] - [[package]] name = "swc_ecma_compat_es2015" version = "46.0.0" @@ -8828,10 +8703,10 @@ dependencies = [ "swc_common 21.0.1", "swc_config", "swc_ecma_ast 23.0.0", - "swc_ecma_compat_common 38.0.0", - "swc_ecma_transformer 14.0.0", + "swc_ecma_compat_common", + "swc_ecma_transformer", "swc_ecma_transforms_base 42.0.0", - "swc_ecma_transforms_classes 42.0.0", + "swc_ecma_transforms_classes", "swc_ecma_transforms_macros", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", @@ -8839,19 +8714,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "swc_ecma_compat_es2016" -version = "42.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1358f912b0b5bdb6509f64dada8dc9ac8dc9233175b1d033c571cd34ad0bbec" -dependencies = [ - "swc_ecma_ast 23.0.0", - "swc_ecma_transformer 13.0.0", - "swc_ecma_transforms_base 41.0.1", - "swc_ecma_utils 29.1.0", - "tracing", -] - [[package]] name = "swc_ecma_compat_es2016" version = "43.0.0" @@ -8859,27 +8721,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4402a84df86ebd3723decdd041743ba8e48c7903bfe7f5c7c712bac46642ac90" dependencies = [ "swc_ecma_ast 23.0.0", - "swc_ecma_transformer 14.0.0", + "swc_ecma_transformer", "swc_ecma_transforms_base 42.0.0", "swc_ecma_utils 29.1.0", "tracing", ] -[[package]] -name = "swc_ecma_compat_es2017" -version = "42.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65a437c6a98cbfed7b355e2da721a52b1731537b6debf81cadccc9f196bbdbba" -dependencies = [ - "serde", - "swc_common 21.0.1", - "swc_ecma_ast 23.0.0", - "swc_ecma_transformer 13.0.0", - "swc_ecma_transforms_base 41.0.1", - "swc_ecma_utils 29.1.0", - "tracing", -] - [[package]] name = "swc_ecma_compat_es2017" version = "43.0.0" @@ -8889,26 +8736,12 @@ dependencies = [ "serde", "swc_common 21.0.1", "swc_ecma_ast 23.0.0", - "swc_ecma_transformer 14.0.0", + "swc_ecma_transformer", "swc_ecma_transforms_base 42.0.0", "swc_ecma_utils 29.1.0", "tracing", ] -[[package]] -name = "swc_ecma_compat_es2018" -version = "43.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27ffcf499581d598250e4d93d45ef64fe81b16f83c3bcb8c21d27af2004e6f54" -dependencies = [ - "serde", - "swc_ecma_ast 23.0.0", - "swc_ecma_transformer 13.0.0", - "swc_ecma_transforms_base 41.0.1", - "swc_ecma_utils 29.1.0", - "tracing", -] - [[package]] name = "swc_ecma_compat_es2018" version = "44.0.0" @@ -8917,26 +8750,12 @@ checksum = "757acfefd8ececa3fd3491e7dcbf6da1b7b5fba602b70b8f2b36af30fac35eea" dependencies = [ "serde", "swc_ecma_ast 23.0.0", - "swc_ecma_transformer 14.0.0", + "swc_ecma_transformer", "swc_ecma_transforms_base 42.0.0", "swc_ecma_utils 29.1.0", "tracing", ] -[[package]] -name = "swc_ecma_compat_es2019" -version = "42.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5125766d7ca9c4789eefdb68fd9d1bc9eba1119df21ad3d1fd7b0ac2808893d0" -dependencies = [ - "swc_common 21.0.1", - "swc_ecma_ast 23.0.0", - "swc_ecma_transformer 13.0.0", - "swc_ecma_transforms_base 41.0.1", - "swc_ecma_utils 29.1.0", - "tracing", -] - [[package]] name = "swc_ecma_compat_es2019" version = "43.0.0" @@ -8945,29 +8764,12 @@ checksum = "3a0f39d1ebadade7d0a0a137cedec958cfd38fe99c5c69c762d879650b5e9848" dependencies = [ "swc_common 21.0.1", "swc_ecma_ast 23.0.0", - "swc_ecma_transformer 14.0.0", + "swc_ecma_transformer", "swc_ecma_transforms_base 42.0.0", "swc_ecma_utils 29.1.0", "tracing", ] -[[package]] -name = "swc_ecma_compat_es2020" -version = "44.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eba7cf139b36cdf75daf9f1fc9096f566c8034d774ce040f09f0fccd4ffe02e" -dependencies = [ - "serde", - "swc_common 21.0.1", - "swc_ecma_ast 23.0.0", - "swc_ecma_compat_es2022 44.0.0", - "swc_ecma_transformer 13.0.0", - "swc_ecma_transforms_base 41.0.1", - "swc_ecma_utils 29.1.0", - "swc_ecma_visit 23.0.0", - "tracing", -] - [[package]] name = "swc_ecma_compat_es2020" version = "45.0.0" @@ -8977,27 +8779,14 @@ dependencies = [ "serde", "swc_common 21.0.1", "swc_ecma_ast 23.0.0", - "swc_ecma_compat_es2022 45.0.0", - "swc_ecma_transformer 14.0.0", + "swc_ecma_compat_es2022", + "swc_ecma_transformer", "swc_ecma_transforms_base 42.0.0", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", "tracing", ] -[[package]] -name = "swc_ecma_compat_es2021" -version = "42.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f64ee2ff23cdc2bb9749f3fb730bd4a95cc26cdea84b384b85574a1ab43f78af" -dependencies = [ - "swc_ecma_ast 23.0.0", - "swc_ecma_transformer 13.0.0", - "swc_ecma_transforms_base 41.0.1", - "swc_ecma_utils 29.1.0", - "tracing", -] - [[package]] name = "swc_ecma_compat_es2021" version = "43.0.0" @@ -9005,32 +8794,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfef1313a8410a2229aca737b65bb82c4aa45bdd6cedc0a0083688da0b960b20" dependencies = [ "swc_ecma_ast 23.0.0", - "swc_ecma_transformer 14.0.0", + "swc_ecma_transformer", "swc_ecma_transforms_base 42.0.0", "swc_ecma_utils 29.1.0", "tracing", ] -[[package]] -name = "swc_ecma_compat_es2022" -version = "44.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9e0499dc93f8eb04c88d5cf6aefc4ce34fdcca9dd69155d6882eb011339c9dd" -dependencies = [ - "rustc-hash 2.1.1", - "swc_atoms", - "swc_common 21.0.1", - "swc_ecma_ast 23.0.0", - "swc_ecma_transformer 13.0.0", - "swc_ecma_transforms_base 41.0.1", - "swc_ecma_transforms_classes 41.0.1", - "swc_ecma_transforms_macros", - "swc_ecma_utils 29.1.0", - "swc_ecma_visit 23.0.0", - "swc_trace_macro", - "tracing", -] - [[package]] name = "swc_ecma_compat_es2022" version = "45.0.0" @@ -9041,9 +8810,9 @@ dependencies = [ "swc_atoms", "swc_common 21.0.1", "swc_ecma_ast 23.0.0", - "swc_ecma_transformer 14.0.0", + "swc_ecma_transformer", "swc_ecma_transforms_base 42.0.0", - "swc_ecma_transforms_classes 42.0.0", + "swc_ecma_transforms_classes", "swc_ecma_transforms_macros", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", @@ -9130,42 +8899,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "swc_ecma_minifier" -version = "51.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c25a685c2efe2f88ba359dde0a17382b28a206ea21b23bda612f97b2c423b2f2" -dependencies = [ - "arrayvec", - "bitflags 2.9.4", - "indexmap 2.13.0", - "num-bigint", - "num_cpus", - "once_cell", - "par-core", - "par-iter", - "parking_lot", - "phf", - "radix_fmt", - "rustc-hash 2.1.1", - "ryu-js", - "serde", - "serde_json", - "swc_atoms", - "swc_common 21.0.1", - "swc_config", - "swc_ecma_ast 23.0.0", - "swc_ecma_codegen 26.0.1", - "swc_ecma_hooks", - "swc_ecma_parser 38.0.2", - "swc_ecma_transforms_base 41.0.1", - "swc_ecma_transforms_optimization 43.0.0", - "swc_ecma_utils 29.1.0", - "swc_ecma_visit 23.0.0", - "swc_timer", - "tracing", -] - [[package]] name = "swc_ecma_minifier" version = "52.0.4" @@ -9195,7 +8928,7 @@ dependencies = [ "swc_ecma_hooks", "swc_ecma_parser 39.0.2", "swc_ecma_transforms_base 42.0.0", - "swc_ecma_transforms_optimization 44.0.0", + "swc_ecma_transforms_optimization", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", "swc_timer", @@ -9222,27 +8955,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "swc_ecma_parser" -version = "38.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7c251d44e048647b5335861d1585b3e95fa8bc74f6e7a40570b0ea95d27ba66" -dependencies = [ - "bitflags 2.9.4", - "either", - "num-bigint", - "phf", - "rustc-hash 2.1.1", - "seq-macro", - "serde", - "smartstring", - "stacker", - "swc_atoms", - "swc_common 21.0.1", - "swc_ecma_ast 23.0.0", - "tracing", -] - [[package]] name = "swc_ecma_parser" version = "39.0.2" @@ -9257,37 +8969,13 @@ dependencies = [ "seq-macro", "serde", "smartstring", + "stacker", "swc_atoms", "swc_common 21.0.1", "swc_ecma_ast 23.0.0", "tracing", ] -[[package]] -name = "swc_ecma_preset_env" -version = "52.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5132d5890cddc4e47feb29c3388b4b0ca2251173c2c859c4b48b896794767c54" -dependencies = [ - "anyhow", - "foldhash 0.1.5", - "indexmap 2.13.0", - "once_cell", - "precomputed-map", - "preset_env_base", - "rustc-hash 2.1.1", - "serde", - "serde_json", - "string_enum", - "swc_atoms", - "swc_common 21.0.1", - "swc_ecma_ast 23.0.0", - "swc_ecma_transformer 13.0.0", - "swc_ecma_transforms 51.0.0", - "swc_ecma_utils 29.1.0", - "swc_ecma_visit 23.0.0", -] - [[package]] name = "swc_ecma_preset_env" version = "53.0.0" @@ -9307,17 +8995,17 @@ dependencies = [ "swc_atoms", "swc_common 21.0.1", "swc_ecma_ast 23.0.0", - "swc_ecma_transformer 14.0.0", - "swc_ecma_transforms 52.0.0", + "swc_ecma_transformer", + "swc_ecma_transforms", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", ] [[package]] name = "swc_ecma_quote_macros" -version = "38.0.0" +version = "39.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16896c184ff6915c85ee4bffd08db32e010b1c1a9628e6c4ee49a233653c20a7" +checksum = "54e4d28106d86d9c45d187687688d03bab7064bd8480d8bc783df9ff2a5d5a9a" dependencies = [ "anyhow", "proc-macro2", @@ -9326,7 +9014,7 @@ dependencies = [ "swc_atoms", "swc_common 21.0.1", "swc_ecma_ast 23.0.0", - "swc_ecma_parser 38.0.2", + "swc_ecma_parser 39.0.2", "swc_macros_common", "syn 2.0.106", ] @@ -9379,25 +9067,6 @@ dependencies = [ "swc_visit", ] -[[package]] -name = "swc_ecma_transformer" -version = "13.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65c334a42d7d8252e5a80dbae85a1230144d29f7ed4aa7feada2a47167f9282e" -dependencies = [ - "rustc-hash 2.1.1", - "swc_atoms", - "swc_common 21.0.1", - "swc_ecma_ast 23.0.0", - "swc_ecma_compat_regexp", - "swc_ecma_hooks", - "swc_ecma_regexp", - "swc_ecma_transforms_base 41.0.1", - "swc_ecma_utils 29.1.0", - "swc_ecma_visit 23.0.0", - "tracing", -] - [[package]] name = "swc_ecma_transformer" version = "14.0.0" @@ -9417,24 +9086,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "swc_ecma_transforms" -version = "51.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94503bbcd555d82cb33ff0e591e935bb925b79b254e94e706521f15d762b473" -dependencies = [ - "par-core", - "swc_common 21.0.1", - "swc_ecma_ast 23.0.0", - "swc_ecma_transforms_base 41.0.1", - "swc_ecma_transforms_compat 47.0.0", - "swc_ecma_transforms_optimization 43.0.0", - "swc_ecma_transforms_proposal 41.0.3", - "swc_ecma_transforms_react 45.0.0", - "swc_ecma_transforms_typescript 45.0.2", - "swc_ecma_utils 29.1.0", -] - [[package]] name = "swc_ecma_transforms" version = "52.0.0" @@ -9445,11 +9096,11 @@ dependencies = [ "swc_common 21.0.1", "swc_ecma_ast 23.0.0", "swc_ecma_transforms_base 42.0.0", - "swc_ecma_transforms_compat 48.0.0", - "swc_ecma_transforms_optimization 44.0.0", - "swc_ecma_transforms_proposal 42.0.0", - "swc_ecma_transforms_react 46.0.1", - "swc_ecma_transforms_typescript 46.0.1", + "swc_ecma_transforms_compat", + "swc_ecma_transforms_optimization", + "swc_ecma_transforms_proposal", + "swc_ecma_transforms_react", + "swc_ecma_transforms_typescript", "swc_ecma_utils 29.1.0", ] @@ -9475,28 +9126,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "swc_ecma_transforms_base" -version = "41.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6be824dc326da1f7673d1e241790626e5f39f09e1d896175134143408eeaa081" -dependencies = [ - "better_scoped_tls", - "indexmap 2.13.0", - "once_cell", - "par-core", - "phf", - "rustc-hash 2.1.1", - "serde", - "swc_atoms", - "swc_common 21.0.1", - "swc_ecma_ast 23.0.0", - "swc_ecma_parser 38.0.2", - "swc_ecma_utils 29.1.0", - "swc_ecma_visit 23.0.0", - "tracing", -] - [[package]] name = "swc_ecma_transforms_base" version = "42.0.0" @@ -9519,19 +9148,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "swc_ecma_transforms_classes" -version = "41.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ffae23e996fa1a7b20b77ff599aa0e4997a6eb21369e2e5e906c91b89fdffaa" -dependencies = [ - "swc_common 21.0.1", - "swc_ecma_ast 23.0.0", - "swc_ecma_transforms_base 41.0.1", - "swc_ecma_utils 29.1.0", - "swc_ecma_visit 23.0.0", -] - [[package]] name = "swc_ecma_transforms_classes" version = "42.0.0" @@ -9545,34 +9161,6 @@ dependencies = [ "swc_ecma_visit 23.0.0", ] -[[package]] -name = "swc_ecma_transforms_compat" -version = "47.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd54b7d82f0037f03367b4c9052a4ba2913e044df009fbeac388b2142c3ddd8a" -dependencies = [ - "indexmap 2.13.0", - "par-core", - "serde", - "swc_atoms", - "swc_common 21.0.1", - "swc_ecma_ast 23.0.0", - "swc_ecma_compat_bugfixes 46.0.0", - "swc_ecma_compat_common 37.0.0", - "swc_ecma_compat_es2015 45.0.0", - "swc_ecma_compat_es2016 42.0.0", - "swc_ecma_compat_es2017 42.0.0", - "swc_ecma_compat_es2018 43.0.0", - "swc_ecma_compat_es2019 42.0.0", - "swc_ecma_compat_es2020 44.0.0", - "swc_ecma_compat_es2021 42.0.0", - "swc_ecma_compat_es2022 44.0.0", - "swc_ecma_transforms_base 41.0.1", - "swc_ecma_utils 29.1.0", - "swc_ecma_visit 23.0.0", - "tracing", -] - [[package]] name = "swc_ecma_transforms_compat" version = "48.0.0" @@ -9585,16 +9173,16 @@ dependencies = [ "swc_atoms", "swc_common 21.0.1", "swc_ecma_ast 23.0.0", - "swc_ecma_compat_bugfixes 47.0.0", - "swc_ecma_compat_common 38.0.0", - "swc_ecma_compat_es2015 46.0.0", - "swc_ecma_compat_es2016 43.0.0", - "swc_ecma_compat_es2017 43.0.0", - "swc_ecma_compat_es2018 44.0.0", - "swc_ecma_compat_es2019 43.0.0", - "swc_ecma_compat_es2020 45.0.0", - "swc_ecma_compat_es2021 43.0.0", - "swc_ecma_compat_es2022 45.0.0", + "swc_ecma_compat_bugfixes", + "swc_ecma_compat_common", + "swc_ecma_compat_es2015", + "swc_ecma_compat_es2016", + "swc_ecma_compat_es2017", + "swc_ecma_compat_es2018", + "swc_ecma_compat_es2019", + "swc_ecma_compat_es2020", + "swc_ecma_compat_es2021", + "swc_ecma_compat_es2022", "swc_ecma_transforms_base 42.0.0", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", @@ -9613,30 +9201,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "swc_ecma_transforms_optimization" -version = "43.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae12179c92f0690850bae8932dfac2b7f191b8bfc6bac80dd81abfe6b0c014aa" -dependencies = [ - "bytes-str", - "dashmap 5.5.3", - "indexmap 2.13.0", - "once_cell", - "par-core", - "petgraph 0.7.1", - "rustc-hash 2.1.1", - "serde_json", - "swc_atoms", - "swc_common 21.0.1", - "swc_ecma_ast 23.0.0", - "swc_ecma_parser 38.0.2", - "swc_ecma_transforms_base 41.0.1", - "swc_ecma_utils 29.1.0", - "swc_ecma_visit 23.0.0", - "tracing", -] - [[package]] name = "swc_ecma_transforms_optimization" version = "44.0.0" @@ -9661,24 +9225,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "swc_ecma_transforms_proposal" -version = "41.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c49fd90ad7ef87cfacb9e15eb939bfecac83fe6638fdd4f94a31eff56b8276" -dependencies = [ - "either", - "rustc-hash 2.1.1", - "serde", - "swc_atoms", - "swc_common 21.0.1", - "swc_ecma_ast 23.0.0", - "swc_ecma_transforms_base 41.0.1", - "swc_ecma_transforms_classes 41.0.1", - "swc_ecma_utils 29.1.0", - "swc_ecma_visit 23.0.0", -] - [[package]] name = "swc_ecma_transforms_proposal" version = "42.0.0" @@ -9692,32 +9238,7 @@ dependencies = [ "swc_common 21.0.1", "swc_ecma_ast 23.0.0", "swc_ecma_transforms_base 42.0.0", - "swc_ecma_transforms_classes 42.0.0", - "swc_ecma_utils 29.1.0", - "swc_ecma_visit 23.0.0", -] - -[[package]] -name = "swc_ecma_transforms_react" -version = "45.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b41b35e76a78a01650dcfb92889d37fdebbc3b86932a052259c2a99e7955e699" -dependencies = [ - "base64 0.22.1", - "bytes-str", - "indexmap 2.13.0", - "once_cell", - "rustc-hash 2.1.1", - "serde", - "sha1", - "string_enum", - "swc_atoms", - "swc_common 21.0.1", - "swc_config", - "swc_ecma_ast 23.0.0", - "swc_ecma_hooks", - "swc_ecma_parser 38.0.2", - "swc_ecma_transforms_base 41.0.1", + "swc_ecma_transforms_classes", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", ] @@ -9747,24 +9268,6 @@ dependencies = [ "swc_ecma_visit 23.0.0", ] -[[package]] -name = "swc_ecma_transforms_typescript" -version = "45.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d25026f22efe873b50c97b3aaca6bfd178f954031effd14394e7b3add1e95fb" -dependencies = [ - "bytes-str", - "rustc-hash 2.1.1", - "serde", - "swc_atoms", - "swc_common 21.0.1", - "swc_ecma_ast 23.0.0", - "swc_ecma_transforms_base 41.0.1", - "swc_ecma_transforms_react 45.0.0", - "swc_ecma_utils 29.1.0", - "swc_ecma_visit 23.0.0", -] - [[package]] name = "swc_ecma_transforms_typescript" version = "46.0.1" @@ -9778,7 +9281,7 @@ dependencies = [ "swc_common 21.0.1", "swc_ecma_ast 23.0.0", "swc_ecma_transforms_base 42.0.0", - "swc_ecma_transforms_react 46.0.1", + "swc_ecma_transforms_react", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", ] @@ -9854,9 +9357,9 @@ dependencies = [ [[package]] name = "swc_emotion" -version = "3.0.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d8058e754b05eb672671b71974c4f79673b32bc2a2763706ba6970f8d2c86f" +checksum = "7077db4cd3dc9908a860c2e55b40ae6de8d6ce41d919867f2e58eb81b4019718" dependencies = [ "base64 0.22.1", "byteorder", @@ -9870,7 +9373,7 @@ dependencies = [ "swc_common 21.0.1", "swc_ecma_ast 23.0.0", "swc_ecma_codegen 26.0.1", - "swc_ecma_transforms 51.0.0", + "swc_ecma_transforms", "swc_ecma_utils 29.1.0", "swc_ecma_visit 23.0.0", "swc_sourcemap", @@ -10003,9 +9506,9 @@ dependencies = [ [[package]] name = "swc_relay" -version = "3.0.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1a0e98d0497d914f2a0736be9be050af6c3c0fbb2a9d911dae40379fffcc7c8" +checksum = "b592abba81c24baad593d6130a162beaa50699b5c2ba791a5b0db7be2dff1db4" dependencies = [ "once_cell", "regex", @@ -10962,6 +10465,7 @@ dependencies = [ "auto-hash-map", "bincode 2.0.1", "concurrent-queue", + "ctor 0.10.1", "dashmap 6.1.0", "either", "erased-serde", @@ -11134,8 +10638,10 @@ dependencies = [ name = "turbo-tasks-malloc" version = "0.1.0" dependencies = [ + "libc", "libmimalloc-sys", "mimalloc", + "windows-sys 0.60.2", ] [[package]] @@ -11235,7 +10741,6 @@ dependencies = [ "either", "indexmap 2.13.0", "num-bigint", - "once_cell", "patricia_tree", "petgraph 0.8.3", "ref-cast", @@ -11245,7 +10750,7 @@ dependencies = [ "serde", "serde_json", "smallvec", - "swc_core 63.1.3", + "swc_core 65.0.3", "swc_sourcemap", "tracing", "turbo-bincode", @@ -11277,7 +10782,7 @@ dependencies = [ "rustc-hash 2.1.1", "serde", "smallvec", - "swc_core 63.1.3", + "swc_core 65.0.3", "tokio", "tracing", "turbo-bincode", @@ -11344,7 +10849,6 @@ dependencies = [ "itertools 0.10.5", "num-bigint", "num-traits", - "once_cell", "parking_lot", "petgraph 0.8.3", "phf", @@ -11354,7 +10858,7 @@ dependencies = [ "serde_json", "smallvec", "strsim 0.11.1", - "swc_core 63.1.3", + "swc_core 65.0.3", "swc_sourcemap", "tokio", "tracing", @@ -11369,6 +10873,7 @@ dependencies = [ "turbopack-resolve", "turbopack-swc-utils", "url", + "urlencoding", ] [[package]] @@ -11396,7 +10901,7 @@ dependencies = [ "serde_json", "styled_components", "styled_jsx", - "swc_core 63.1.3", + "swc_core 65.0.3", "swc_emotion", "swc_plugin_backend_wasmtime", "swc_relay", @@ -11446,9 +10951,8 @@ dependencies = [ "bincode 2.0.1", "image", "mime", - "once_cell", + "phf", "regex", - "rustc-hash 2.1.1", "serde", "turbo-bincode", "turbo-rcstr", @@ -11492,7 +10996,6 @@ dependencies = [ "js-sys", "napi", "napi-derive", - "once_cell", "owo-colors", "parking_lot", "regex", @@ -11578,7 +11081,7 @@ version = "0.1.0" dependencies = [ "anyhow", "parking_lot", - "swc_core 63.1.3", + "swc_core 65.0.3", "turbo-rcstr", "turbo-tasks", "turbopack-core", @@ -11590,7 +11093,6 @@ version = "0.1.0" dependencies = [ "anyhow", "bincode 2.0.1", - "once_cell", "regex", "rustc-hash 2.1.1", "serde", @@ -11619,6 +11121,7 @@ dependencies = [ "rustc-hash 2.1.1", "serde", "serde_json", + "smallvec", "tungstenite 0.21.0", "turbo-rcstr", "turbo-tasks-malloc", @@ -11633,7 +11136,6 @@ dependencies = [ "anyhow", "crossbeam-channel", "crossbeam-utils", - "once_cell", "parking_lot", "postcard", "rustc-hash 2.1.1",