diff --git a/packages/glob/__tests__/internal-globber.test.ts b/packages/glob/__tests__/internal-globber.test.ts index cb6f343f..36dec23d 100644 --- a/packages/glob/__tests__/internal-globber.test.ts +++ b/packages/glob/__tests__/internal-globber.test.ts @@ -97,6 +97,24 @@ describe('globber', () => { ]) }) + it('does not match file with trailing slash when implicitDescendants=true', async () => { + // Create the following layout: + // + // /file + const root = path.join( + getTestTemp(), + 'defaults-to-implicit-descendants-true' + ) + + const filePath = path.join(root, 'file') + + await fs.mkdir(root, {recursive: true}) + await fs.writeFile(filePath, 'test file content') + + const itemPaths = await glob(`${filePath}/`, {}) + expect(itemPaths).toEqual([]) + }) + it('defaults to omitBrokenSymbolicLinks=true', async () => { // Create the following layout: // diff --git a/packages/glob/__tests__/internal-pattern.test.ts b/packages/glob/__tests__/internal-pattern.test.ts index 11b0507d..8a9ecc85 100644 --- a/packages/glob/__tests__/internal-pattern.test.ts +++ b/packages/glob/__tests__/internal-pattern.test.ts @@ -26,7 +26,7 @@ describe('pattern', () => { it('escapes homedir', async () => { const home = path.join(getTestTemp(), 'home-with-[and]') await fs.mkdir(home, {recursive: true}) - const pattern = new Pattern('~/m*', undefined, home) + const pattern = new Pattern('~/m*', false, undefined, home) expect(pattern.searchPath).toBe(home) expect(pattern.match(path.join(home, 'match'))).toBeTruthy() diff --git a/packages/glob/src/internal-globber.ts b/packages/glob/src/internal-globber.ts index aac3032d..98cbb819 100644 --- a/packages/glob/src/internal-globber.ts +++ b/packages/glob/src/internal-globber.ts @@ -66,7 +66,6 @@ export class DefaultGlobber implements Globber { async *globGenerator(): AsyncGenerator { // Fill in defaults options const options = globOptionsHelper.getOptions(this.options) - // Implicit descendants? const patterns: Pattern[] = [] for (const pattern of this.patterns) { @@ -77,12 +76,13 @@ export class DefaultGlobber implements Globber { pattern.segments[pattern.segments.length - 1] !== '**') ) { patterns.push( - new Pattern(pattern.negate, pattern.segments.concat('**')) + new Pattern(pattern.negate, true, pattern.segments.concat('**')) ) } } // Push the search paths + const stack: SearchState[] = [] for (const searchPath of patternHelper.getSearchPaths(patterns)) { core.debug(`Search path '${searchPath}'`) @@ -180,6 +180,7 @@ export class DefaultGlobber implements Globber { } result.searchPaths.push(...patternHelper.getSearchPaths(result.patterns)) + return result } diff --git a/packages/glob/src/internal-pattern.ts b/packages/glob/src/internal-pattern.ts index 72e3dc71..a2e074a5 100644 --- a/packages/glob/src/internal-pattern.ts +++ b/packages/glob/src/internal-pattern.ts @@ -43,15 +43,31 @@ export class Pattern { */ private readonly rootRegExp: RegExp + /** + * Indicates that the pattern is implicitly added as opposed to user specified. + */ + private readonly isImplicitPattern: boolean + /* eslint-disable no-dupe-class-members */ // Disable no-dupe-class-members due to false positive for method overload // https://github.com/typescript-eslint/typescript-eslint/issues/291 constructor(pattern: string) - constructor(pattern: string, segments: undefined, homedir: string) - constructor(negate: boolean, segments: string[]) + constructor( + pattern: string, + isImplicitPattern: boolean, + segments: undefined, + homedir: string + ) + constructor( + negate: boolean, + isImplicitPattern: boolean, + segments: string[], + homedir?: string + ) constructor( patternOrNegate: string | boolean, + isImplicitPattern: boolean = false, segments?: string[], homedir?: string ) { @@ -107,6 +123,8 @@ export class Pattern { IS_WINDOWS ? 'i' : '' ) + this.isImplicitPattern = isImplicitPattern + // Create minimatch const minimatchOptions: IMinimatchOptions = { dot: true, @@ -132,7 +150,7 @@ export class Pattern { // Append a trailing slash. Otherwise Minimatch will not match the directory immediately // preceding the globstar. For example, given the pattern `/foo/**`, Minimatch returns // false for `/foo` but returns true for `/foo/`. Append a trailing slash to handle that quirk. - if (!itemPath.endsWith(path.sep)) { + if (!itemPath.endsWith(path.sep) && this.isImplicitPattern === false) { // Note, this is safe because the constructor ensures the pattern has an absolute root. // For example, formats like C: and C:foo on Windows are resolved to an absolute root. itemPath = `${itemPath}${path.sep}`