Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions packages/glob/__tests__/internal-pattern-helper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,36 @@ describe('pattern-helper', () => {
])
})

it('matches when itemPath uses Windows separators', () => {
if (!IS_WINDOWS) return
const root = 'C\\\\'
const patterns = [
`${root}**/*.proj`,
`${root}**/README.txt`,
`!${root}**/solution2/**`,
`${root}**/*.sln`,
`!${root}**/proj2/README.txt`
].map(x => new Pattern(x))
expect(
patternHelper.match(
patterns,
path.join(root, 'solution1', 'proj1', 'proj1.proj')
)
).toBe(MatchKind.All)
expect(
patternHelper.match(
patterns,
path.join(root, 'solution1', 'proj2', 'README.txt')
)
).toBe(MatchKind.All)
expect(
patternHelper.match(
patterns,
path.join(root, 'solution2', 'proj1', 'README.txt')
)
).toBe(MatchKind.None)
})

it('partialMatch skips negate patterns', () => {
const root = IS_WINDOWS ? 'C:\\' : '/'
const patterns = [
Expand Down
11 changes: 11 additions & 0 deletions packages/glob/__tests__/internal-pattern.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,17 @@ describe('pattern', () => {
)
})

it('matches when itemPath uses Windows separators', () => {
if (!IS_WINDOWS) return
const root = 'C\\\\'
const pattern = new Pattern(`${root}Foo/**/Baz`)
// itemPath uses '\\' separators; toMinimatchPath should normalize
expect(pattern.match(path.join(root, 'Foo', 'Baz'))).toBe(MatchKind.All)
expect(pattern.match(path.join(root, 'Foo', 'bar', 'bAZ'))).toBe(
MatchKind.All
)
})

it('is case insensitive partial match on Windows', () => {
const root = IS_WINDOWS ? 'C:\\' : '/'
const pattern = new Pattern(`${root}Foo/Bar/**/Baz`)
Expand Down
10 changes: 10 additions & 0 deletions packages/glob/src/internal-path-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,13 @@ export function safeTrimTrailingSeparator(p: string): string {
// Otherwise trim trailing slash
return p.substr(0, p.length - 1)
}

/**
* Converts a filesystem path to a Minimatch-friendly path.
* Minimatch operates on POSIX-style '/' separators across platforms.
* On Windows, convert '\\' to '/'. Otherwise, return the path unchanged.
*/
export function toMinimatchPath(p: string): string {
if (!p) return ''
return IS_WINDOWS ? p.replace(/\\/g, '/') : p
}
13 changes: 9 additions & 4 deletions packages/glob/src/internal-pattern.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,9 @@ export class Pattern {
noext: true,
nonegate: true
}
pattern = IS_WINDOWS ? pattern.replace(/\\/g, '/') : pattern
this.minimatch = new Minimatch(pattern, minimatchOptions)
// Convert to a Minimatch-friendly form using POSIX separators
const minimatchPattern = pathHelper.toMinimatchPath(pattern)
this.minimatch = new Minimatch(minimatchPattern, minimatchOptions)
}

/**
Expand All @@ -156,8 +157,11 @@ export class Pattern {
itemPath = pathHelper.safeTrimTrailingSeparator(itemPath)
}

// Convert to a Minimatch-friendly form using POSIX separators
const itemPathForMatch = pathHelper.toMinimatchPath(itemPath)

// Match
if (this.minimatch.match(itemPath)) {
if (this.minimatch.match(itemPathForMatch)) {
return this.trailingSeparator ? MatchKind.Directory : MatchKind.All
}

Expand All @@ -176,8 +180,9 @@ export class Pattern {
return this.rootRegExp.test(itemPath)
}

const mmItem = pathHelper.toMinimatchPath(itemPath)
return this.minimatch.matchOne(
itemPath.split(IS_WINDOWS ? /\\+/ : /\/+/),
mmItem.split(/\/+/),
this.minimatch.set[0],
true
)
Expand Down