From dea60eb4cf4ccbc948cb04dc8ada589e818d6041 Mon Sep 17 00:00:00 2001 From: Joe Date: Tue, 17 Feb 2026 19:07:50 -0600 Subject: [PATCH] Add formatting and static analysis scripts with usage instructions - Introduced new scripts for auto-fixing formatting and performing static analysis across the project, including support for Lua, Rust, and TypeScript. - Created `format.md` documentation to guide users on running the formatting scripts. - Updated CI scripts to utilize the number of processor threads for improved performance during linting and testing. - Enhanced logging in the `unwatch` function to provide clearer feedback on path watching status. These changes streamline the formatting and analysis process, ensuring consistent code quality across the project. --- .cursor/commands/format.md | 23 ++++++ crates/memofs/src/std_backend.rs | 17 +++-- scripts/ci.ps1 | 21 +++--- scripts/ci.sh | 22 +++--- scripts/format.ps1 | 126 +++++++++++++++++++++++++++++++ scripts/format.sh | 126 +++++++++++++++++++++++++++++++ 6 files changed, 309 insertions(+), 26 deletions(-) create mode 100644 .cursor/commands/format.md create mode 100644 scripts/format.ps1 create mode 100644 scripts/format.sh diff --git a/.cursor/commands/format.md b/.cursor/commands/format.md new file mode 100644 index 00000000..50fecabc --- /dev/null +++ b/.cursor/commands/format.md @@ -0,0 +1,23 @@ +# /format - Auto-fix Formatting & Static Analysis + +Run formatting and static analysis (linting) across the entire project. + +## Instructions + +### 1. Run the Format Script + +**Windows (PowerShell):** +```powershell +.\scripts\format.ps1 +``` + +**macOS/Linux (Bash):** +```bash +bash scripts/format.sh +``` + +**Monitor the script output as it runs.** If a step fails, investigate the failure and fix it manually before re-running. + +### 2. Report + +Once formatting passes clean, provide a brief summary and confirm the final result. diff --git a/crates/memofs/src/std_backend.rs b/crates/memofs/src/std_backend.rs index ac97383d..0a17df4f 100644 --- a/crates/memofs/src/std_backend.rs +++ b/crates/memofs/src/std_backend.rs @@ -352,22 +352,27 @@ impl VfsBackend for StdBackend { } fn unwatch(&mut self, path: &Path) -> io::Result<()> { - // Only remove from watches if unwatch succeeds - // This keeps state consistent if unwatch fails (e.g., path wasn't directly watched) + let was_watched = self.watches.contains(path); + match self.debouncer.unwatch(path) { Ok(()) => { - log::info!("Unwatched path: {}", path.display()); + if was_watched { + log::info!("Unwatched path: {}", path.display()); + } else { + log::trace!( + "Unwatched path (was not actively watched): {}", + path.display() + ); + } self.watches.remove(path); Ok(()) } Err(err) => { - // If the path wasn't being watched (common when parent dir is watched), - // still remove from our tracking set but don't propagate the error if matches!( err.kind, notify::ErrorKind::WatchNotFound | notify::ErrorKind::PathNotFound ) { - log::info!( + log::trace!( "Path was not directly watched (likely covered by parent): {}", path.display() ); diff --git a/scripts/ci.ps1 b/scripts/ci.ps1 index 5ce4f315..32bf74fd 100644 --- a/scripts/ci.ps1 +++ b/scripts/ci.ps1 @@ -6,6 +6,7 @@ param( ) $RbxDom = -not $NoRbxDom +$Threads = [Environment]::ProcessorCount $ErrorActionPreference = "Continue" $failures = @() @@ -56,19 +57,19 @@ $selene = $LASTEXITCODE Record-Result "Selene" $selene Write-Step 6 "Rust Linting (Clippy) - Auto-fix" -cargo clippy -j 16 --fix --allow-dirty --allow-staged 2>&1 | Out-Null +cargo clippy -j $Threads --fix --allow-dirty --allow-staged 2>&1 | Out-Null Write-Host "Verifying..." -ForegroundColor Yellow -cargo clippy -j 16 --all-targets --all-features 2>&1 +cargo clippy -j $Threads --all-targets --all-features 2>&1 $clippy = $LASTEXITCODE Record-Result "Clippy" $clippy Write-Step 7 "Build Everything" -cargo build -j 16 --locked --all-targets --all-features +cargo build --locked --all-targets --all-features $build = $LASTEXITCODE Record-Result "Build" $build Write-Step 8 "Run ALL Rust Tests" -$testOutput = cargo test -j 16 --locked --all-features -- --test-threads=16 2>&1 +$testOutput = cargo test --locked --all-features -- --test-threads=$Threads 2>&1 $rustTests = $LASTEXITCODE $testOutput | Write-Host Record-Result "Rust Tests" $rustTests @@ -106,18 +107,18 @@ if ($RbxDom) { Write-Step 13 "Rust Linting (Clippy) for rbx-dom - Auto-fix" Push-Location rbx-dom - cargo clippy -j 16 --fix --allow-dirty --allow-staged 2>&1 | Out-Null + cargo clippy -j $Threads --fix --allow-dirty --allow-staged 2>&1 | Out-Null Write-Host "Verifying..." -ForegroundColor Yellow - cargo clippy -j 16 --all-targets --all-features -- -D warnings 2>&1 + cargo clippy -j $Threads --all-targets --all-features -- -D warnings 2>&1 $clippyRbxDom = $LASTEXITCODE Pop-Location Record-Result "Clippy (rbx-dom)" $clippyRbxDom Write-Step 14 "Build rbx-dom" Push-Location rbx-dom - cargo build -j 16 --verbose + cargo build --verbose $buildRbxDom = $LASTEXITCODE - cargo build -j 16 --all-features --verbose + cargo build --all-features --verbose $buildRbxDomAll = $LASTEXITCODE Pop-Location Record-Result "Build (rbx-dom)" $buildRbxDom @@ -125,9 +126,9 @@ if ($RbxDom) { Write-Step 15 "Run ALL rbx-dom Rust Tests" Push-Location rbx-dom - cargo test -j 16 --verbose -- --test-threads=16 + cargo test --verbose -- --test-threads=$Threads $testsRbxDom = $LASTEXITCODE - cargo test -j 16 --all-features --verbose -- --test-threads=16 + cargo test --all-features --verbose -- --test-threads=$Threads $testsRbxDomAll = $LASTEXITCODE Pop-Location Record-Result "Tests (rbx-dom)" $testsRbxDom diff --git a/scripts/ci.sh b/scripts/ci.sh index 3dc32ded..a3673ea3 100755 --- a/scripts/ci.sh +++ b/scripts/ci.sh @@ -11,6 +11,8 @@ for arg in "$@"; do esac done +THREADS=$(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || echo 4) + failures=() step() { @@ -55,19 +57,19 @@ selene_exit=$? record "Selene" $selene_exit step 6 "Rust Linting (Clippy) - Auto-fix" -cargo clippy -j 16 --fix --allow-dirty --allow-staged >/dev/null 2>&1 +cargo clippy -j $THREADS --fix --allow-dirty --allow-staged >/dev/null 2>&1 echo "Verifying..." -cargo clippy -j 16 --all-targets --all-features 2>&1 +cargo clippy -j $THREADS --all-targets --all-features 2>&1 clippy_exit=$? record "Clippy" $clippy_exit step 7 "Build Everything" -cargo build -j 16 --locked --all-targets --all-features +cargo build --locked --all-targets --all-features build_exit=$? record "Build" $build_exit step 8 "Run ALL Rust Tests" -cargo test -j 16 --locked --all-features -- --test-threads=16 2>&1 +cargo test --locked --all-features -- --test-threads=$THREADS 2>&1 rust_tests=$? record "Rust Tests" $rust_tests @@ -101,24 +103,24 @@ if [ "$RBX_DOM" = true ]; then record "Selene (rbx_dom_lua)" $selene_rbxdom step 13 "Rust Linting (Clippy) for rbx-dom - Auto-fix" - (cd rbx-dom && cargo clippy -j 16 --fix --allow-dirty --allow-staged >/dev/null 2>&1) + (cd rbx-dom && cargo clippy -j $THREADS --fix --allow-dirty --allow-staged >/dev/null 2>&1) echo "Verifying..." - (cd rbx-dom && cargo clippy -j 16 --all-targets --all-features -- -D warnings 2>&1) + (cd rbx-dom && cargo clippy -j $THREADS --all-targets --all-features -- -D warnings 2>&1) clippy_rbxdom=$? record "Clippy (rbx-dom)" $clippy_rbxdom step 14 "Build rbx-dom" - (cd rbx-dom && cargo build -j 16 --verbose) + (cd rbx-dom && cargo build --verbose) build_rbxdom=$? - (cd rbx-dom && cargo build -j 16 --all-features --verbose) + (cd rbx-dom && cargo build --all-features --verbose) build_rbxdom_all=$? record "Build (rbx-dom)" $build_rbxdom record "Build (rbx-dom all-features)" $build_rbxdom_all step 15 "Run ALL rbx-dom Rust Tests" - (cd rbx-dom && cargo test -j 16 --verbose -- --test-threads=16) + (cd rbx-dom && cargo test --verbose -- --test-threads=$THREADS) tests_rbxdom=$? - (cd rbx-dom && cargo test -j 16 --all-features --verbose -- --test-threads=16) + (cd rbx-dom && cargo test --all-features --verbose -- --test-threads=$THREADS) tests_rbxdom_all=$? record "Tests (rbx-dom)" $tests_rbxdom record "Tests (rbx-dom all-features)" $tests_rbxdom_all diff --git a/scripts/format.ps1 b/scripts/format.ps1 new file mode 100644 index 00000000..28f53b17 --- /dev/null +++ b/scripts/format.ps1 @@ -0,0 +1,126 @@ +# Auto-fix Formatting & Static Analysis +# Usage: .\scripts\format.ps1 [-NoRbxDom] + +param( + [switch]$NoRbxDom +) + +$RbxDom = -not $NoRbxDom +$Threads = [Environment]::ProcessorCount + +$ErrorActionPreference = "Continue" +$failures = @() + +function Write-Step($number, $name) { + Write-Host "" + Write-Host "=== Step ${number}: $name ===" -ForegroundColor Cyan +} + +function Record-Result($step, $exitCode) { + if ($exitCode -ne 0) { + $script:failures += $step + Write-Host "FAIL" -ForegroundColor Red + } else { + Write-Host "PASS" -ForegroundColor Green + } +} + +# ─── Rojo ──────────────────────────────────────────────────────────────────── + +Write-Step 1 "Auto-fix Lua Formatting (Stylua)" +stylua plugin/src +$styluaRojo = $LASTEXITCODE +Record-Result "Stylua (Rojo)" $styluaRojo + +Write-Step 2 "Auto-fix Rust Formatting" +cargo fmt +$rustfmt = $LASTEXITCODE +Record-Result "Rustfmt" $rustfmt + +Write-Step 3 "Auto-fix TypeScript Formatting (Prettier)" +Push-Location vscode-rojo +npx prettier --write "src/**/*.ts" +$prettier = $LASTEXITCODE +Pop-Location +Record-Result "Prettier" $prettier + +Write-Step 4 "Lua Static Analysis (Selene)" +selene plugin/src +$selene = $LASTEXITCODE +Record-Result "Selene" $selene + +Write-Step 5 "Rust Linting (Clippy) - Auto-fix" +cargo clippy -j $Threads --fix --allow-dirty --allow-staged 2>&1 | Out-Null +Write-Host "Verifying..." -ForegroundColor Yellow +cargo clippy -j $Threads --all-targets --all-features 2>&1 +$clippy = $LASTEXITCODE +Record-Result "Clippy" $clippy + +# ─── rbx-dom ───────────────────────────────────────────────────────────────── + +if ($RbxDom) { + Write-Step 6 "Auto-fix Lua Formatting (Stylua) for rbx_dom_lua" + stylua rbx-dom/rbx_dom_lua/src + $styluaRbxDom = $LASTEXITCODE + Record-Result "Stylua (rbx_dom_lua)" $styluaRbxDom + + Write-Step 7 "Auto-fix Rust Formatting (rbx-dom)" + Push-Location rbx-dom + cargo fmt + $rustfmtRbxDom = $LASTEXITCODE + Pop-Location + Record-Result "Rustfmt (rbx-dom)" $rustfmtRbxDom + + Write-Step 8 "Lua Static Analysis (Selene) for rbx_dom_lua" + selene rbx-dom/rbx_dom_lua/src + $seleneRbxDom = $LASTEXITCODE + Record-Result "Selene (rbx_dom_lua)" $seleneRbxDom + + Write-Step 9 "Rust Linting (Clippy) for rbx-dom - Auto-fix" + Push-Location rbx-dom + cargo clippy -j $Threads --fix --allow-dirty --allow-staged 2>&1 | Out-Null + Write-Host "Verifying..." -ForegroundColor Yellow + cargo clippy -j $Threads --all-targets --all-features -- -D warnings 2>&1 + $clippyRbxDom = $LASTEXITCODE + Pop-Location + Record-Result "Clippy (rbx-dom)" $clippyRbxDom +} + +# ─── Report ────────────────────────────────────────────────────────────────── + +Write-Host "" +Write-Host "=== FORMAT COMPLETE ===" -ForegroundColor Magenta +Write-Host "" +Write-Host "--- Rojo ---" -ForegroundColor White +Write-Host "" +Write-Host "Formatting:" +Write-Host " - Stylua: $(if ($styluaRojo -eq 0) {'PASS'} else {'FAIL'})" +Write-Host " - Rustfmt: $(if ($rustfmt -eq 0) {'PASS'} else {'FAIL'})" +Write-Host " - Prettier (vscode-rojo): $(if ($prettier -eq 0) {'PASS'} else {'FAIL'})" +Write-Host "" +Write-Host "Linting:" +Write-Host " - Selene: $(if ($selene -eq 0) {'PASS'} else {'FAIL'})" +Write-Host " - Clippy: $(if ($clippy -eq 0) {'PASS'} else {'FAIL'})" + +if ($RbxDom) { + Write-Host "" + Write-Host "--- rbx-dom ---" -ForegroundColor White + Write-Host "" + Write-Host "Formatting:" + Write-Host " - Stylua (rbx_dom_lua): $(if ($styluaRbxDom -eq 0) {'PASS'} else {'FAIL'})" + Write-Host " - Rustfmt: $(if ($rustfmtRbxDom -eq 0) {'PASS'} else {'FAIL'})" + Write-Host "" + Write-Host "Linting:" + Write-Host " - Selene (rbx_dom_lua): $(if ($seleneRbxDom -eq 0) {'PASS'} else {'FAIL'})" + Write-Host " - Clippy: $(if ($clippyRbxDom -eq 0) {'PASS'} else {'FAIL'})" +} + +Write-Host "" +if ($failures.Count -eq 0) { + Write-Host "--- Overall: PASS ---" -ForegroundColor Green + exit 0 +} else { + Write-Host "--- Overall: FAIL ---" -ForegroundColor Red + Write-Host "Failed steps: $($failures -join ', ')" -ForegroundColor Red + exit 1 +} diff --git a/scripts/format.sh b/scripts/format.sh new file mode 100644 index 00000000..38fcceff --- /dev/null +++ b/scripts/format.sh @@ -0,0 +1,126 @@ +#!/usr/bin/env bash +# Auto-fix Formatting & Static Analysis +# Usage: bash scripts/format.sh [--no-rbx-dom] + +set -o pipefail + +RBX_DOM=true +for arg in "$@"; do + case "$arg" in + --no-rbx-dom) RBX_DOM=false ;; + esac +done + +THREADS=$(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || echo 4) + +failures=() + +step() { + echo "" + echo "=== Step $1: $2 ===" +} + +record() { + if [ "$2" -ne 0 ]; then + failures+=("$1") + echo "FAIL" + else + echo "PASS" + fi +} + +# ─── Rojo ──────────────────────────────────────────────────────────────────── + +step 1 "Auto-fix Lua Formatting (Stylua)" +stylua plugin/src +stylua_rojo=$? +record "Stylua (Rojo)" $stylua_rojo + +step 2 "Auto-fix Rust Formatting" +cargo fmt +rustfmt_exit=$? +record "Rustfmt" $rustfmt_exit + +step 3 "Auto-fix TypeScript Formatting (Prettier)" +(cd vscode-rojo && npx prettier --write "src/**/*.ts") +prettier_exit=$? +record "Prettier" $prettier_exit + +step 4 "Lua Static Analysis (Selene)" +selene plugin/src +selene_exit=$? +record "Selene" $selene_exit + +step 5 "Rust Linting (Clippy) - Auto-fix" +cargo clippy -j $THREADS --fix --allow-dirty --allow-staged >/dev/null 2>&1 +echo "Verifying..." +cargo clippy -j $THREADS --all-targets --all-features 2>&1 +clippy_exit=$? +record "Clippy" $clippy_exit + +# ─── rbx-dom ───────────────────────────────────────────────────────────────── + +if [ "$RBX_DOM" = true ]; then + step 6 "Auto-fix Lua Formatting (Stylua) for rbx_dom_lua" + (cd rbx-dom && stylua rbx_dom_lua/src) + stylua_rbxdom=$? + record "Stylua (rbx_dom_lua)" $stylua_rbxdom + + step 7 "Auto-fix Rust Formatting (rbx-dom)" + (cd rbx-dom && cargo fmt) + rustfmt_rbxdom=$? + record "Rustfmt (rbx-dom)" $rustfmt_rbxdom + + step 8 "Lua Static Analysis (Selene) for rbx_dom_lua" + (cd rbx-dom && selene rbx_dom_lua/src) + selene_rbxdom=$? + record "Selene (rbx_dom_lua)" $selene_rbxdom + + step 9 "Rust Linting (Clippy) for rbx-dom - Auto-fix" + (cd rbx-dom && cargo clippy -j $THREADS --fix --allow-dirty --allow-staged >/dev/null 2>&1) + echo "Verifying..." + (cd rbx-dom && cargo clippy -j $THREADS --all-targets --all-features -- -D warnings 2>&1) + clippy_rbxdom=$? + record "Clippy (rbx-dom)" $clippy_rbxdom +fi + +# ─── Report ────────────────────────────────────────────────────────────────── + +pass_or_fail() { [ "$1" -eq 0 ] && echo "PASS" || echo "FAIL"; } + +echo "" +echo "=== FORMAT COMPLETE ===" +echo "" +echo "--- Rojo ---" +echo "" +echo "Formatting:" +echo " - Stylua: $(pass_or_fail $stylua_rojo)" +echo " - Rustfmt: $(pass_or_fail $rustfmt_exit)" +echo " - Prettier (vscode-rojo): $(pass_or_fail $prettier_exit)" +echo "" +echo "Linting:" +echo " - Selene: $(pass_or_fail $selene_exit)" +echo " - Clippy: $(pass_or_fail $clippy_exit)" + +if [ "$RBX_DOM" = true ]; then + echo "" + echo "--- rbx-dom ---" + echo "" + echo "Formatting:" + echo " - Stylua (rbx_dom_lua): $(pass_or_fail $stylua_rbxdom)" + echo " - Rustfmt: $(pass_or_fail $rustfmt_rbxdom)" + echo "" + echo "Linting:" + echo " - Selene (rbx_dom_lua): $(pass_or_fail $selene_rbxdom)" + echo " - Clippy: $(pass_or_fail $clippy_rbxdom)" +fi + +echo "" +if [ ${#failures[@]} -eq 0 ]; then + echo "--- Overall: PASS ---" + exit 0 +else + echo "--- Overall: FAIL ---" + echo "Failed steps: $(IFS=', '; echo "${failures[*]}")" + exit 1 +fi