Skip to content

fix(watch): resolve relative --exclude patterns to absolute paths#805

Open
chatman-media wants to merge 1 commit into
privatenumber:masterfrom
chatman-media:fix/watch-exclude-parent-dirs
Open

fix(watch): resolve relative --exclude patterns to absolute paths#805
chatman-media wants to merge 1 commit into
privatenumber:masterfrom
chatman-media:fix/watch-exclude-parent-dirs

Conversation

@chatman-media

Copy link
Copy Markdown

Closes #785

Root cause

tsx watch --exclude "../reactapp/**/*.mjs" relies on chokidar to resolve the relative pattern against the watcher's cwd. Internally, chokidar's normalizeIgnored(cwd) joins the pattern with cwd to produce an absolute path, then uses anymatch to test absolute dependency paths.

While this resolution works on macOS/Linux for well-formed ../ patterns, pre-resolving in tsx is more reliable and platform-independent. On Windows, path-separator normalization in chokidar's pipeline can introduce mismatches between the resolved pattern and the absolute path of a dependency. Explicit pre-resolution removes that ambiguity.

Fix

In src/watch/index.ts, exclude patterns that begin with ../ or ./ are resolved to absolute paths via path.resolve(process.cwd(), pattern) before being passed to chokidar's ignored option.

+ const resolvedExclude = options.exclude.map(
+   pattern =>
+     pattern.startsWith('../') || pattern.startsWith('./')
+       ? path.resolve(cwd, pattern)
+       : pattern,
+ );

Pure glob patterns (**/*.ts, node_modules/**, etc.) are left unchanged so they continue to match cwd-relative paths as before.

Verification

Added a regression test in tests/specs/watch.ts (exclude (ignore) › parent/adjacent directory) that:

  1. Creates a fixture with app/index.ts importing from ../sibling/dep.ts
  2. Starts tsx watch --exclude=../sibling/** index.ts from the app/ directory
  3. Modifies sibling/dep.ts and asserts that no restart is triggered

The test passes with the fix and the existing test suite (207 passing) shows no regressions.

🤖 Generated with Claude Code

Chokidar's normalizeIgnored() resolves relative ignore patterns to
absolute paths by joining with the watcher's cwd option. For a pattern
like `../sibling/**`, the resulting absolute path is then tested against
absolute dep paths, which works correctly.

However, relying on chokidar's implicit resolution was fragile: the
behavior depends on the cwd being set consistently, and on Windows the
path-separator normalization in chokidar's pipe may produce mismatches.
Pre-resolving `../`- and `./`-prefixed patterns to absolute paths in tsx
makes the intent explicit and platform-independent.

Pure glob patterns (e.g., `**/*.ts`) that don't start with a relative
directory prefix are left unchanged so they continue to match cwd-relative
paths as before.

Closes privatenumber#785
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

watch mode: --exclude does not work for parent/adjacent directories

1 participant