diff --git a/src/bundler/options.rs b/src/bundler/options.rs index 0470a8e38238..c4fb5f54df0f 100644 --- a/src/bundler/options.rs +++ b/src/bundler/options.rs @@ -2072,7 +2072,6 @@ pub enum PlaceholderField { Target, } -// Shared body for PathTemplate::needs / PathTemplateConst::needs (D064). #[inline] fn path_template_needs(data: &[u8], field: PlaceholderField) -> bool { let needle: &[u8] = match field { @@ -2113,7 +2112,6 @@ pub fn find_unterminated_placeholder(template: &[u8]) -> Option<(usize, &[u8])> None } -// Shared body for PathTemplate::print / PathTemplateConst::print (D064). // Writes raw path bytes via a byte-writer free fn (not `core::fmt::Display`). fn path_template_print( writer: &mut W, @@ -2424,45 +2422,6 @@ impl PlaceholderConst { }; } -impl PathTemplateConst { - /// Byte-writer form mirroring [`PathTemplate::print`]. - /// Kept as an inherent method so callers writing - /// to `Vec` via `write!(.., "{}", template)` resolve through the - /// blanket [`core::fmt::Display`] impl below. - pub(crate) fn print( - &self, - writer: &mut W, - sanitize_parent_dirs: bool, - ) -> bun_io::Result<()> { - path_template_print( - writer, - self.data, - self.placeholder.dir, - self.placeholder.name, - self.placeholder.ext, - self.placeholder.hash, - self.placeholder.target, - sanitize_parent_dirs, - ) - } -} - -impl core::fmt::Display for PathTemplateConst { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let mut buf = Vec::::new(); - self.print(&mut buf, true).map_err(|_| core::fmt::Error)?; - write!(f, "{}", bstr::BStr::new(&buf)) - } -} - -impl core::fmt::Display for PathTemplate { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let mut buf = Vec::::new(); - self.print(&mut buf, true).map_err(|_| core::fmt::Error)?; - write!(f, "{}", bstr::BStr::new(&buf)) - } -} - impl From for PathTemplate { fn from(c: PathTemplateConst) -> Self { PathTemplate { diff --git a/src/install/bin.rs b/src/install/bin.rs index 397537c8e380..0435a8d0977d 100644 --- a/src/install/bin.rs +++ b/src/install/bin.rs @@ -732,8 +732,6 @@ impl bun_collections::PriorityCompare for PriorityQueueContext { // Min-heap keyed by `PriorityQueueContext::less_than` (string-order of dep names). pub(crate) type PriorityQueue = bun_collections::PriorityQueue; -// `inherent_associated_types` is unstable, so callers use `Bin::PriorityQueueContext`. - // https://github.com/npm/npm-normalize-package-bin/blob/574e6d7cd21b2f3dee28a216ec2053c2551f7af9/lib/index.js#L38 fn normalized_bin_name(name: &[u8]) -> &[u8] { let name = match name diff --git a/src/jsc/DeprecatedStrong.rs b/src/jsc/DeprecatedStrong.rs index c8ef61c48f74..b09d92730de1 100644 --- a/src/jsc/DeprecatedStrong.rs +++ b/src/jsc/DeprecatedStrong.rs @@ -5,15 +5,6 @@ use core::ptr::NonNull; use crate::JSValue; -// Refcount contract (load-bearing): `ref()`/`unref()` calls must be balanced -// in pairs; Drop is the release for the `init()` protect. In debug builds a -// final `unref()` (ref_count 1 → 0) additionally frees the canary, zeroes -// `raw`, and clears `_safety` so a subsequent Drop is a no-op. Release builds -// have no ref_count, so an unref-used-as-release followed by Drop would -// double-unprotect — callers must never use `unref()` as the release. -// (Audited 2026-06: the only user is test_runner/Collection.rs, which uses -// `init` + Drop and never calls `ref`/`unref`.) - #[cfg(debug_assertions)] macro_rules! enable_safety { () => { @@ -40,7 +31,6 @@ struct SafetyData { // so freeing does NOT run DeprecatedStrong::drop on the sentinel value; the // pointer is stored cast to the inner type for ergonomic field access. ptr: NonNull, - ref_count: u32, } pub struct DeprecatedStrong { @@ -63,7 +53,6 @@ impl DeprecatedStrong { _safety: None, }))) .cast::(), - ref_count: 1, }); #[cfg(not(debug_assertions))] let _safety: Safety = (); @@ -76,32 +65,6 @@ impl DeprecatedStrong { pub fn get(&self) -> JSValue { self.raw } - - pub fn unref(&mut self) { - self.raw.unprotect(); - #[cfg(debug_assertions)] - if let Some(_safety) = &mut self._safety { - if _safety.ref_count == 1 { - // SAFETY: ptr was produced by heap::alloc in `init` and not yet freed. - unsafe { - debug_assert!((*_safety.ptr.as_ptr()).raw.encoded() == 0xAEBCFA); - (*_safety.ptr.as_ptr()).raw = JSValue::from_encoded(0xFFFFFF); - // Free without running Drop on the sentinel (ManuallyDrop is repr(transparent)). - drop(bun_core::heap::take( - _safety - .ptr - .as_ptr() - .cast::>(), - )); - } - // Neutralize so Drop is a no-op (see top-of-file refcount contract). - self._safety = None; - self.raw = JSValue::ZERO; - return; - } - _safety.ref_count -= 1; - } - } } impl Drop for DeprecatedStrong { @@ -109,12 +72,10 @@ impl Drop for DeprecatedStrong { self.raw.unprotect(); #[cfg(debug_assertions)] if let Some(_safety) = &mut self._safety { - // SAFETY: ptr was produced by heap::alloc in `init` and has not been freed - // (ref_count == 1 asserted below). + // SAFETY: ptr was produced by heap::alloc in `init` and has not been freed. unsafe { debug_assert!((*_safety.ptr.as_ptr()).raw.encoded() == 0xAEBCFA); (*_safety.ptr.as_ptr()).raw = JSValue::from_encoded(0xFFFFFF); - debug_assert!(_safety.ref_count == 1); // Free without running Drop on the sentinel (ManuallyDrop is repr(transparent)). drop(bun_core::heap::take( _safety diff --git a/src/jsc/bindings/URLSearchParams.cpp b/src/jsc/bindings/URLSearchParams.cpp index 6c88785176e2..914b4026a871 100644 --- a/src/jsc/bindings/URLSearchParams.cpp +++ b/src/jsc/bindings/URLSearchParams.cpp @@ -31,13 +31,6 @@ namespace WebCore { -extern "C" JSC::EncodedJSValue URLSearchParams__create(JSDOMGlobalObject* globalObject, const ZigString* input) -{ - String str = Zig::toString(*input); - auto result = URLSearchParams::create(str, nullptr); - return JSC::JSValue::encode(WebCore::toJSNewlyCreated(globalObject, globalObject, WTF::move(result))); -} - extern "C" WebCore::URLSearchParams* URLSearchParams__fromJS(JSC::EncodedJSValue value) { return WebCoreCast(value); diff --git a/src/jsc/bindings/bindings.cpp b/src/jsc/bindings/bindings.cpp index 59947724bd44..e85042268ff4 100644 --- a/src/jsc/bindings/bindings.cpp +++ b/src/jsc/bindings/bindings.cpp @@ -3024,10 +3024,6 @@ void JSC__JSString__toZigString(JSC::JSString* arg0, JSC::JSGlobalObject* arg1, // We don't need to assert here because ->value returns a reference to the same string as the one owned by the JSString. } -bool JSC__JSString__eql(const JSC::JSString* arg0, JSC::JSGlobalObject* obj, JSC::JSString* arg2) -{ - return arg0->equal(obj, arg2); -} bool JSC__JSString__is8Bit(const JSC::JSString* arg0) { return arg0->is8Bit(); }; size_t JSC__JSString__length(const JSC::JSString* arg0) { return arg0->length(); } diff --git a/src/jsc/bindings/headers.h b/src/jsc/bindings/headers.h index ddece38e8b43..ea2c8d4dc8b0 100644 --- a/src/jsc/bindings/headers.h +++ b/src/jsc/bindings/headers.h @@ -109,7 +109,6 @@ CPP_DECL JSC::JSObject* JSC__JSCell__toObject(JSC::JSCell* cell, JSC::JSGlobalOb #pragma mark - JSC::JSString -CPP_DECL bool JSC__JSString__eql(const JSC::JSString* arg0, JSC::JSGlobalObject* arg1, JSC::JSString* arg2); CPP_DECL bool JSC__JSString__is8Bit(const JSC::JSString* arg0); CPP_DECL void JSC__JSString__iterator(JSC::JSString* arg0, JSC::JSGlobalObject* arg1, void* arg2); CPP_DECL size_t JSC__JSString__length(const JSC::JSString* arg0); diff --git a/src/libarchive/lib.rs b/src/libarchive/lib.rs index 2b957cd9da25..8925918e89c0 100644 --- a/src/libarchive/lib.rs +++ b/src/libarchive/lib.rs @@ -522,10 +522,6 @@ pub mod lib { .expect("archive_read_new returned null"), ) } - #[inline] - pub fn as_ptr(&self) -> *mut Archive { - self.0.as_ptr() - } } impl core::ops::Deref for ReadArchive { type Target = Archive; @@ -554,10 +550,6 @@ pub mod lib { .expect("archive_write_new returned null"), ) } - #[inline] - pub fn as_ptr(&self) -> *mut Archive { - self.0.as_ptr() - } } impl core::ops::Deref for WriteArchive { type Target = Archive; @@ -583,10 +575,6 @@ pub mod lib { pub fn new() -> Self { Self(core::ptr::NonNull::new(Entry::new()).expect("archive_entry_new returned null")) } - #[inline] - pub fn as_ptr(&self) -> *mut Entry { - self.0.as_ptr() - } } impl core::ops::Deref for OwnedEntry { type Target = Entry; diff --git a/src/resolver/dir_info.rs b/src/resolver/dir_info.rs index 71579442f71a..84dceeb77073 100644 --- a/src/resolver/dir_info.rs +++ b/src/resolver/dir_info.rs @@ -26,9 +26,6 @@ pub type Index = IndexType; // only inside `dir_info_uncached` while filling a freshly-`put` slot, before // any handle to that slot escapes. All access is additionally serialized under // the resolver mutex. -// -// `as_ptr()` exposes the raw `*mut` for the few callers that still need it -// (the `dir_info_uncached` fill path and `MatchResult.dir_info` round-trip). // ───────────────────────────────────────────────────────────────────────────── /// Non-owning, `Copy` handle to a `DirInfo` slot in the BSSMap singleton. diff --git a/src/resolver/fs.rs b/src/resolver/fs.rs index b02e36ac6974..411a675bdf41 100644 --- a/src/resolver/fs.rs +++ b/src/resolver/fs.rs @@ -701,15 +701,6 @@ impl bun_dotenv::DirEntryProbe for DirEntry { } } -// pub fn statBatch(fs: *FileSystemEntry, paths: []string) ![]?Stat { -// } -// pub fn stat(fs: *FileSystemEntry, path: string) !Stat { -// } -// pub fn readFile(fs: *FileSystemEntry, path: string) ?string { -// } -// pub fn readDir(fs: *FileSystemEntry, path: string) ?[]string { -// } - #[derive(Default, Clone, Copy)] pub struct ModKey { pub(crate) size: u64, diff --git a/src/runtime/error.rs b/src/runtime/error.rs index 19466ef76a57..7eef4536525d 100644 --- a/src/runtime/error.rs +++ b/src/runtime/error.rs @@ -471,8 +471,6 @@ pub enum Error { StandaloneGraph(#[from] bun_standalone_graph::Error), #[error(transparent)] TerminalInit(crate::api::bun_terminal_body::InitError), - #[error(transparent)] - DirIterator(#[from] crate::node::dir_iterator::IteratorError), #[error("JSError")] Js(bun_jsc::JsError), } @@ -826,7 +824,6 @@ impl Error { Self::Sourcemap(e) => e.name(), Self::StandaloneGraph(e) => e.name(), Self::TerminalInit(e) => <&'static str>::from(e), - Self::DirIterator(e) => <&'static str>::from(e), Self::Js(bun_jsc::JsError::OutOfMemory) => "OutOfMemory", Self::Js(_) => "JSError", } diff --git a/src/runtime/node/dir_iterator.rs b/src/runtime/node/dir_iterator.rs index 0d89a1b1c822..39e719694060 100644 --- a/src/runtime/node/dir_iterator.rs +++ b/src/runtime/node/dir_iterator.rs @@ -15,17 +15,6 @@ use bun_sys::{self as sys, Fd, Tag}; // `bun_sys::EntryKind` (and as `crate::node::types::DirentKind`). use bun_sys::EntryKind; -#[derive(thiserror::Error, strum::IntoStaticStr, Debug, Clone, Copy, PartialEq, Eq)] -pub enum IteratorError { - #[error("AccessDenied")] - AccessDenied, - #[error("SystemResources")] - SystemResources, - /// posix.UnexpectedError - #[error("Unexpected")] - Unexpected, -} - pub struct IteratorResult { /// `RawSlice` invariant: borrows the iterator's `getdents` buffer /// (streaming-iterator contract — invalidated on next `next()` call). diff --git a/src/runtime/node/node_fs.rs b/src/runtime/node/node_fs.rs index b14243547d3f..a2a8128515b7 100644 --- a/src/runtime/node/node_fs.rs +++ b/src/runtime/node/node_fs.rs @@ -4527,12 +4527,6 @@ pub enum StatOrNotFound { NotFound, } impl StatOrNotFound { - pub fn to_js(&mut self, global_object: &JSGlobalObject) -> JsResult { - match self { - StatOrNotFound::Stats(s) => s.to_js_newly_created(global_object), - StatOrNotFound::NotFound => Ok(JSValue::UNDEFINED), - } - } pub(crate) fn to_js_newly_created(&self, global_object: &JSGlobalObject) -> JsResult { match self { StatOrNotFound::Stats(s) => s.to_js_newly_created(global_object), @@ -4558,11 +4552,6 @@ impl StringOrUndefined { /// For use in `Return`'s definitions to act as `void` while returning `null` to JavaScript pub struct Null; -impl Null { - pub fn to_js(&self, _: &JSGlobalObject) -> JSValue { - JSValue::NULL - } -} pub mod ret { use super::*; diff --git a/src/runtime/node/types.rs b/src/runtime/node/types.rs index 3c18a2543297..995e5ca1df13 100644 --- a/src/runtime/node/types.rs +++ b/src/runtime/node/types.rs @@ -1359,10 +1359,6 @@ pub struct VectorArrayBuffer { } impl VectorArrayBuffer { - pub fn to_js(&self, _: &JSGlobalObject) -> JSValue { - self.value - } - /// Release the per-element roots and pins taken by `from_js(.., pin: true)`. /// Must run on the JS thread, exactly once, after the I/O completes. pub(crate) fn release(&mut self) { diff --git a/src/runtime/server/RequestContext.rs b/src/runtime/server/RequestContext.rs index 87bd776e2c12..d7d5dd3ffd66 100644 --- a/src/runtime/server/RequestContext.rs +++ b/src/runtime/server/RequestContext.rs @@ -3161,7 +3161,6 @@ where this.run_error_handler(js_err); return; } - // .InlineBlob, Body::Value::WTFStringImpl(_) | Body::Value::InternalBlob(_) | Body::Value::Blob(_) => { // toBlobIfPossible checks for WTFString needing a conversion. this.blob = value.use_as_any_blob_allow_non_utf8_string(); @@ -4089,8 +4088,6 @@ where let total = bytes.len() + chunk.len(); 'getter: { - // TODO: small-body fast path via InlineBlob is not - // implemented; always build an InternalBlob. // Vec aborts on OOM (repo-wide abort-on-OOM policy). bytes.reserve_exact(total.saturating_sub(bytes.len())); bytes.extend_from_slice(chunk); diff --git a/src/runtime/webcore/Blob.rs b/src/runtime/webcore/Blob.rs index 921bc6cb7dbf..398c0db7a2c9 100644 --- a/src/runtime/webcore/Blob.rs +++ b/src/runtime/webcore/Blob.rs @@ -6869,55 +6869,6 @@ impl Internal { } } -// ────────────────────────────────────────────────────────────────────────── -// Inline (InlineBlob) -// ────────────────────────────────────────────────────────────────────────── - -/// A blob which stores all the data in the same space as a real Blob -/// This is an optimization for small Response and Request bodies -#[repr(C, packed)] -pub struct Inline { - pub(crate) bytes: [u8; Inline::AVAILABLE_BYTES], - pub(crate) len: u8, - pub(crate) was_string: bool, -} - -impl Inline { - const REAL_BLOB_SIZE: usize = core::mem::size_of::(); - // Inherent assoc types are nightly-only; - // the int-size alias is hoisted to module-level `InlineIntSize` above. - pub(crate) const AVAILABLE_BYTES: usize = - Self::REAL_BLOB_SIZE - core::mem::size_of::() - 1 - 1; - - pub fn concat(first: &[u8], second: &[u8]) -> Inline { - let total = first.len() + second.len(); - debug_assert!(total <= Self::AVAILABLE_BYTES); - - let mut inline_blob = Inline::default(); - let bytes_slice = &mut inline_blob.bytes[..total]; - - if !first.is_empty() { - bytes_slice[..first.len()].copy_from_slice(first); - } - if !second.is_empty() { - bytes_slice[first.len()..][..second.len()].copy_from_slice(second); - } - - inline_blob.len = total as u8; - inline_blob - } -} - -impl Default for Inline { - fn default() -> Self { - Self { - bytes: [0; Self::AVAILABLE_BYTES], - len: 0, - was_string: false, - } - } -} - // ────────────────────────────────────────────────────────────────────────── // JSDOMFile__hasInstance / FileOpener / FileCloser // ────────────────────────────────────────────────────────────────────────── diff --git a/src/runtime/webcore/Body.rs b/src/runtime/webcore/Body.rs index f19decab0571..051e9218d1b4 100644 --- a/src/runtime/webcore/Body.rs +++ b/src/runtime/webcore/Body.rs @@ -509,8 +509,6 @@ pub enum Value { /// Single-use Blob /// Avoids a heap allocation. InternalBlob(InternalBlob), - /// Single-use Blob that stores the bytes in the Value itself. - // InlineBlob(InlineBlob), Locked(PendingValue), Used, Empty, @@ -544,7 +542,6 @@ pub enum Tag { Blob, WTFStringImpl, InternalBlob, - // InlineBlob, Locked, Used, Empty, @@ -714,7 +711,6 @@ impl Value { AnyBlob::Blob(b) => Value::Blob(b), AnyBlob::InternalBlob(b) => Value::InternalBlob(b), AnyBlob::WTFStringImpl(s) => Value::WTFStringImpl(s), - // AnyBlob::InlineBlob(b) => Value::InlineBlob(b), }; } } @@ -725,7 +721,6 @@ impl Value { Value::InternalBlob(b) => b.slice_const().len() as blob::SizeType, Value::WTFStringImpl(s) => wtf_impl(s).utf8_byte_length() as blob::SizeType, Value::Locked(l) => l.size_hint(), - // Value::InlineBlob(b) => b.slice_const().len() as blob::SizeType, _ => 0, } } @@ -735,7 +730,6 @@ impl Value { Value::InternalBlob(b) => b.memory_cost(), Value::WTFStringImpl(s) => wtf_impl(s).memory_cost(), Value::Locked(l) => l.size_hint() as usize, - // Value::InlineBlob(b) => b.slice_const().len(), _ => 0, } } @@ -745,13 +739,10 @@ impl Value { Value::InternalBlob(b) => b.slice_const().len(), Value::WTFStringImpl(s) => wtf_impl(s).byte_slice().len(), Value::Locked(l) => l.size_hint() as usize, - // Value::InlineBlob(b) => b.slice_const().len(), _ => 0, } } - // pub const empty = Value::Empty; - pub(crate) fn to_readable_stream(&mut self, global_this: &JSGlobalObject) -> JsResult { jsc::mark_binding(); @@ -1102,7 +1093,7 @@ impl Value { // These ones must use promise.wrap() to handle exceptions thrown while calling .toJS() on the value. // These exceptions can happen if the String is too long, ArrayBuffer is too large, JSON parse error, etc. Action::GetText => match new { - Value::WTFStringImpl(_) | Value::InternalBlob(_) /* | Value::InlineBlob(_) */ => { + Value::WTFStringImpl(_) | Value::InternalBlob(_) => { let mut blob = new.use_as_any_blob_allow_non_utf8_string(); let result = promise.wrap(global, |g| blob.to_string_transfer(g)); blob.detach(); @@ -1228,17 +1219,6 @@ impl Value { wtf_ref.deref(); new_blob } - // Value::InlineBlob(_) => { - // let cloned = self.InlineBlob.bytes; - // // keep same behavior as InternalBlob but clone the data - // let new_blob = Blob::create( - // &cloned[0..self.InlineBlob.len], - // VirtualMachine::get().global, - // false, - // ); - // *self = Value::Used; - // new_blob - // } // `Blob::default()` leaves `global_this` null which matches the // don't-care contract here. _ => Blob::default(), @@ -1297,7 +1277,6 @@ impl Value { break 'brk AnyBlob::WTFStringImpl(str); } } - // Value::InlineBlob(b) => AnyBlob::InlineBlob(b), Value::Locked(l) => l .to_any_blob_allow_promise() .unwrap_or(AnyBlob::Blob(Blob::default())), @@ -1320,7 +1299,6 @@ impl Value { let _ = core::mem::ManuallyDrop::new(core::mem::replace(self, Value::Used)); AnyBlob::WTFStringImpl(s) } - // Value::InlineBlob(b) => AnyBlob::InlineBlob(b), Value::Locked(l) => l .to_any_blob_allow_promise() .unwrap_or(AnyBlob::Blob(Blob::default())), @@ -2326,7 +2304,6 @@ impl<'a> ValueBufferer<'a> { (self.on_finished_buffering)(self.ctx, b"", Some(err_copy), false); return Ok(()); } - // Value::InlineBlob(_) | Value::WTFStringImpl(_) | Value::InternalBlob(_) | Value::Blob(_) => { // toBlobIfPossible checks for WTFString needing a conversion. let mut input = value.use_as_any_blob_allow_non_utf8_string(); diff --git a/src/runtime/webcore/FileReader.rs b/src/runtime/webcore/FileReader.rs index e18936c83a78..3e46c880f4a7 100644 --- a/src/runtime/webcore/FileReader.rs +++ b/src/runtime/webcore/FileReader.rs @@ -93,7 +93,6 @@ impl Default for FileReader { } pub type IOReader = BufferedReader; -pub const TAG: readable_stream::Tag = readable_stream::Tag::File; #[derive(strum::IntoStaticStr)] pub enum ReadDuringJSOnPullResult { diff --git a/src/runtime/webcore/Response.rs b/src/runtime/webcore/Response.rs index be79badd01a0..7c59e96ad5f1 100644 --- a/src/runtime/webcore/Response.rs +++ b/src/runtime/webcore/Response.rs @@ -378,8 +378,8 @@ impl Response { } /// R-2 `JsCell` escape hatch — single-JS-thread invariant. Centralises the - /// `unsafe { self.init.get_mut() }` deref so the four call sites - /// ([`get_init_headers_mut`], [`header`], [`get_or_create_headers`], + /// `unsafe { self.init.get_mut() }` deref so the three call sites + /// ([`get_init_headers_mut`], [`get_or_create_headers`], /// [`get_content_type`]) read it as a plain `&mut Init`. /// /// # Safety (encapsulated) diff --git a/src/runtime/webcore/streams.rs b/src/runtime/webcore/streams.rs index 0e8f0676b5f0..dc14a97f8445 100644 --- a/src/runtime/webcore/streams.rs +++ b/src/runtime/webcore/streams.rs @@ -2398,10 +2398,6 @@ impl BufferAction { self.promise.value() } - pub fn get(&self) -> *mut JSPromise { - std::ptr::from_mut(self.promise.get()) - } - pub(crate) fn swap(&mut self) -> *mut JSPromise { std::ptr::from_mut(self.promise.swap()) } diff --git a/test/internal/source-lints/dead-symbols-35559.test.ts b/test/internal/source-lints/dead-symbols-35559.test.ts new file mode 100644 index 000000000000..d1eedf7a5259 --- /dev/null +++ b/test/internal/source-lints/dead-symbols-35559.test.ts @@ -0,0 +1,104 @@ +// Guards against reintroduction of symbols removed in #35559. Each entry was +// verified to have zero callers across src/ and build/debug/codegen/ before +// deletion, and a full build plus rust:check-all (all targets) passes without +// them. This test fails if any of them reappear, e.g. via a merge that +// resurrects a stale file or a copy-paste from an old branch. +// +// This is a source-tree lint: it reads files from src/ and does not touch the +// built binary, so it belongs in test/internal/source-lints/ per the README. + +import { expect, test } from "bun:test"; +import { readFileSync } from "node:fs"; +import path from "node:path"; + +const repoRoot = path.resolve(import.meta.dir, "..", "..", ".."); + +function src(p: string): string { + return readFileSync(path.join(repoRoot, p), "utf8"); +} + +function resurrected(checks: Array<[string, RegExp]>): string[] { + return checks.filter(([file, re]) => re.test(src(file))).map(([file, re]) => `${file}: ${re.source}`); +} + +test("dead webcore items removed in #35559 do not reappear", () => { + const checks: Array<[string, RegExp]> = [ + // blob::Inline was never constructed; every Body::Value::InlineBlob arm + // existed only as commented-out code. + ["src/runtime/webcore/Blob.rs", /pub struct Inline \{/], + ["src/runtime/webcore/Blob.rs", /impl Inline \{/], + ["src/runtime/webcore/Body.rs", /InlineBlob/], + ["src/runtime/server/RequestContext.rs", /InlineBlob/], + // StreamResult::is_done is live; Writable's is the one that was removed. + ["src/runtime/webcore/streams.rs", /impl Writable \{\n\s*pub fn is_done\b/], + ["src/runtime/webcore/streams.rs", /pub fn init\(handler: &mut T\) -> Signal \{/], + // BufferAction is consumed only via fulfill/reject/value/swap. + ["src/runtime/webcore/streams.rs", /pub fn get\(&self\) -> \*mut JSPromise \{/], + ["src/runtime/webcore/Response.rs", /pub fn header\(&self, name: HTTPHeaderName\)/], + ["src/runtime/webcore/Response.rs", /pub fn from_js_direct\(value: JSValue\) -> Option<\*mut Response>/], + ["src/runtime/webcore/ReadableStream.rs", /pub fn unref\(&mut self\) \{\s*\n\s*if C::SUPPORTS_REF/], + ["src/runtime/webcore/FileReader.rs", /pub const TAG: readable_stream::Tag/], + ]; + expect(resurrected(checks)).toEqual([]); +}); + +test("dead jsc helpers removed in #35559 do not reappear", () => { + const checks: Array<[string, RegExp]> = [ + // The only user (test_runner/Collection.rs) uses init + Drop; no ref() + // counterpart exists. + ["src/jsc/DeprecatedStrong.rs", /pub fn unref\(&mut self\)/], + ["src/jsc/Strong.rs", /pub fn call\(&mut self, global: &JSGlobalObject, args: &\[JSValue\]\)/], + ["src/jsc/Weak.rs", /pub fn init\(\) -> Self \{/], + ["src/jsc/Weak.rs", /pub fn has\(&self\) -> bool \{/], + ["src/jsc/JSPropertyIterator.rs", /pub fn reset\(&mut self\) \{/], + ["src/jsc/JSString.rs", /pub fn eql\(&self, global: &JSGlobalObject, other: &JSString\)/], + ["src/jsc/JSString.rs", /JSC__JSString__eql/], + ["src/jsc/URLSearchParams.rs", /URLSearchParams__create/], + // C++ sides of the removed extern imports. + ["src/jsc/bindings/bindings.cpp", /JSC__JSString__eql/], + ["src/jsc/bindings/headers.h", /JSC__JSString__eql/], + ["src/jsc/bindings/URLSearchParams.cpp", /URLSearchParams__create/], + // ref_count became write-only once unref() was removed. + ["src/jsc/DeprecatedStrong.rs", /ref_count/], + ]; + expect(resurrected(checks)).toEqual([]); +}); + +test("dead bundler/ast items removed in #35559 do not reappear", () => { + const checks: Array<[string, RegExp]> = [ + // Callers use PathTemplate::print directly; nothing formats either type + // via Display. + ["src/bundler/options.rs", /impl PathTemplateConst \{/], + ["src/bundler/options.rs", /impl core::fmt::Display for PathTemplateConst/], + ["src/bundler/options.rs", /impl core::fmt::Display for PathTemplate \{/], + // Only self-recursive; external is_boolean() calls are on JSValue. + ["src/ast/expr.rs", /pub fn is_boolean\(&self\) -> bool \{/], + ["src/ast/lib.rs", /pub fn init_comptime\(\) -> Log \{/], + ]; + expect(resurrected(checks)).toEqual([]); +}); + +test("dead install/spawn/node/resolver items removed in #35559 do not reappear", () => { + const checks: Array<[string, RegExp]> = [ + ["src/install/PackageManager/ProgressStrings.rs", /pub fn extract\(\) -> &'static \[u8\]/], + ["src/install/PackageManager/ProgressStrings.rs", /EXTRACT_NO_EMOJI_/], + ["src/install/bin.rs", /pub type Context = PriorityQueueContext;/], + ["src/install/PackageManager/security_scanner.rs", /pub fn event_loop\(&self\) -> &AnyEventLoop \{/], + ["src/install/lockfile/Package/Scripts.rs", /pub fn first\(&self\) -> &\[u8\] \{/], + ["src/spawn/static_pipe_writer.rs", /pub fn get_buffer\(&self\) -> &\[u8\]/], + ["src/spawn/static_pipe_writer.rs", /pub fn flush\(&mut self\) \{/], + ["src/spawn/static_pipe_writer.rs", /pub fn loop_\(&self\) -> \*mut AsyncLoop/], + // ResultTaskMini::run_from_main_thread_mini (private) is live; the + // removed one was `pub fn` on ResultTask. + ["src/spawn/process.rs", /pub fn run_from_main_thread_mini\b/], + // Never constructed; the iterator returns bun_sys::Error. + ["src/runtime/node/dir_iterator.rs", /pub enum IteratorError \{/], + ["src/runtime/error.rs", /DirIterator\(/], + ["src/runtime/node/node_fs.rs", /impl Null \{\s*\n\s*pub fn to_js/], + ["src/runtime/node/types.rs", /impl VectorArrayBuffer \{\s*\n\s*pub fn to_js/], + ["src/resolver/dir_info.rs", /pub const fn as_ptr\(self\) -> \*mut DirInfo/], + ["src/resolver/fs.rs", /pub fn statBatch/], + ["src/libarchive/lib.rs", /pub fn as_ptr\(&self\) -> \*mut Archive \{/], + ]; + expect(resurrected(checks)).toEqual([]); +});