diff --git a/crates/fspy/tests/oxlint.rs b/crates/fspy/tests/oxlint.rs index f093aab0..87780f32 100644 --- a/crates/fspy/tests/oxlint.rs +++ b/crates/fspy/tests/oxlint.rs @@ -1,20 +1,24 @@ mod test_utils; -use std::{env::vars_os, process::Stdio}; +use std::{env::vars_os, ffi::OsString}; use fspy::{AccessMode, PathAccessIterable}; use test_log::test; -/// Find the oxlint executable in test_bins -fn find_oxlint() -> std::path::PathBuf { - let test_bins_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) +/// Get the test_bins/.bin directory path +fn test_bins_bin_dir() -> std::path::PathBuf { + std::path::Path::new(env!("CARGO_MANIFEST_DIR")) .parent() .unwrap() .join("vite_task_bin") .join("test_bins") .join("node_modules") - .join(".bin"); + .join(".bin") +} +/// Find the oxlint executable in test_bins +fn find_oxlint() -> std::path::PathBuf { + let test_bins_dir = test_bins_bin_dir(); which::which_in("oxlint", Some(&test_bins_dir), std::env::current_dir().unwrap()) .expect("oxlint not found in test_bins/node_modules/.bin") } @@ -22,7 +26,22 @@ fn find_oxlint() -> std::path::PathBuf { async fn track_oxlint(dir: &std::path::Path, args: &[&str]) -> anyhow::Result { let oxlint_path = find_oxlint(); let mut command = fspy::Command::new(&oxlint_path); - command.args(args).stdout(Stdio::null()).stderr(Stdio::null()).envs(vars_os()).current_dir(dir); + + // Build PATH with test_bins/.bin prepended so oxlint can find tsgolint + let test_bins_dir = test_bins_bin_dir(); + let new_path = if let Some(existing_path) = std::env::var_os("PATH") { + let mut paths = vec![test_bins_dir.as_os_str().to_owned()]; + paths.extend(std::env::split_paths(&existing_path).map(|p| p.into_os_string())); + std::env::join_paths(paths)? + } else { + OsString::from(&test_bins_dir) + }; + + command + .args(args) + .envs(vars_os().filter(|(k, _)| !k.eq_ignore_ascii_case("PATH"))) + .env("PATH", new_path) + .current_dir(dir); let child = command.spawn().await?; let termination = child.wait_handle.await?; @@ -54,9 +73,6 @@ async fn oxlint_reads_directory() -> anyhow::Result<()> { // on macOS, tmpdir.path() may be a symlink, so we need to canonicalize it let tmpdir_path = std::fs::canonicalize(tmpdir.path())?; - let js_file = tmpdir.path().join("test.js"); - std::fs::write(&js_file, "console.log('hello');")?; - let accesses = track_oxlint(&tmpdir_path, &[]).await?; // Check that oxlint read the directory to find JS files @@ -64,3 +80,37 @@ async fn oxlint_reads_directory() -> anyhow::Result<()> { test_utils::assert_contains(&accesses, &tmpdir_path, AccessMode::READ_DIR); Ok(()) } + +#[test(tokio::test)] +async fn oxlint_type_aware() -> anyhow::Result<()> { + let tmpdir = tempfile::tempdir()?; + // on macOS, tmpdir.path() may be a symlink, so we need to canonicalize it + let tmpdir_path = std::fs::canonicalize(tmpdir.path())?; + + // Create a simple TypeScript file + let ts_file = tmpdir_path.join("index.ts"); + std::fs::write( + &ts_file, + r#" +import type { Foo } from './types'; +declare const _foo: Foo; +"#, + )?; + + // Run oxlint without --type-aware first + let accesses = track_oxlint(&tmpdir_path, &[""]).await?; + let access_to_types_ts = accesses.iter().find(|access| { + let os_str = access.path.to_cow_os_str(); + os_str.as_encoded_bytes().ends_with(b"\\types.ts") + || os_str.as_encoded_bytes().ends_with(b"/types.ts") + }); + assert_eq!(access_to_types_ts, None, "oxlint should not read types.ts without --type-aware"); + + // Run oxlint with --type-aware to enable type-aware linting + let accesses = track_oxlint(&tmpdir_path, &["--type-aware"]).await?; + + // Check that oxlint read types.ts + test_utils::assert_contains(&accesses, &tmpdir_path.join("types.ts"), AccessMode::READ); + + Ok(()) +} diff --git a/crates/fspy/tests/rust_std.rs b/crates/fspy/tests/rust_std.rs index 2ff9e0a0..633ec11b 100644 --- a/crates/fspy/tests/rust_std.rs +++ b/crates/fspy/tests/rust_std.rs @@ -37,11 +37,25 @@ async fn open_write() -> anyhow::Result<()> { #[test(tokio::test)] async fn readdir() -> anyhow::Result<()> { - let accesses = track_child!((), |(): ()| { + let tmpdir = tempfile::tempdir()?; + let tmpdir_path = std::fs::canonicalize(tmpdir.path())?; + // Reading a non-existent directory results in different tracked accesses on different platforms: + // - Windows: READ, because the NT APIs open the directory as handle just like files (NtCreateFile/NtOpenFile), + // and if that fails, not read dir call (NtQueryDirectoryFile/NtQueryDirectoryFileEx) is made. + // - macOS/Linux: + // - opendir results in a read_dir access. This call is directly made without trying to open the directory as a fd first. + // - open + fopendir results in READ access, because open would fail with ENOENT, and fopendir is not called. + // + // This difference is acceptable because both will result in a "not found" fingerprint in vite-task. + // To keep the test consistent across platforms, we create the directory first. + std::fs::create_dir(tmpdir.path().join("hello_dir"))?; + + let accesses = track_child!(tmpdir_path.to_str().unwrap().to_owned(), |tmpdir_path: String| { + std::env::set_current_dir(tmpdir_path).unwrap(); let _ = std::fs::read_dir("hello_dir"); }) .await?; - assert_contains(&accesses, current_dir()?.join("hello_dir").as_path(), AccessMode::READ_DIR); + assert_contains(&accesses, tmpdir_path.join("hello_dir").as_path(), AccessMode::READ_DIR); Ok(()) } diff --git a/crates/fspy/tests/rust_tokio.rs b/crates/fspy/tests/rust_tokio.rs index e847ba1a..7e13ea36 100644 --- a/crates/fspy/tests/rust_tokio.rs +++ b/crates/fspy/tests/rust_tokio.rs @@ -42,7 +42,13 @@ async fn open_write() -> anyhow::Result<()> { #[test(tokio::test)] async fn readdir() -> anyhow::Result<()> { - let accesses = track_child!((), |(): ()| { + let tmpdir = tempfile::tempdir()?; + let tmpdir_path = std::fs::canonicalize(tmpdir.path())?; + + std::fs::create_dir(tmpdir.path().join("hello_dir"))?; + + let accesses = track_child!(tmpdir_path.to_str().unwrap().to_owned(), |tmpdir_path: String| { + std::env::set_current_dir(tmpdir_path).unwrap(); tokio::runtime::Builder::new_current_thread().enable_io().build().unwrap().block_on( async { let _ = tokio::fs::read_dir("hello_dir").await; @@ -50,7 +56,7 @@ async fn readdir() -> anyhow::Result<()> { ); }) .await?; - assert_contains(&accesses, current_dir()?.join("hello_dir").as_path(), AccessMode::READ_DIR); + assert_contains(&accesses, tmpdir_path.join("hello_dir").as_path(), AccessMode::READ_DIR); Ok(()) } diff --git a/crates/fspy_preload_windows/src/windows/convert.rs b/crates/fspy_preload_windows/src/windows/convert.rs index 6787bc13..e33a21af 100644 --- a/crates/fspy_preload_windows/src/windows/convert.rs +++ b/crates/fspy_preload_windows/src/windows/convert.rs @@ -50,16 +50,24 @@ impl ToAbsolutePath for POBJECT_ATTRIBUTES { self, f: F, ) -> winsafe::SysResult { - let filename_str = unsafe { get_u16_str(&*(*self).ObjectName) }; + let filename_str = if let Some(object_name) = unsafe { (*self).ObjectName.as_ref() } { + unsafe { get_u16_str(object_name) } + } else { + U16Str::from_slice(&[]) + }; let filename_slice = filename_str.as_slice(); - let is_absolute = (filename_slice.get(0) == Some(&b'\\'.into()) - && filename_slice.get(1) == Some(&b'\\'.into())) // \\... + let is_absolute = filename_slice.get(0) == Some(&b'\\'.into()) // \... || filename_slice.get(1) == Some(&b':'.into()); // C:... - if is_absolute { + if !is_absolute { let Ok(mut root_dir) = (unsafe { get_path_name((*self).RootDirectory) }) else { return f(None); }; + // If filename is empty, just use root_dir directly + if filename_str.is_empty() { + let root_dir_str = U16Str::from_slice(&root_dir); + return f(Some(root_dir_str)); + } let root_dir_cstr = { root_dir.push(0); unsafe { U16CStr::from_ptr_str(root_dir.as_ptr()) } diff --git a/crates/fspy_preload_windows/src/windows/detour.rs b/crates/fspy_preload_windows/src/windows/detour.rs index 0b8a2ddc..92bce9c7 100644 --- a/crates/fspy_preload_windows/src/windows/detour.rs +++ b/crates/fspy_preload_windows/src/windows/detour.rs @@ -21,7 +21,6 @@ impl Detour { Detour { symbol_name, target: UnsafeCell::new(unsafe { transmute_copy(&target) }), new } } - #[expect(dead_code)] pub const unsafe fn dynamic(symbol_name: &'static CStr, new: T) -> Self { Detour { symbol_name, target: UnsafeCell::new(null_mut()), new } } @@ -52,15 +51,18 @@ pub struct DetourAny { pub struct AttachContext { kernelbase: HMODULE, kernel32: HMODULE, + ntdll: HMODULE, } impl AttachContext { pub fn new() -> Self { let kernelbase = unsafe { LoadLibraryA(c"kernelbase".as_ptr()) }; let kernel32 = unsafe { LoadLibraryA(c"kernel32".as_ptr()) }; + let ntdll = unsafe { LoadLibraryA(c"ntdll".as_ptr()) }; assert_ne!(kernelbase, null_mut()); assert_ne!(kernel32, null_mut()); - Self { kernelbase, kernel32 } + assert_ne!(ntdll, null_mut()); + Self { kernelbase, kernel32, ntdll } } } @@ -74,9 +76,14 @@ impl DetourAny { unsafe { *self.target = symbol_in_kernelbase.cast() }; } else { if unsafe { *self.target }.is_null() { - // dynamic symbol + // dynamic symbol - look up from kernel32 or ntdll let symbol_in_kernel32 = unsafe { GetProcAddress(ctx.kernel32, symbol_name) }; - unsafe { *self.target = symbol_in_kernel32.cast() }; + if !symbol_in_kernel32.is_null() { + unsafe { *self.target = symbol_in_kernel32.cast() }; + } else { + let symbol_in_ntdll = unsafe { GetProcAddress(ctx.ntdll, symbol_name) }; + unsafe { *self.target = symbol_in_ntdll.cast() }; + } } } if unsafe { *self.target }.is_null() { diff --git a/crates/fspy_preload_windows/src/windows/detours/nt.rs b/crates/fspy_preload_windows/src/windows/detours/nt.rs index 344837f6..cbefa0fd 100644 --- a/crates/fspy_preload_windows/src/windows/detours/nt.rs +++ b/crates/fspy_preload_windows/src/windows/detours/nt.rs @@ -286,6 +286,55 @@ static DETOUR_NT_QUERY_DIRECTORY_FILE: Detour< }) }; +// NtQueryDirectoryFileEx is not in ntapi crate, so we define it here. +// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntquerydirectoryfileex +type NtQueryDirectoryFileExFn = unsafe extern "system" fn( + file_handle: HANDLE, + event: HANDLE, + apc_routine: PIO_APC_ROUTINE, + apc_context: PVOID, + io_status_block: PIO_STATUS_BLOCK, + file_information: PVOID, + length: ULONG, + file_information_class: FILE_INFORMATION_CLASS, + query_flags: ULONG, + file_name: PUNICODE_STRING, +) -> NTSTATUS; + +static DETOUR_NT_QUERY_DIRECTORY_FILE_EX: Detour = unsafe { + Detour::dynamic(c"NtQueryDirectoryFileEx", { + unsafe extern "system" fn new_fn( + file_handle: HANDLE, + event: HANDLE, + apc_routine: PIO_APC_ROUTINE, + apc_context: PVOID, + io_status_block: PIO_STATUS_BLOCK, + file_information: PVOID, + length: ULONG, + file_information_class: FILE_INFORMATION_CLASS, + query_flags: ULONG, + file_name: PUNICODE_STRING, + ) -> NTSTATUS { + unsafe { handle_open(AccessMode::READ_DIR, file_handle) }; + unsafe { + (DETOUR_NT_QUERY_DIRECTORY_FILE_EX.real())( + file_handle, + event, + apc_routine, + apc_context, + io_status_block, + file_information, + length, + file_information_class, + query_flags, + file_name, + ) + } + } + new_fn + }) +}; + pub const DETOURS: &[DetourAny] = &[ DETOUR_NT_CREATE_FILE.as_any(), DETOUR_NT_OPEN_FILE.as_any(), @@ -294,4 +343,5 @@ pub const DETOURS: &[DetourAny] = &[ DETOUR_NT_OPEN_SYMBOLIC_LINK_OBJECT.as_any(), DETOUR_NT_QUERY_INFORMATION_BY_NAME.as_any(), DETOUR_NT_QUERY_DIRECTORY_FILE.as_any(), + DETOUR_NT_QUERY_DIRECTORY_FILE_EX.as_any(), ]; diff --git a/crates/fspy_preload_windows/src/windows/winapi_utils.rs b/crates/fspy_preload_windows/src/windows/winapi_utils.rs index 4f01c9a2..afd0ba06 100644 --- a/crates/fspy_preload_windows/src/windows/winapi_utils.rs +++ b/crates/fspy_preload_windows/src/windows/winapi_utils.rs @@ -29,8 +29,16 @@ pub fn ck_long(val: c_long) -> winsafe::SysResult<()> { } pub unsafe fn get_u16_str(ustring: &UNICODE_STRING) -> &U16Str { - let chars = - unsafe { slice::from_raw_parts((*ustring).Buffer, (*ustring).Length.try_into().unwrap()) }; + // https://learn.microsoft.com/en-us/windows/win32/api/subauth/ns-subauth-unicode_string + // UNICODE_STRING.Length is in bytes + let u16_count = ustring.Length / 2; + let chars: &[u16] = if u16_count == 0 { + // If length is zero, we can't use slice::from_raw_parts as it requires a non-null pointer but + // Buffer may be null in that case. + &[] + } else { + unsafe { slice::from_raw_parts((*ustring).Buffer, u16_count.try_into().unwrap()) } + }; match U16CStr::from_slice_truncate(chars) { Ok(ok) => ok.as_ustr(), Err(_) => chars.into(), diff --git a/crates/fspy_shared/src/ipc/mod.rs b/crates/fspy_shared/src/ipc/mod.rs index 2b348caf..14d9bab7 100644 --- a/crates/fspy_shared/src/ipc/mod.rs +++ b/crates/fspy_shared/src/ipc/mod.rs @@ -32,7 +32,7 @@ impl Debug for AccessMode { } } -#[derive(Encode, BorrowDecode, Debug, Clone, Copy)] +#[derive(Encode, BorrowDecode, Debug, Clone, Copy, PartialEq, Eq)] pub struct PathAccess<'a> { pub mode: AccessMode, pub path: &'a NativeStr, diff --git a/crates/vite_task_bin/test_bins/package.json b/crates/vite_task_bin/test_bins/package.json index e759a6e4..99651da9 100644 --- a/crates/vite_task_bin/test_bins/package.json +++ b/crates/vite_task_bin/test_bins/package.json @@ -12,6 +12,7 @@ "@yarnpkg/shell": "catalog:", "cross-env": "^10.1.0", "oxlint": "catalog:", + "oxlint-tsgolint": "catalog:", "vite-task-test-bins": "link:" } } diff --git a/crates/vite_task_bin/tests/test_snapshots/main.rs b/crates/vite_task_bin/tests/test_snapshots/main.rs index d84baf75..755c5b79 100644 --- a/crates/vite_task_bin/tests/test_snapshots/main.rs +++ b/crates/vite_task_bin/tests/test_snapshots/main.rs @@ -13,7 +13,7 @@ use std::{ use copy_dir::copy_dir; use redact::{redact_e2e_output, redact_snapshot}; use tokio::runtime::Runtime; -use vite_path::{AbsolutePath, RelativePathBuf}; +use vite_path::{AbsolutePath, AbsolutePathBuf, RelativePathBuf}; use vite_str::Str; use vite_task::{CLIArgs, Session}; use vite_task_bin::CustomTaskSubcommand; @@ -209,13 +209,13 @@ fn run_case(runtime: &Runtime, tmpdir: &AbsolutePath, fixture_path: &Path) { fn test_snapshots() { let tokio_runtime = Runtime::new().unwrap(); let tmp_dir = tempfile::tempdir().unwrap(); - let tmp_dir_path = AbsolutePath::new(tmp_dir.path()).unwrap(); + let tmp_dir_path = AbsolutePathBuf::new(tmp_dir.path().canonicalize().unwrap()).unwrap(); let tests_dir = std::env::current_dir().unwrap().join("tests"); insta::glob!(tests_dir, "test_snapshots/fixtures/*", |case_path| run_case( &tokio_runtime, - tmp_dir_path, + &tmp_dir_path, case_path )); } diff --git a/crates/vite_task_bin/tests/test_snapshots/redact.rs b/crates/vite_task_bin/tests/test_snapshots/redact.rs index ce6fede1..3bcd50a4 100644 --- a/crates/vite_task_bin/tests/test_snapshots/redact.rs +++ b/crates/vite_task_bin/tests/test_snapshots/redact.rs @@ -54,6 +54,7 @@ fn redact_string(s: &mut String, redactions: &[(&str, &str)]) { pub fn redact_e2e_output(mut output: String, workspace_root: &str) -> String { let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); + redact_string( &mut output, &[(workspace_root, ""), (manifest_dir.as_str(), "")], @@ -61,7 +62,7 @@ pub fn redact_e2e_output(mut output: String, workspace_root: &str) -> String { // Redact durations like "123ms" or "1.23s" to "ms" or "s" let duration_regex = regex::Regex::new(r"\d+(\.\d+)?(ms|s)").unwrap(); - output = duration_regex.replace_all(&output, "$2").into_owned(); + output = duration_regex.replace_all(&output, "").into_owned(); // Redact thread counts like "using 10 threads" to "using threads" let thread_regex = regex::Regex::new(r"using \d+ threads").unwrap(); diff --git a/crates/vite_task_bin/tests/test_snapshots/snapshots/test_snapshots__direct lint@cache-keys.snap b/crates/vite_task_bin/tests/test_snapshots/snapshots/test_snapshots__direct lint@cache-keys.snap index 7f735149..78c6bac0 100644 --- a/crates/vite_task_bin/tests/test_snapshots/snapshots/test_snapshots__direct lint@cache-keys.snap +++ b/crates/vite_task_bin/tests/test_snapshots/snapshots/test_snapshots__direct lint@cache-keys.snap @@ -5,7 +5,7 @@ input_file: crates/vite_task_bin/tests/test_snapshots/fixtures/cache-keys --- > vite lint Found 0 warnings and 0 errors. -Finished in ms on 0 files with 90 rules using threads. +Finished in on 0 files with 90 rules using threads. > echo debugger > main.js @@ -21,4 +21,4 @@ Finished in ms on 0 files with 90 rules using threads. help: Remove the debugger statement Found 1 warning and 0 errors. -Finished in ms on 1 file with 90 rules using threads. +Finished in on 1 file with 90 rules using threads. diff --git a/crates/vite_task_bin/tests/test_snapshots/snapshots/test_snapshots__multiple task failures returns exit code 1@exit-codes.snap b/crates/vite_task_bin/tests/test_snapshots/snapshots/test_snapshots__multiple task failures returns exit code 1@exit-codes.snap index 82a7a694..8f95da73 100644 --- a/crates/vite_task_bin/tests/test_snapshots/snapshots/test_snapshots__multiple task failures returns exit code 1@exit-codes.snap +++ b/crates/vite_task_bin/tests/test_snapshots/snapshots/test_snapshots__multiple task failures returns exit code 1@exit-codes.snap @@ -1,6 +1,5 @@ --- source: crates/vite_task_bin/tests/test_snapshots/main.rs -assertion_line: 203 expression: e2e_outputs input_file: crates/vite_task_bin/tests/test_snapshots/fixtures/exit-codes --- diff --git a/crates/vite_task_bin/tests/test_snapshots/snapshots/test_snapshots__single task failure returns task exit code@exit-codes.snap b/crates/vite_task_bin/tests/test_snapshots/snapshots/test_snapshots__single task failure returns task exit code@exit-codes.snap index 4a88c347..a068a2c7 100644 --- a/crates/vite_task_bin/tests/test_snapshots/snapshots/test_snapshots__single task failure returns task exit code@exit-codes.snap +++ b/crates/vite_task_bin/tests/test_snapshots/snapshots/test_snapshots__single task failure returns task exit code@exit-codes.snap @@ -1,6 +1,5 @@ --- source: crates/vite_task_bin/tests/test_snapshots/main.rs -assertion_line: 203 expression: e2e_outputs input_file: crates/vite_task_bin/tests/test_snapshots/fixtures/exit-codes --- diff --git a/crates/vite_task_bin/tests/test_snapshots/snapshots/test_snapshots__task with cache enabled@cache-disabled.snap b/crates/vite_task_bin/tests/test_snapshots/snapshots/test_snapshots__task with cache enabled@cache-disabled.snap index 11901124..a89dfa2a 100644 --- a/crates/vite_task_bin/tests/test_snapshots/snapshots/test_snapshots__task with cache enabled@cache-disabled.snap +++ b/crates/vite_task_bin/tests/test_snapshots/snapshots/test_snapshots__task with cache enabled@cache-disabled.snap @@ -31,10 +31,10 @@ test content ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Statistics: 1 tasks • 1 cache hits • 0 cache misses -Performance: 100% cache hit rate, ms saved in total +Performance: 100% cache hit rate, saved in total Task Details: ──────────────────────────────────────────────── [1] cache-disabled-test#cached-task: $ print-file test.txt ✓ - → Cache hit - output replayed - ms saved + → Cache hit - output replayed - saved ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6911583b..fd6305a3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,13 +17,13 @@ catalogs: version: 9.1.7 lint-staged: specifier: ^16.2.6 - version: 16.2.6 + version: 16.2.7 oxlint: specifier: ^1.34.0 - version: 1.34.0 + version: 1.38.0 oxlint-tsgolint: specifier: ^0.10.0 - version: 0.10.0 + version: 0.10.1 importers: @@ -37,13 +37,13 @@ importers: version: 9.1.7 lint-staged: specifier: 'catalog:' - version: 16.2.6 + version: 16.2.7 oxlint: specifier: 'catalog:' - version: 1.34.0(oxlint-tsgolint@0.10.0) + version: 1.38.0(oxlint-tsgolint@0.10.1) oxlint-tsgolint: specifier: 'catalog:' - version: 0.10.0 + version: 0.10.1 crates/vite_task_bin/test_bins: dependencies: @@ -55,7 +55,10 @@ importers: version: 10.1.0 oxlint: specifier: 'catalog:' - version: 1.34.0(oxlint-tsgolint@0.10.0) + version: 1.38.0(oxlint-tsgolint@0.10.1) + oxlint-tsgolint: + specifier: 'catalog:' + version: 0.10.1 vite-task-test-bins: specifier: 'link:' version: 'link:' @@ -77,77 +80,77 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@oxlint-tsgolint/darwin-arm64@0.10.0': - resolution: {integrity: sha512-mhBF/pjey0UdLL1ocU46Fqta+uJuRfqrLfDpcViRg17BtDiUNd8JY9iN2FOoS2HGSCAgCUjZ0AZkwkHwFs/VTw==} + '@oxlint-tsgolint/darwin-arm64@0.10.1': + resolution: {integrity: sha512-KGC4++BeEqrIcmDHiJt/e6/860PWJmUJjjp0mE+smpBmRXMjmOFFjrPmN+ZyCyVgf1WdmhPkQXsRSPeTR+2omw==} cpu: [arm64] os: [darwin] - '@oxlint-tsgolint/darwin-x64@0.10.0': - resolution: {integrity: sha512-roLi34mw/i1z+NS7luboix55SXyhVv38dNUTcRDkk+0lNPzI9ngrM+1y1N2oBSUmz5o9OZGnfJJ7BSGCw/fFEQ==} + '@oxlint-tsgolint/darwin-x64@0.10.1': + resolution: {integrity: sha512-tvmrDgj3Q0tdc+zMWfCVLVq8EQDEUqasm1zaWgSMYIszpID6qdgqbT+OpWWXV9fLZgtvrkoXGwxkHAUJzdVZXQ==} cpu: [x64] os: [darwin] - '@oxlint-tsgolint/linux-arm64@0.10.0': - resolution: {integrity: sha512-HL9NThPH1V2F6l9XhwNmhQZUknN4m4yQYEvQFFGfZTYN6cvEEBIiqfF4KvBUg8c0xadMbQlW+Ug7/ybA9Nn+CA==} + '@oxlint-tsgolint/linux-arm64@0.10.1': + resolution: {integrity: sha512-7kD28z6/ykGx8WetKTPRZt30pd+ziassxg/8cM24lhjUI+hNXyRHVtHes73dh9D6glJKno+1ut+3amUdZBZcpQ==} cpu: [arm64] os: [linux] - '@oxlint-tsgolint/linux-x64@0.10.0': - resolution: {integrity: sha512-Tw8QNq8ab+4+qE5krvJyMA66v6XE3GoiISRD5WmJ7YOxUnu//jSw/bBm7OYf/TNEZyeV0BTR7zXzhT5R+VFWlQ==} + '@oxlint-tsgolint/linux-x64@0.10.1': + resolution: {integrity: sha512-NmJmiqdzYUTHIxteSTyX6IFFgnIsOAjRWXfrS6Jbo5xlB3g39WHniSF3asB/khLJNtwSg4InUS34NprYM7zrEw==} cpu: [x64] os: [linux] - '@oxlint-tsgolint/win32-arm64@0.10.0': - resolution: {integrity: sha512-LTogmTRwpwQqVaH1Ama8Wd5/VVZWBSF8v5qTbeT628+1F5Kt1V5eHBvyFh4oN18UCZlgqrh7DqkDhsieXUaC8Q==} + '@oxlint-tsgolint/win32-arm64@0.10.1': + resolution: {integrity: sha512-3KrT80vl3nXUkjuJI/z8dF6xWsKx0t9Tz4ZQHgQw3fYw+CoihBRWGklrdlmCz+EGfMyVaQLqBV9PZckhSqLe2A==} cpu: [arm64] os: [win32] - '@oxlint-tsgolint/win32-x64@0.10.0': - resolution: {integrity: sha512-ygqxx8EmNWy9/wCQS5uXq9k/o2EyYNwNxY1ZHNzlmZC/kV06Aemx5OBDafefawBNqH7xTZPfccUrjdiy+QlTrw==} + '@oxlint-tsgolint/win32-x64@0.10.1': + resolution: {integrity: sha512-hW1fSJZVxG51sLdGq1sQjOzb1tsQ23z/BquJfUwL7CqBobxr7TJvGmoINL+9KryOJt0jCoaiMfWe4yoYw5XfIA==} cpu: [x64] os: [win32] - '@oxlint/darwin-arm64@1.34.0': - resolution: {integrity: sha512-euz3Dtp5/UE9axFkQnllOWp3gOwoqaxfZPUUwiW8HBelqhI9PRMVIfQ/akmwl+G5XixQZIgXkXQ5SJxnb1+Qww==} + '@oxlint/darwin-arm64@1.38.0': + resolution: {integrity: sha512-9rN3047QTyA4i73FKikDUBdczRcLtOsIwZ5TsEx5Q7jr5nBjolhYQOFQf9QdhBLdInxw1iX4+lgdMCf1g74zjg==} cpu: [arm64] os: [darwin] - '@oxlint/darwin-x64@1.34.0': - resolution: {integrity: sha512-XpmNviE5KOnHkhmQPwJJIBs+mJkr0qItTZBN4dz+O3p9gWN+gCqi3CBP71RiVahZw4qAEQSgY4wro+z0kx+erg==} + '@oxlint/darwin-x64@1.38.0': + resolution: {integrity: sha512-Y1UHW4KOlg5NvyrSn/bVBQP8/LRuid7Pnu+BWGbAVVsFcK0b565YgMSO3Eu9nU3w8ke91dr7NFpUmS+bVkdkbw==} cpu: [x64] os: [darwin] - '@oxlint/linux-arm64-gnu@1.34.0': - resolution: {integrity: sha512-aCPdoEUGsJGF9y88vDYoaugG4IEGwSBa+usyuAvEVl3vTfuTmE0RDQEC1Z+WnJ3J/cIEpbgKOzS12VwbzFicjg==} + '@oxlint/linux-arm64-gnu@1.38.0': + resolution: {integrity: sha512-ZiVxPZizlXSnAMdkEFWX/mAj7U3bNiku8p6I9UgLrXzgGSSAhFobx8CaFGwVoKyWOd+gQgZ/ogCrunvx2k0CFg==} cpu: [arm64] os: [linux] libc: [glibc] - '@oxlint/linux-arm64-musl@1.34.0': - resolution: {integrity: sha512-cMo72LQBFmdnVLRKLAHD94ZUBq5Z+aA9Y+RKzkjhCmJuef5ZAfKC24TJD/6c5LxGYzkwwmyySoQAHq5B69i3PQ==} + '@oxlint/linux-arm64-musl@1.38.0': + resolution: {integrity: sha512-ELtlCIGZ72A65ATZZHFxHMFrkRtY+DYDCKiNKg6v7u5PdeOFey+OlqRXgXtXlxWjCL+g7nivwI2FPVsWqf05Qw==} cpu: [arm64] os: [linux] libc: [musl] - '@oxlint/linux-x64-gnu@1.34.0': - resolution: {integrity: sha512-+9xFhhkqgNIysEh+uHvcba8v4UtL1YzxuyDS2wTLdWrkGvIllCx5WjJItt3K/AhwatciksgNEXSo2Hh4fcQRog==} + '@oxlint/linux-x64-gnu@1.38.0': + resolution: {integrity: sha512-E1OcDh30qyng1m0EIlsOuapYkqk5QB6o6IMBjvDKqIoo6IrjlVAasoJfS/CmSH998gXRL3BcAJa6Qg9IxPFZnQ==} cpu: [x64] os: [linux] libc: [glibc] - '@oxlint/linux-x64-musl@1.34.0': - resolution: {integrity: sha512-qa7TL2DfEDdMeSP5UiU5JMs6D2PW7ZJAQ0WZYTgqDV8BlZ6nMkIYVBVIk3QPxIfkyxvfJVbG1RB3PkSWDcfwpA==} + '@oxlint/linux-x64-musl@1.38.0': + resolution: {integrity: sha512-4AfpbM/4sQnr6S1dMijEPfsq4stQbN5vJ2jsahSy/QTcvIVbFkgY+RIhrA5UWlC6eb0rD5CdaPQoKGMJGeXpYw==} cpu: [x64] os: [linux] libc: [musl] - '@oxlint/win32-arm64@1.34.0': - resolution: {integrity: sha512-mSJumUveg1S3DiOgvsrVNAGuvenBbbC/zsfT1qhltT+GLhJ7RPBK2I/jz0fTdE+I7M9/as8yc0XJ/eY23y2amA==} + '@oxlint/win32-arm64@1.38.0': + resolution: {integrity: sha512-OvUVYdI68OwXh3d1RjH9N/okCxb6PrOGtEtzXyqGA7Gk+IxyZcX0/QCTBwV8FNbSSzDePSSEHOKpoIB+VXdtvg==} cpu: [arm64] os: [win32] - '@oxlint/win32-x64@1.34.0': - resolution: {integrity: sha512-izsDDt5WY4FSISCkPRLUYQD1aRaaEJkPLtEZe3DlioSUdUVAdvVbE+BGllFqR16DWfTTwO/6K4jDeooxQzTMjw==} + '@oxlint/win32-x64@1.38.0': + resolution: {integrity: sha512-7IuZMYiZiOcgg5zHvpJY6jRlEwh8EB/uq7GsoQJO9hANq96TIjyntGByhIjFSsL4asyZmhTEki+MO/u5Fb/WQA==} cpu: [x64] os: [win32] @@ -167,8 +170,8 @@ packages: engines: {node: '>=18.12.0'} hasBin: true - ansi-escapes@7.1.1: - resolution: {integrity: sha512-Zhl0ErHcSRUaVfGUeUdDuLgpkEo8KIFjB4Y9uAc46ScOpdDiU1Dbyplh7qWJeJ/ZHpbyMSM26+X3BySgnIz40Q==} + ansi-escapes@7.2.0: + resolution: {integrity: sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==} engines: {node: '>=18'} ansi-regex@6.2.2: @@ -296,8 +299,8 @@ packages: resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} hasBin: true - lint-staged@16.2.6: - resolution: {integrity: sha512-s1gphtDbV4bmW1eylXpVMk2u7is7YsrLl8hzrtvC70h4ByhcMLZFY01Fx05ZUDNuv1H8HO4E+e2zgejV1jVwNw==} + lint-staged@16.2.7: + resolution: {integrity: sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==} engines: {node: '>=20.17'} hasBin: true @@ -329,16 +332,16 @@ packages: resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} engines: {node: '>=18'} - oxlint-tsgolint@0.10.0: - resolution: {integrity: sha512-LDDSIu5J/4D4gFUuQQIEQpAC6maNEbMg4nC8JL/+Pe0cUDR86dtVZ09E2x5MwCh8f9yfktoaxt5x6UIVyzrajg==} + oxlint-tsgolint@0.10.1: + resolution: {integrity: sha512-EEHNdo5cW2w1xwYdBQ7d3IXDqWAtMkfVFrh+9gQ4kYbYJwygY4QXSh1eH80/xVipZdVKujAwBgg/nNNHk56kxQ==} hasBin: true - oxlint@1.34.0: - resolution: {integrity: sha512-Ni0N8wAiKlgaYkI/Yz4VrutfVIZgd2shDtS+loQxyBTwO8YUAnk3+g7OQ1cyI/aatHiFwvFNfV/uvZyHUtyPpA==} + oxlint@1.38.0: + resolution: {integrity: sha512-XT7tBinQS+hVLxtfJOnokJ9qVBiQvZqng40tDgR6qEJMRMnpVq/JwYfbYyGntSq8MO+Y+N9M1NG4bAMFUtCJiw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: - oxlint-tsgolint: '>=0.9.2' + oxlint-tsgolint: '>=0.10.0' peerDependenciesMeta: oxlint-tsgolint: optional: true @@ -434,8 +437,8 @@ packages: resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} engines: {node: '>=18'} - yaml@2.8.1: - resolution: {integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==} + yaml@2.8.2: + resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} engines: {node: '>= 14.6'} hasBin: true @@ -455,46 +458,46 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 - '@oxlint-tsgolint/darwin-arm64@0.10.0': + '@oxlint-tsgolint/darwin-arm64@0.10.1': optional: true - '@oxlint-tsgolint/darwin-x64@0.10.0': + '@oxlint-tsgolint/darwin-x64@0.10.1': optional: true - '@oxlint-tsgolint/linux-arm64@0.10.0': + '@oxlint-tsgolint/linux-arm64@0.10.1': optional: true - '@oxlint-tsgolint/linux-x64@0.10.0': + '@oxlint-tsgolint/linux-x64@0.10.1': optional: true - '@oxlint-tsgolint/win32-arm64@0.10.0': + '@oxlint-tsgolint/win32-arm64@0.10.1': optional: true - '@oxlint-tsgolint/win32-x64@0.10.0': + '@oxlint-tsgolint/win32-x64@0.10.1': optional: true - '@oxlint/darwin-arm64@1.34.0': + '@oxlint/darwin-arm64@1.38.0': optional: true - '@oxlint/darwin-x64@1.34.0': + '@oxlint/darwin-x64@1.38.0': optional: true - '@oxlint/linux-arm64-gnu@1.34.0': + '@oxlint/linux-arm64-gnu@1.38.0': optional: true - '@oxlint/linux-arm64-musl@1.34.0': + '@oxlint/linux-arm64-musl@1.38.0': optional: true - '@oxlint/linux-x64-gnu@1.34.0': + '@oxlint/linux-x64-gnu@1.38.0': optional: true - '@oxlint/linux-x64-musl@1.34.0': + '@oxlint/linux-x64-musl@1.38.0': optional: true - '@oxlint/win32-arm64@1.34.0': + '@oxlint/win32-arm64@1.38.0': optional: true - '@oxlint/win32-x64@1.34.0': + '@oxlint/win32-x64@1.38.0': optional: true '@types/node@25.0.3': @@ -523,7 +526,7 @@ snapshots: transitivePeerDependencies: - typanion - ansi-escapes@7.1.1: + ansi-escapes@7.2.0: dependencies: environment: 1.1.0 @@ -635,7 +638,7 @@ snapshots: argparse: 1.0.10 esprima: 4.0.1 - lint-staged@16.2.6: + lint-staged@16.2.7: dependencies: commander: 14.0.2 listr2: 9.0.5 @@ -643,7 +646,7 @@ snapshots: nano-spawn: 2.0.0 pidtree: 0.6.0 string-argv: 0.3.2 - yaml: 2.8.1 + yaml: 2.8.2 listr2@9.0.5: dependencies: @@ -656,7 +659,7 @@ snapshots: log-update@6.1.0: dependencies: - ansi-escapes: 7.1.1 + ansi-escapes: 7.2.0 cli-cursor: 5.0.0 slice-ansi: 7.1.2 strip-ansi: 7.1.2 @@ -677,26 +680,26 @@ snapshots: dependencies: mimic-function: 5.0.1 - oxlint-tsgolint@0.10.0: + oxlint-tsgolint@0.10.1: optionalDependencies: - '@oxlint-tsgolint/darwin-arm64': 0.10.0 - '@oxlint-tsgolint/darwin-x64': 0.10.0 - '@oxlint-tsgolint/linux-arm64': 0.10.0 - '@oxlint-tsgolint/linux-x64': 0.10.0 - '@oxlint-tsgolint/win32-arm64': 0.10.0 - '@oxlint-tsgolint/win32-x64': 0.10.0 - - oxlint@1.34.0(oxlint-tsgolint@0.10.0): + '@oxlint-tsgolint/darwin-arm64': 0.10.1 + '@oxlint-tsgolint/darwin-x64': 0.10.1 + '@oxlint-tsgolint/linux-arm64': 0.10.1 + '@oxlint-tsgolint/linux-x64': 0.10.1 + '@oxlint-tsgolint/win32-arm64': 0.10.1 + '@oxlint-tsgolint/win32-x64': 0.10.1 + + oxlint@1.38.0(oxlint-tsgolint@0.10.1): optionalDependencies: - '@oxlint/darwin-arm64': 1.34.0 - '@oxlint/darwin-x64': 1.34.0 - '@oxlint/linux-arm64-gnu': 1.34.0 - '@oxlint/linux-arm64-musl': 1.34.0 - '@oxlint/linux-x64-gnu': 1.34.0 - '@oxlint/linux-x64-musl': 1.34.0 - '@oxlint/win32-arm64': 1.34.0 - '@oxlint/win32-x64': 1.34.0 - oxlint-tsgolint: 0.10.0 + '@oxlint/darwin-arm64': 1.38.0 + '@oxlint/darwin-x64': 1.38.0 + '@oxlint/linux-arm64-gnu': 1.38.0 + '@oxlint/linux-arm64-musl': 1.38.0 + '@oxlint/linux-x64-gnu': 1.38.0 + '@oxlint/linux-x64-musl': 1.38.0 + '@oxlint/win32-arm64': 1.38.0 + '@oxlint/win32-x64': 1.38.0 + oxlint-tsgolint: 0.10.1 path-key@3.1.1: {} @@ -775,4 +778,4 @@ snapshots: string-width: 7.2.0 strip-ansi: 7.1.2 - yaml@2.8.1: {} + yaml@2.8.2: {}