Skip to content

fix: escape square brackets in glob paths - #920

Open
tzh476 wants to merge 2 commits into
unplugin:mainfrom
tzh476:fix/escape-square-brackets-in-globs
Open

fix: escape square brackets in glob paths#920
tzh476 wants to merge 2 commits into
unplugin:mainfrom
tzh476:fix/escape-square-brackets-in-globs

Conversation

@tzh476

@tzh476 tzh476 commented Aug 17, 2026

Copy link
Copy Markdown

What

Escape [] in resolved component globs so directories like [Resource] or [a-z] match in the watcher.

Why

escapeSpecialChars only escaped (). resolveOptions builds globs from absolute dirs, so a folder named [Resource] becomes a picomatch character class. Range-like names such as [a-z] still fail to match the real path (picomatch 4 treats some non-range brackets as literals, which is likely why #913 was closed as no longer needed — the range case remains broken).

How

Extend the escape regex from /[()]/g to /[()[\]]/g. matchGlobs then receives a literal-bracket pattern.

Testing

  • vitest run test/utils.test.ts
  • 6 passed (0 fail)
  • RED on current main: matchGlobs('/.../[a-z]/.../Button.vue', [unescaped glob]) is false
  • GREEN after the escape: same path returns true
  • Also covers [Foo] as requested

Fixes #810

Made with Cursor

Resolved dirs such as [Resource] or [a-z] were passed to picomatch as
character classes, so the watcher skipped matching files. Escape [] the
same way parentheses are already escaped.

Change-Id: I6f7df301ff794b36e009767ce090ceb22ac07c3c
Co-authored-by: Cursor <cursoragent@cursor.com>
@tzh476
tzh476 requested a review from antfu as a code owner August 17, 2026 16:31
@bolt-new-by-stackblitz

Copy link
Copy Markdown

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@pkg-pr-new

pkg-pr-new Bot commented Aug 17, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/unplugin-vue-components@920

commit: 729dd70

…orking

Extending escapeSpecialChars to brackets, as this PR originally did, escapes the
whole joined path -- including the part that comes from the user's `dirs` option.
That turns a deliberate character class into a literal:

  dirs: ['src/[ab]']  ->  /proj/src/[ab]/**/*.vue    matches /proj/src/a  true
                          /proj/src/\[ab\]/**/*.vue  matches /proj/src/a  false

Verified with picomatch against the exact glob options.ts builds.

Escape only the `root` prefix instead. That is a real filesystem path, so its
parentheses and brackets are always literal, while everything after it is left as
the user wrote it.

Three tests added; the two behavioural ones fail with the previous implementation:
  - a character class after the root still matches multiple directories
  - the same under a root containing parentheses, so both hold at once

Note: test/dts.test.ts has 7 failures on this branch, but they reproduce on the
branch with these three files reverted, so they are pre-existing and unrelated.

Change-Id: I430acfc4eef4ecc2ef353a3fb46daf2ee98f93bf
Signed-off-by: tzh476 <tzh476@gmail.com>
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.

Square brackets in resolved base path leads to matchGlobs in watcher to fails

1 participant