fix: improve Windows Rust environment setup for build workflows#19960
fix: improve Windows Rust environment setup for build workflows#19960Syroxivoss wants to merge 2 commits into
Conversation
WalkthroughAdds a scripts infrastructure and updates npm scripts to route tasks through it. New files: 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (4)
scripts/rust-env.mjs (1)
31-40: Consider validatingcommandto avoid surprising shell parsing on Windows.With
shell: isWindows,spawnSyncon Windows runs the command throughcmd.exe, so a command name containing spaces or shell metacharacters would be interpreted by the shell. Since all current call sites pass fixed literals (cargo,rustc,rustup,bun), this is not an active issue — just something worth keeping in mind ifcommandExistsever gets used with user-supplied input.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/rust-env.mjs` around lines 31 - 40, The commandExists function currently calls spawnSync(command, ['--version'], { shell: isWindows, ... }), which can allow shell parsing surprises on Windows if command contains spaces or metacharacters; update commandExists to validate or sanitize the command before passing it to spawnSync (e.g., assert it matches a safe token pattern like /^[A-Za-z0-9._-]+$/ or throw/return false for unsafe input) and/or avoid shell mode for untrusted inputs by ensuring shell is false when command is not a simple token; locate the commandExists function and modify the validation around the command parameter and the spawnSync invocation to enforce this check.scripts/run-task.mjs (1)
56-66:cwd = process.cwd()is intentional but worth documenting.Spawned commands inherit the invoker's cwd rather than the repo root. This is needed so
crates/node'snapi build …passthrough runs in the oxide crate, but it also means predefined tasks likebuild(turbo …) will fail if someone ever invokesrun-task.mjsfrom a subdirectory. A short comment aboveconst cwd = process.cwd()explaining this contract would help future contributors.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/run-task.mjs` around lines 56 - 66, Add a short explanatory comment above the const cwd = process.cwd() declaration explaining that the script intentionally uses the invoker's working directory (process.cwd()) so spawned commands inherit the caller's cwd — this is required so tasks like the `crates/node` `napi build …` passthrough run inside the oxide crate; also note the trade-off that running run-task.mjs from a subdirectory can cause predefined tasks like `build` (e.g., `turbo …`) to fail. Reference the existing symbol const cwd = process.cwd() and keep the comment concise.scripts/preflight.mjs (1)
1-1: Dead code: unusedspawnSyncimport andrun()helper.The locally defined
runfunction (lines 68–75) is never called anywhere in this file — all subprocesses are executed viacommandExists/readInstalledRustTargetsfrom./rust-env.mjs. ThespawnSyncimport on line 1 is likewise unused. Safe to remove.🧹 Proposed cleanup
-import { spawnSync } from 'node:child_process' import fs from 'node:fs' import path from 'node:path' import process from 'node:process' @@ -function run(command, args) { - return spawnSync(command, args, { - cwd: root, - encoding: 'utf8', - stdio: ['ignore', 'pipe', 'pipe'], - env: rustEnv, - }) -} - function formatList(items) {Also applies to: 68-75
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/preflight.mjs` at line 1, Remove the dead code by deleting the unused import and helper: remove the top-level import "spawnSync" (import { spawnSync } from 'node:child_process') and delete the locally defined helper function named run (the function defined around lines with signature run(...) that spawns a subprocess). Ensure no other references to spawnSync or run remain; if any helper logic from run is needed, consolidate calls to existing utilities (commandExists / readInstalledRustTargets) instead.package.json (1)
35-48: LGTM — task names match entries inpredefinedCommands.All routed tasks (
build,dev,test,test:integrations,test:ui,vite,nextjs, plus thecheck:env→preflight.mjs doctorentry) are defined inscripts/run-task.mjsandscripts/preflight.mjscontexts, so none will hit the unknown-task error path.One small note:
tdd(vitest --hideSkippedTests) andbench(vitest bench) still invoke vitest directly and therefore bypass the Rust preflight. That's likely intentional for fast iteration, but if the motivation of this PR is to surface Rust env issues early on Windows, consider whethertddshould also run throughrun-task.mjs(or at leastcheck:env) to avoid the originalcargo ENOENTclass of failures.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@package.json` around lines 35 - 48, The tdd script currently invokes vitest directly ("tdd": "vitest --hideSkippedTests") and bypasses the preflight checks; change it to route through the existing runner or preflight so Rust/Windows env errors are detected early—either update the "tdd" script to call node ./scripts/run-task.mjs tdd (and implement a tdd case in scripts/run-task.mjs that runs vitest) or prepend the preflight check by making "tdd" run node ./scripts/preflight.mjs doctor && vitest --hideSkippedTests; reference the "tdd" and "bench" npm scripts and the run-task.mjs / preflight.mjs entrypoints when locating where to implement the routing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@scripts/preflight.mjs`:
- Around line 98-100: The message shown when hasDefaultCargoBin() is true is
misleading because that function is true whenever cargoBin exists (including
when CARGO_HOME was explicitly set); update the string construction to say "Rust
appears to be installed at the detected Cargo directory (<path>), so rerun the
command through the repo scripts such as `pnpm build` or `pnpm run check:env`"
and inject the cargoBin value (or equivalent detected path variable) into the
message; locate the ternary using hasDefaultCargoBin() and replace the hardcoded
"default cargo directory" text with the new phrasing that includes the cargoBin
path.
In `@scripts/run-task.mjs`:
- Around line 30-44: The unknown-task check runs after passthrough mutation so a
bogus task name can be ignored when passthrough starts with "--"; move
validation earlier by checking that task exists in predefinedCommands (i.e.
ensure predefinedCommands[task] is defined) and that task is truthy before you
compute or mutate the commands variable or apply the passthrough logic, or
alternatively add an explicit guard that if passthrough form is used and
predefinedCommands[task] is undefined you emit the unknown-task error/warning;
update the logic around the commands/passthrough handling (symbols:
predefinedCommands, task, passthrough, commands) to validate first and only then
build or override commands.
In `@scripts/rust-env.mjs`:
- Around line 23-28: The current Windows branch sets RUSTUP_TOOLCHAIN to a
hardcoded 'stable-x86_64-pc-windows-msvc' which breaks ARM64 Windows hosts;
update the env object handling for RUSTUP_TOOLCHAIN in scripts/rust-env.mjs so
it either omits RUSTUP_TOOLCHAIN entirely (letting rustup choose the default) or
derives the triple from Node's process.arch (e.g., map 'arm64' ->
'stable-aarch64-pc-windows-msvc' and default to the x86_64 triple for other
arches) instead of always forcing the x86_64 triple; change the RUSTUP_TOOLCHAIN
assignment in the Windows branch accordingly.
---
Nitpick comments:
In `@package.json`:
- Around line 35-48: The tdd script currently invokes vitest directly ("tdd":
"vitest --hideSkippedTests") and bypasses the preflight checks; change it to
route through the existing runner or preflight so Rust/Windows env errors are
detected early—either update the "tdd" script to call node
./scripts/run-task.mjs tdd (and implement a tdd case in scripts/run-task.mjs
that runs vitest) or prepend the preflight check by making "tdd" run node
./scripts/preflight.mjs doctor && vitest --hideSkippedTests; reference the "tdd"
and "bench" npm scripts and the run-task.mjs / preflight.mjs entrypoints when
locating where to implement the routing.
In `@scripts/preflight.mjs`:
- Line 1: Remove the dead code by deleting the unused import and helper: remove
the top-level import "spawnSync" (import { spawnSync } from
'node:child_process') and delete the locally defined helper function named run
(the function defined around lines with signature run(...) that spawns a
subprocess). Ensure no other references to spawnSync or run remain; if any
helper logic from run is needed, consolidate calls to existing utilities
(commandExists / readInstalledRustTargets) instead.
In `@scripts/run-task.mjs`:
- Around line 56-66: Add a short explanatory comment above the const cwd =
process.cwd() declaration explaining that the script intentionally uses the
invoker's working directory (process.cwd()) so spawned commands inherit the
caller's cwd — this is required so tasks like the `crates/node` `napi build …`
passthrough run inside the oxide crate; also note the trade-off that running
run-task.mjs from a subdirectory can cause predefined tasks like `build` (e.g.,
`turbo …`) to fail. Reference the existing symbol const cwd = process.cwd() and
keep the comment concise.
In `@scripts/rust-env.mjs`:
- Around line 31-40: The commandExists function currently calls
spawnSync(command, ['--version'], { shell: isWindows, ... }), which can allow
shell parsing surprises on Windows if command contains spaces or metacharacters;
update commandExists to validate or sanitize the command before passing it to
spawnSync (e.g., assert it matches a safe token pattern like /^[A-Za-z0-9._-]+$/
or throw/return false for unsafe input) and/or avoid shell mode for untrusted
inputs by ensuring shell is false when command is not a simple token; locate the
commandExists function and modify the validation around the command parameter
and the spawnSync invocation to enforce this check.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 7789ec75-bcdf-4edd-bac7-d5f58d76df00
📒 Files selected for processing (5)
crates/node/package.jsonpackage.jsonscripts/preflight.mjsscripts/run-task.mjsscripts/rust-env.mjs
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
scripts/run-task.mjs (1)
37-48: Passthrough without--silently drops intermediate commands' args.For multi-command tasks (
test,test:ui) the non---branch only appends passthrough args to the last command (line 46:index !== commands.length - 1). Sopnpm test -- --reporter=verboseapplies--reporter=verbosetovitestbut not tocargo, which is probably intentional, however the inverse is also true: there is no way to forward flags tocargo testvia this script. Consider documenting this behavior (or splitting into separate tasks liketest:rust/test:js) so contributors aren't surprised.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/run-task.mjs` around lines 37 - 48, The current logic only appends passthrough args to the last command (variables: passthrough, commands; mapping callback with index !== commands.length - 1), which prevents forwarding flags to earlier commands (e.g., cargo). Change the mapping so passthrough is appended to every command when the user omits a `--` (or alternatively add a selector flag to target a specific command); update the commands = commands.map(...) callback to always return [entry[0], [...entry[1], ...passthrough]] instead of only for the last index, and ensure behavior is documented in the task help/comments.scripts/preflight.mjs (1)
113-128:rustupwarning path skips the WASM target check even whencargo/rustcare present via another toolchain manager.If a contributor uses a non-rustup Rust installation (Nix, system package,
asdf, etc.),commandExists('rustup')returns false and the WASM target is never verified — only a warning is emitted. Downstreamcargo build --target wasm32-wasip1-threadswill then fail later with a less actionable error. SinceneedsWasmTargetcontexts hard-require that target, consider escalating to an error (or at least making the warning spell out how to add the target without rustup) whencontext.needsWasmTargetis true.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/preflight.mjs` around lines 113 - 128, The current branch skips verifying the WASM target when commandExists('rustup') is false, which lets context.needsWasmTarget cases slip through as only a warning; update the logic so when context.needsWasmTarget is true and rustup is not found, push an errors entry (similar to the existing errors.push for missing targets) instead of just a warnings.push, or at minimum make the warning actionable by specifying how to add the target without rustup; adjust the block that references commandExists('rustup'), context.needsWasmTarget, readInstalledRustTargets, and wasmTarget to produce an errors.push with a clear title and body recommending either rustup installation or platform-specific instructions for adding the wasm target.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@scripts/preflight.mjs`:
- Line 67: The current assignment const context = contexts[command] ??
contexts.doctor silently treats unknown command values as doctor; instead,
explicitly validate the command: check whether contexts hasOwnProperty(command)
(or command in contexts) and if not, log an error and exit non‑zero (or throw)
so typos like "typo" fail fast; if you prefer permissive behavior, at minimum
log which context was chosen (e.g., console.log or processLogger) before running
the task — update the code around the contexts/command lookup (the const context
= ... line and the success message branch that checks command === 'doctor') to
use this validation/logging approach.
In `@scripts/run-task.mjs`:
- Around line 61-67: The loop using spawnSync over the commands array is
vulnerable to cmd.exe re-parsing when shell: isWindows is set; update the call
to avoid using a shell on Windows (i.e. set shell: false) so spawnSync(command,
args, ...) passes args directly to the executable, or if a shell is absolutely
required for some commands, build a single command string and properly escape
each arg before passing it to spawnSync as a string; change the code around
spawnSync, commands and the shell: isWindows option (and the passthrough path
that produces those args) so arbitrary user-supplied tokens are not handed
unescaped into cmd.exe.
---
Nitpick comments:
In `@scripts/preflight.mjs`:
- Around line 113-128: The current branch skips verifying the WASM target when
commandExists('rustup') is false, which lets context.needsWasmTarget cases slip
through as only a warning; update the logic so when context.needsWasmTarget is
true and rustup is not found, push an errors entry (similar to the existing
errors.push for missing targets) instead of just a warnings.push, or at minimum
make the warning actionable by specifying how to add the target without rustup;
adjust the block that references commandExists('rustup'),
context.needsWasmTarget, readInstalledRustTargets, and wasmTarget to produce an
errors.push with a clear title and body recommending either rustup installation
or platform-specific instructions for adding the wasm target.
In `@scripts/run-task.mjs`:
- Around line 37-48: The current logic only appends passthrough args to the last
command (variables: passthrough, commands; mapping callback with index !==
commands.length - 1), which prevents forwarding flags to earlier commands (e.g.,
cargo). Change the mapping so passthrough is appended to every command when the
user omits a `--` (or alternatively add a selector flag to target a specific
command); update the commands = commands.map(...) callback to always return
[entry[0], [...entry[1], ...passthrough]] instead of only for the last index,
and ensure behavior is documented in the task help/comments.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 2dbe23de-d988-4ea2-8cdc-ae6ddfa6f974
📒 Files selected for processing (3)
scripts/preflight.mjsscripts/run-task.mjsscripts/rust-env.mjs
🚧 Files skipped from review as they are similar to previous changes (1)
- scripts/rust-env.mjs
| }, | ||
| } | ||
|
|
||
| const context = contexts[command] ?? contexts.doctor |
There was a problem hiding this comment.
Unknown context silently falls back to doctor.
contexts[command] ?? contexts.doctor means an unrecognized task arg runs the doctor checks instead of erroring. In practice run-task.mjs already validates the task, so this is only reachable when preflight is invoked directly (e.g. node ./scripts/preflight.mjs typo), but the success message on line 178 still gates on command === 'doctor', so a typo'd context would run doctor-equivalent checks and print nothing on success, which is confusing. Consider erroring on unknown commands, or at least logging which context was selected.
Proposed fix
-const context = contexts[command] ?? contexts.doctor
+const context = contexts[command]
+if (!context) {
+ console.error(`Unknown preflight context: ${command}`)
+ console.error(`Known contexts: ${Object.keys(contexts).join(', ')}`)
+ process.exit(1)
+}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const context = contexts[command] ?? contexts.doctor | |
| const context = contexts[command] | |
| if (!context) { | |
| console.error(`Unknown preflight context: ${command}`) | |
| console.error(`Known contexts: ${Object.keys(contexts).join(', ')}`) | |
| process.exit(1) | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@scripts/preflight.mjs` at line 67, The current assignment const context =
contexts[command] ?? contexts.doctor silently treats unknown command values as
doctor; instead, explicitly validate the command: check whether contexts
hasOwnProperty(command) (or command in contexts) and if not, log an error and
exit non‑zero (or throw) so typos like "typo" fail fast; if you prefer
permissive behavior, at minimum log which context was chosen (e.g., console.log
or processLogger) before running the task — update the code around the
contexts/command lookup (the const context = ... line and the success message
branch that checks command === 'doctor') to use this validation/logging
approach.
| for (let [command, args] of commands) { | ||
| let result = spawnSync(command, args, { | ||
| cwd, | ||
| env: rustEnv, | ||
| stdio: 'inherit', | ||
| shell: isWindows, | ||
| }) |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Does Node.js spawnSync with shell:true on Windows properly quote args containing spaces and special shell characters?
💡 Result:
No, Node.js spawnSync with shell: true on Windows does not properly quote individual arguments containing spaces or special shell characters like '&'. Instead, it simply joins the command and all args array elements with spaces into a single string, which is then passed to cmd.exe /d /s /c. This raw concatenation means spaces split arguments unless the user has already included shell-quoting in the arg strings themselves, and special characters like '&' are interpreted by cmd.exe, potentially truncating or altering command execution. The official documentation warns against passing unsanitized input with shell: true due to this risk of command injection via shell metacharacters. When shell: true and the shell is CMD, windowsVerbatimArguments is automatically true, meaning no additional quoting/escaping is done by Node.js before passing to the shell.
Citations:
- 1: https://nodejs.org/api/child_process.html
- 2: https://nodejs.org/api/child%5Fprocess.html
- 3: child_process should individually escape args[] on shell: true nodejs/node#29532
- 4: child_process.spawnSync() seems to be truncating arguments containing '&' nodejs/node#6702
- 5: Error: spawnSync npm.cmd EINVAL nodejs/node#59210
🏁 Script executed:
# First, find the file and inspect the relevant code sections
cd /tmp && find . -name "run-task.mjs" -type f 2>/dev/null | head -5Repository: tailwindlabs/tailwindcss
Length of output: 50
🏁 Script executed:
# Check if file exists at the expected path
if [ -f scripts/run-task.mjs ]; then
echo "File found at scripts/run-task.mjs"
wc -l scripts/run-task.mjs
fiRepository: tailwindlabs/tailwindcss
Length of output: 126
🏁 Script executed:
# Read the relevant sections of the file
if [ -f scripts/run-task.mjs ]; then
echo "=== Lines 40-70 (including context around the issue) ==="
sed -n '40,70p' scripts/run-task.mjs | cat -n
fiRepository: tailwindlabs/tailwindcss
Length of output: 1070
🏁 Script executed:
# Also check lines around line 43 to see the passthrough path
if [ -f scripts/run-task.mjs ]; then
echo "=== Lines 1-50 (to understand setup and line 43) ==="
sed -n '1,50p' scripts/run-task.mjs | cat -n
fiRepository: tailwindlabs/tailwindcss
Length of output: 2012
Args may not be shell-escaped correctly when shell: true on Windows.
With shell: isWindows, spawnSync passes command and joined args through cmd.exe. Node.js does minimal quoting for args when shell is truthy, so passthrough values that contain spaces, &, |, ^, ", etc. can be reinterpreted by the shell. For the hard-coded turbo/cargo/vitest/pnpm invocations this is fine, but the -- passthrough path (line 43) forwards arbitrary user-supplied tokens into this call, e.g. from crates/node napi build … --target x or any future ad-hoc use. A single arg containing a space (e.g. a path) will be split into two args on Windows.
Low impact for the current hard-coded call sites, but worth flagging since the override path is explicitly designed to accept arbitrary commands.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@scripts/run-task.mjs` around lines 61 - 67, The loop using spawnSync over the
commands array is vulnerable to cmd.exe re-parsing when shell: isWindows is set;
update the call to avoid using a shell on Windows (i.e. set shell: false) so
spawnSync(command, args, ...) passes args directly to the executable, or if a
shell is absolutely required for some commands, build a single command string
and properly escape each arg before passing it to spawnSync as a string; change
the code around spawnSync, commands and the shell: isWindows option (and the
passthrough path that produces those args) so arbitrary user-supplied tokens are
not handed unescaped into cmd.exe.
|
Hey! Thanks for your contributions, and I know I closed other PRs of yours already, but I would suggest to open issues / discussions first before making big changes to any codebase you find on GitHub. It's not fun to have to close somebody's PR, and it's not fun to get your PR closed when you put some work into this. So for that alone I'm sorry. That said, we typically do all our development on macOS and verify everything on Linux & Windows machines as well (all tests and integration tests are setup in CI). We want to keep things simple, additional layers of indirection (by introducing some custom scripts) adds an additional layer of maintenance that is not necessary and will eventually get out of sync as well. Thanks for the PR |
Here is everything you need to know about this update. Please take a good look at what changed and the test results before merging this pull request. ### What changed? #### ✳️ eslint (9.30.1 → 9.32.0) · [Repo](https://github.com/eslint/eslint) · [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) <details> <summary>Release Notes</summary> <h4><a href="https://github.com/eslint/eslint/releases/tag/v9.32.0">9.32.0</a></h4> <blockquote><h2 dir="auto">Features</h2> <ul dir="auto"> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/1245000c5a81954d42f0c7eb670efe450c3bbad5"><code class="notranslate">1245000</code></a> feat: support explicit resource management in core rules (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19828">#19828</a>) (fnx)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/0e957a7b5528f375a51e7c1a2fd1b03cdcd2af2d"><code class="notranslate">0e957a7</code></a> feat: support typescript types in accessor rules (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19882">#19882</a>) (fnx)</li> </ul> <h2 dir="auto">Bug Fixes</h2> <ul dir="auto"> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/960fd40dfd204af30726b49b6bec714fe49a606e"><code class="notranslate">960fd40</code></a> fix: Upgrade @eslint/js (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19971">#19971</a>) (Nicholas C. Zakas)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/bbf23fa2f1c6058f6cb5c9f2f32460a15e75e596"><code class="notranslate">bbf23fa</code></a> fix: Refactor reporting into FileReport (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19877">#19877</a>) (Nicholas C. Zakas)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/d4988872f375890bf677ce1a1d92a505085b51fa"><code class="notranslate">d498887</code></a> fix: bump @eslint/plugin-kit to 0.3.4 to resolve vulnerability (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19965">#19965</a>) (Milos Djermanovic)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/f46fc6c137c951bc73cf3bd9446053c1b11f769b"><code class="notranslate">f46fc6c</code></a> fix: report only global references in no-implied-eval (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19932">#19932</a>) (Nitin Kumar)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/7863d26b7cfb03a81ec86f93439757ff60bf6afb"><code class="notranslate">7863d26</code></a> fix: remove outdated types in <code class="notranslate">ParserOptions.ecmaFeatures</code> (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19944">#19944</a>) (ntnyq)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/317330552e2d276221c7f2dd9c1516ad8b41cc3c"><code class="notranslate">3173305</code></a> fix: update execScript message in no-implied-eval rule (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19937">#19937</a>) (TKDev7)</li> </ul> <h2 dir="auto">Documentation</h2> <ul dir="auto"> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/86e7426e4463ca49ffa5c82e825ecb6aa19ca8a0"><code class="notranslate">86e7426</code></a> docs: Update README (GitHub Actions Bot)</li> </ul> <h2 dir="auto">Chores</h2> <ul dir="auto"> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/50de1ced9df2b1ee48ee6843c8cfe0f5d8edbc27"><code class="notranslate">50de1ce</code></a> chore: package.json update for @eslint/js release (Jenkins)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/74f01a3f5905aaa0902837ced2425209c09c048f"><code class="notranslate">74f01a3</code></a> ci: unpin <code class="notranslate">jiti</code> to version <code class="notranslate">^2.5.1</code> (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19970">#19970</a>) (루밀LuMir)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/2ab13813a7e7f3014c35490b351447ec43229951"><code class="notranslate">2ab1381</code></a> ci: pin <code class="notranslate">jiti</code> to version 2.4.2 (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19964">#19964</a>) (Francesco Trotta)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/b7f75454695079f54b77fcdc9ebe3b9199d5ad30"><code class="notranslate">b7f7545</code></a> test: switch to flat config mode in <code class="notranslate">SourceCode</code> tests (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19953">#19953</a>) (Milos Djermanovic)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/f5a35e3b7cee17cd31fc02c24c3e74b42ee202bc"><code class="notranslate">f5a35e3</code></a> test: switch to flat config mode in eslint-fuzzer (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19960">#19960</a>) (Milos Djermanovic)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/e22af8c42d622d8d912ee7bedf49bf4283247fdc"><code class="notranslate">e22af8c</code></a> refactor: use <code class="notranslate">CustomRuleDefinitionType</code> in <code class="notranslate">JSRuleDefinition</code> (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19949">#19949</a>) (Francesco Trotta)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/e85571730f1360464b7ee00695c678d551f9c643"><code class="notranslate">e855717</code></a> chore: switch performance tests to hyperfine (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19919">#19919</a>) (Francesco Trotta)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/2f73a23655092a41780859ffe0a07c44a2f1b5f5"><code class="notranslate">2f73a23</code></a> test: switch to flat config mode in <code class="notranslate">ast-utils</code> tests (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19948">#19948</a>) (Milos Djermanovic)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/c565a530f50c96dacd44e096f7d531b073aa4dc7"><code class="notranslate">c565a53</code></a> chore: exclude <code class="notranslate">further_reading_links.json</code> from Prettier formatting (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19943">#19943</a>) (Milos Djermanovic)</li> </ul></blockquote> <h4><a href="https://github.com/eslint/eslint/releases/tag/v9.31.0">9.31.0</a></h4> <blockquote><h2 dir="auto">Features</h2> <ul dir="auto"> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/35cf44c22e36b1554486e7a75c870e86c10b83f8"><code class="notranslate">35cf44c</code></a> feat: output full actual location in rule tester if different (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19904">#19904</a>) (ST-DDT)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/a6a63259de6cb5642f69c7be429554bbcedca4c0"><code class="notranslate">a6a6325</code></a> feat: support explicit resource management in <code class="notranslate">no-loop-func</code> (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19895">#19895</a>) (Milos Djermanovic)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/4682cdc6960279ee17f23899fbab6f58d881eadf"><code class="notranslate">4682cdc</code></a> feat: support explicit resource management in <code class="notranslate">no-undef-init</code> (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19894">#19894</a>) (Milos Djermanovic)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/58482165eaf597cc5c58216a956c301ae87520b3"><code class="notranslate">5848216</code></a> feat: support explicit resource management in <code class="notranslate">init-declarations</code> (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19893">#19893</a>) (Milos Djermanovic)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/bb370b8e79f65ee32d9d89ecf249fb74a141ad22"><code class="notranslate">bb370b8</code></a> feat: support explicit resource management in <code class="notranslate">no-const-assign</code> (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19892">#19892</a>) (Milos Djermanovic)</li> </ul> <h2 dir="auto">Bug Fixes</h2> <ul dir="auto"> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/07fac6cafa0426b4d1ea12d9001f3955f19b286d"><code class="notranslate">07fac6c</code></a> fix: retry on EMFILE when writing autofix results (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19926">#19926</a>) (TKDev7)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/28cc7abbb72b29b1cac6fc4253646a7839586064"><code class="notranslate">28cc7ab</code></a> fix: Remove incorrect RuleContext types (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19910">#19910</a>) (Nicholas C. Zakas)</li> </ul> <h2 dir="auto">Documentation</h2> <ul dir="auto"> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/664cb44ab03785bd200a792607a7e20faa2d4b28"><code class="notranslate">664cb44</code></a> docs: Update README (GitHub Actions Bot)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/40dbe2a43f83d366e9026faec70293512fb61ca2"><code class="notranslate">40dbe2a</code></a> docs: fix mismatch between <code class="notranslate">globalIgnores()</code> code and text (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19914">#19914</a>) (MaoShizhong)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/5a0069d60815246cf24e1c96125540792c2507ef"><code class="notranslate">5a0069d</code></a> docs: Update README (GitHub Actions Bot)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/fef04b5c7fea99362d67b31b8e98cd4914020ed3"><code class="notranslate">fef04b5</code></a> docs: Update working on issues info (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19902">#19902</a>) (Nicholas C. Zakas)</li> </ul> <h2 dir="auto">Chores</h2> <ul dir="auto"> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/3ddd454c1c73294e5af7905d60d03fac162f1b3e"><code class="notranslate">3ddd454</code></a> chore: upgrade to <code class="notranslate">@eslint/js@9.31.0</code> (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19935">#19935</a>) (Francesco Trotta)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/d5054e5454a537e9ade238c768c262c6c592cbc1"><code class="notranslate">d5054e5</code></a> chore: package.json update for @eslint/js release (Jenkins)</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/0f4a3781fe7c11fad7b206c3c694655486ddd187"><code class="notranslate">0f4a378</code></a> chore: update eslint (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19933">#19933</a>) (renovate[bot])</li> <li> <a href="https://bounce.depfu.com/github.com/eslint/eslint/commit/76c2340c368f96db77439b5cd1df0196cc39bf3e"><code class="notranslate">76c2340</code></a> chore: bump mocha to v11 (<a href="https://bounce.depfu.com/github.com/eslint/eslint/pull/19917">#19917</a>) (루밀LuMir)</li> </ul></blockquote> <p><em>Does any of this look wrong? <a href="https://depfu.com/packages/npm/eslint/feedback">Please let us know.</a></em></p> </details> <details> <summary>Commits</summary> <p><a href="https://github.com/eslint/eslint/compare/6769b5fa11ecfb2c2cf78472d3d90564a1e01d3c...2364031090daafe34e80904c32065bfe4692d7a2">See the full diff on Github</a>. The new version differs by 37 commits:</p> <ul> <li><a href="https://github.com/eslint/eslint/commit/2364031090daafe34e80904c32065bfe4692d7a2"><code>9.32.0</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/a0e62e2739a5e214b1d371eda76f6a3b664e222a"><code>Build: changelog update for 9.32.0</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/960fd40dfd204af30726b49b6bec714fe49a606e"><code>fix: Upgrade @eslint/js (tailwindlabs#19971)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/50de1ced9df2b1ee48ee6843c8cfe0f5d8edbc27"><code>chore: package.json update for @eslint/js release</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/bbf23fa2f1c6058f6cb5c9f2f32460a15e75e596"><code>fix: Refactor reporting into FileReport (tailwindlabs#19877)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/74f01a3f5905aaa0902837ced2425209c09c048f"><code>ci: unpin `jiti` to version `^2.5.1` (tailwindlabs#19970)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/d4988872f375890bf677ce1a1d92a505085b51fa"><code>fix: bump @eslint/plugin-kit to 0.3.4 to resolve vulnerability (tailwindlabs#19965)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/2ab13813a7e7f3014c35490b351447ec43229951"><code>ci: pin `jiti` to version 2.4.2 (tailwindlabs#19964)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/b7f75454695079f54b77fcdc9ebe3b9199d5ad30"><code>test: switch to flat config mode in `SourceCode` tests (tailwindlabs#19953)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/f5a35e3b7cee17cd31fc02c24c3e74b42ee202bc"><code>test: switch to flat config mode in eslint-fuzzer (tailwindlabs#19960)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/f46fc6c137c951bc73cf3bd9446053c1b11f769b"><code>fix: report only global references in no-implied-eval (tailwindlabs#19932)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/86e7426e4463ca49ffa5c82e825ecb6aa19ca8a0"><code>docs: Update README</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/e22af8c42d622d8d912ee7bedf49bf4283247fdc"><code>refactor: use `CustomRuleDefinitionType` in `JSRuleDefinition` (tailwindlabs#19949)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/1245000c5a81954d42f0c7eb670efe450c3bbad5"><code>feat: support explicit resource management in core rules (tailwindlabs#19828)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/e85571730f1360464b7ee00695c678d551f9c643"><code>chore: switch performance tests to hyperfine (tailwindlabs#19919)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/0e957a7b5528f375a51e7c1a2fd1b03cdcd2af2d"><code>feat: support typescript types in accessor rules (tailwindlabs#19882)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/2f73a23655092a41780859ffe0a07c44a2f1b5f5"><code>test: switch to flat config mode in `ast-utils` tests (tailwindlabs#19948)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/7863d26b7cfb03a81ec86f93439757ff60bf6afb"><code>fix: remove outdated types in `ParserOptions.ecmaFeatures` (tailwindlabs#19944)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/c565a530f50c96dacd44e096f7d531b073aa4dc7"><code>chore: exclude `further_reading_links.json` from Prettier formatting (tailwindlabs#19943)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/317330552e2d276221c7f2dd9c1516ad8b41cc3c"><code>fix: update execScript message in no-implied-eval rule (tailwindlabs#19937)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/14053edc64bd378ab920575f2488fbfcbb5a4ea0"><code>9.31.0</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/2b77bd05dc50911bc97b2d2711dd75f6b5d9b9fd"><code>Build: changelog update for 9.31.0</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/3ddd454c1c73294e5af7905d60d03fac162f1b3e"><code>chore: upgrade to `@eslint/js@9.31.0` (tailwindlabs#19935)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/d5054e5454a537e9ade238c768c262c6c592cbc1"><code>chore: package.json update for @eslint/js release</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/0f4a3781fe7c11fad7b206c3c694655486ddd187"><code>chore: update eslint (tailwindlabs#19933)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/664cb44ab03785bd200a792607a7e20faa2d4b28"><code>docs: Update README</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/07fac6cafa0426b4d1ea12d9001f3955f19b286d"><code>fix: retry on EMFILE when writing autofix results (tailwindlabs#19926)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/35cf44c22e36b1554486e7a75c870e86c10b83f8"><code>feat: output full actual location in rule tester if different (tailwindlabs#19904)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/40dbe2a43f83d366e9026faec70293512fb61ca2"><code>docs: fix mismatch between `globalIgnores()` code and text (tailwindlabs#19914)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/76c2340c368f96db77439b5cd1df0196cc39bf3e"><code>chore: bump mocha to v11 (tailwindlabs#19917)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/28cc7abbb72b29b1cac6fc4253646a7839586064"><code>fix: Remove incorrect RuleContext types (tailwindlabs#19910)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/a6a63259de6cb5642f69c7be429554bbcedca4c0"><code>feat: support explicit resource management in `no-loop-func` (tailwindlabs#19895)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/4682cdc6960279ee17f23899fbab6f58d881eadf"><code>feat: support explicit resource management in `no-undef-init` (tailwindlabs#19894)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/58482165eaf597cc5c58216a956c301ae87520b3"><code>feat: support explicit resource management in `init-declarations` (tailwindlabs#19893)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/bb370b8e79f65ee32d9d89ecf249fb74a141ad22"><code>feat: support explicit resource management in `no-const-assign` (tailwindlabs#19892)</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/5a0069d60815246cf24e1c96125540792c2507ef"><code>docs: Update README</code></a></li> <li><a href="https://github.com/eslint/eslint/commit/fef04b5c7fea99362d67b31b8e98cd4914020ed3"><code>docs: Update working on issues info (tailwindlabs#19902)</code></a></li> </ul> </details> ---  [Depfu](https://depfu.com) will automatically keep this PR conflict-free, as long as you don't add any commits to this branch yourself. You can also trigger a rebase manually by commenting with `@depfu rebase`. <details><summary>All Depfu comment commands</summary> <blockquote><dl> <dt>@depfu rebase</dt><dd>Rebases against your default branch and redoes this update</dd> <dt>@depfu recreate</dt><dd>Recreates this PR, overwriting any edits that you've made to it</dd> <dt>@depfu merge</dt><dd>Merges this PR once your tests are passing and conflicts are resolved</dd> <dt>@depfu cancel merge</dt><dd>Cancels automatic merging of this PR</dd> <dt>@depfu close</dt><dd>Closes this PR and deletes the branch</dd> <dt>@depfu reopen</dt><dd>Restores the branch and reopens this PR (if it's closed)</dd> <dt>@depfu pause</dt><dd>Ignores all future updates for this dependency and closes this PR</dd> <dt>@depfu pause [minor|major]</dt><dd>Ignores all future minor/major updates for this dependency and closes this PR</dd> <dt>@depfu resume</dt><dd>Future versions of this dependency will create PRs again (leaves this PR as is)</dd> </dl></blockquote> </details> Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com>
Hello Tailwind CSS team,
I’m submitting this contribution set with a strong focus on reviewability, project fit, and contributor usefulness.
Instead of opening one large pull request, I deliberately split the work into three smaller PRs so each change can be reviewed on its own merits and verified independently:
I chose that structure intentionally. Since this repository spans the compiler core, multiple adapters, the Node bridge, and the oxide scanner, broad PRs can become difficult to review quickly. I wanted each change to stay close to the layer that actually owns the behavior, and I wanted the validation story for each PR to remain simple and concrete.
The first PR,
fix/windows-rust-env, is focused on contributor workflows on Windows. The specific problem I addressed was that contributors could still hitcargo ENOENTfailures during build workflows even when Rust was already installed, simply because the current shell environment did not expose the expected Rust binaries cleanly. To address that, I added environment-aware helper scripts, introduced a contributor-facing preflight check, and routed the relevant build/test commands through the same corrected Rust-aware execution path. I also updated the oxide package build commands to use that path consistently. The purpose of this PR is narrow: make the Windows contributor workflow more reliable without changing the actual compiler behavior.The second PR,
feat/hocus-variant, is a small but real product-facing change in Tailwind itself. I added a built-inhocus:variant that applies styles on both focus and hover. I kept the implementation aligned with existing variant behavior by preserving the@media (hover: hover)guard for hover output while still emitting direct focus selectors. I also updated the relevant focused tests so that the feature is covered both at the variant-output level and in@applyerror reporting. The goal here was to contribute something user-visible while still keeping the scope compact and easy to reason about.The third PR,
docs/contributor-guides, is documentation-focused, but not generic documentation. I rewrote the contributor-facing guidance so it reflects how this repository actually works: the relationship between the core compiler, the adapter layer,@tailwindcss/node, the oxide scanner, integration fixtures, and the playground workflows. I specifically tried to avoid boilerplate open-source text and instead wrote the docs around the real workflows a contributor would hit in this monorepo, especially around setup, validation, Windows-specific issues, Rust, Bun, Playwright, and deciding where a change belongs before editing code. My intention was to improve contributor onboarding without adding docs that feel detached from the codebase.Across the three PRs, I tried to keep a few principles consistent:
Validation for the work included:
pnpm run check:envcd crates/node && pnpm run buildpnpm exec vitest run packages/tailwindcss/src/variants.test.ts packages/tailwindcss/src/index.test.ts -t "hocus|variant that does not exist"For the docs work, I also manually reviewed the command paths, local guide links, and contributor flow to make sure the text matched the actual repository structure and workflows.
This is one of my first serious open-source contribution sets at this level of repository complexity, so I approached it conservatively: understand the local code path first, make the change in the nearest owning layer, validate the smallest relevant slice, and split the work into focused PRs instead of asking maintainers to parse one broad patch. If any of these changes should be scoped even more tightly, rewritten in a different style, or moved to a different layer, I’m happy to revise them.
Thank you for your time and review.