Skip to content

Commit

Permalink
glob (actions#268)
Browse files Browse the repository at this point in the history
  • Loading branch information
ericsciple authored Dec 31, 2019
1 parent a94e244 commit a11539e
Show file tree
Hide file tree
Showing 16 changed files with 3,065 additions and 0 deletions.
671 changes: 671 additions & 0 deletions packages/glob/__tests__/glob.test.ts

Large diffs are not rendered by default.

640 changes: 640 additions & 0 deletions packages/glob/__tests__/internal-path-helper.test.ts

Large diffs are not rendered by default.

92 changes: 92 additions & 0 deletions packages/glob/__tests__/internal-path.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import * as path from 'path'
import {Path} from '../src/internal-path'

const IS_WINDOWS = process.platform === 'win32'

describe('path', () => {
it('constructs from rooted path', () => {
assertPath(`/`, `${path.sep}`, [path.sep])
assertPath(`/foo`, `${path.sep}foo`, [path.sep, 'foo'])
if (IS_WINDOWS) {
assertPath(`C:\\foo`, `C:\\foo`, ['C:\\', 'foo'])
assertPath(`C:foo`, `C:foo`, ['C:', 'foo'])
assertPath(`\\\\foo\\bar\\baz`, `\\\\foo\\bar\\baz`, [
'\\\\foo\\bar',
'baz'
])
}
})

it('constructs from rooted segments', () => {
assertPath([`/`], `${path.sep}`, [path.sep])
assertPath([`/`, `foo`], `${path.sep}foo`, [path.sep, 'foo'])
if (IS_WINDOWS) {
assertPath([`C:\\`, `foo`], `C:\\foo`, ['C:\\', 'foo'])
assertPath([`C:`, `foo`], `C:foo`, ['C:', 'foo'])
assertPath([`\\\\foo\\bar`, `baz`], `\\\\foo\\bar\\baz`, [
'\\\\foo\\bar',
'baz'
])
}
})

it('constructs from relative path', () => {
assertPath(`foo`, `foo`, ['foo'])
assertPath(`foo/bar`, `foo${path.sep}bar`, ['foo', 'bar'])
})

it('constructs from relative segments', () => {
assertPath([`foo`], `foo`, ['foo'])
assertPath([`foo`, `bar`], `foo${path.sep}bar`, ['foo', 'bar'])
})

it('normalizes slashes', () => {
assertPath(
`/foo///bar${path.sep}${path.sep}${path.sep}baz`,
`${path.sep}foo${path.sep}bar${path.sep}baz`,
[path.sep, 'foo', 'bar', 'baz']
)
})

it('preserves relative pathing', () => {
assertPath(
'/foo/../bar/./baz',
`${path.sep}foo${path.sep}..${path.sep}bar${path.sep}.${path.sep}baz`,
[path.sep, 'foo', '..', 'bar', '.', 'baz']
)
})

it('trims unnecessary trailing slash', () => {
assertPath('/', path.sep, [path.sep])
assertPath('/foo/', `${path.sep}foo`, [path.sep, 'foo'])
assertPath('foo/', 'foo', ['foo'])
assertPath('foo/bar/', `foo${path.sep}bar`, ['foo', 'bar'])
if (IS_WINDOWS) {
assertPath('\\', '\\', ['\\'])
assertPath('C:\\', 'C:\\', ['C:\\'])
assertPath('C:\\foo\\', 'C:\\foo', ['C:\\', 'foo'])
assertPath('C:foo\\', 'C:foo', ['C:', 'foo'])
assertPath('\\\\computer\\share\\', '\\\\computer\\share', [
'\\\\computer\\share'
])
assertPath('\\\\computer\\share\\foo', '\\\\computer\\share\\foo', [
'\\\\computer\\share',
'foo'
])
assertPath('\\\\computer\\share\\foo\\', '\\\\computer\\share\\foo', [
'\\\\computer\\share',
'foo'
])
}
})
})

function assertPath(
itemPath: string | string[],
expectedPath: string,
expectedSegments: string[]
): void {
const actual = new Path(itemPath)
expect(actual.toString()).toBe(expectedPath)
expect(actual.segments).toEqual(expectedSegments)
}
190 changes: 190 additions & 0 deletions packages/glob/__tests__/internal-pattern-helper.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
import * as path from 'path'
import * as patternHelper from '../src/internal-pattern-helper'
import {MatchKind} from '../src/internal-match-kind'
import {IS_WINDOWS} from '../../io/src/io-util'

describe('pattern-helper', () => {
it('getSearchPaths omits negate search paths', () => {
const root = IS_WINDOWS ? 'C:\\' : '/'
const patterns = patternHelper.parse(
[
`${root}search1/foo/**`,
`${root}search2/bar/**`,
`!${root}search3/baz/**`
],
patternHelper.getOptions()
)
const searchPaths = patternHelper.getSearchPaths(patterns)
expect(searchPaths).toEqual([
`${root}search1${path.sep}foo`,
`${root}search2${path.sep}bar`
])
})

it('getSearchPaths omits search path when ancestor is also a search path', () => {
if (IS_WINDOWS) {
const patterns = patternHelper.parse(
[
'C:\\Search1\\Foo\\**',
'C:\\sEARCH1\\fOO\\bar\\**',
'C:\\sEARCH1\\foo\\bar',
'C:\\Search2\\**',
'C:\\Search3\\Foo\\Bar\\**',
'C:\\sEARCH3\\fOO\\bAR\\**'
],
patternHelper.getOptions()
)
const searchPaths = patternHelper.getSearchPaths(patterns)
expect(searchPaths).toEqual([
'C:\\Search1\\Foo',
'C:\\Search2',
'C:\\Search3\\Foo\\Bar'
])
} else {
const patterns = patternHelper.parse(
[
'/search1/foo/**',
'/search1/foo/bar/**',
'/search2/foo/bar',
'/search2/**',
'/search3/foo/bar/**',
'/search3/foo/bar/**'
],
patternHelper.getOptions()
)
const searchPaths = patternHelper.getSearchPaths(patterns)
expect(searchPaths).toEqual([
'/search1/foo',
'/search2',
'/search3/foo/bar'
])
}
})

it('match supports interleaved exclude patterns', () => {
const root = IS_WINDOWS ? 'C:\\' : '/'
const itemPaths = [
`${root}solution1/proj1/proj1.proj`,
`${root}solution1/proj1/README.txt`,
`${root}solution1/proj2/proj2.proj`,
`${root}solution1/proj2/README.txt`,
`${root}solution1/solution1.sln`,
`${root}solution2/proj1/proj1.proj`,
`${root}solution2/proj1/README.txt`,
`${root}solution2/proj2/proj2.proj`,
`${root}solution2/proj2/README.txt`,
`${root}solution2/solution2.sln`
]
const patterns = patternHelper.parse(
[
`${root}**/*.proj`, // include all proj files
`${root}**/README.txt`, // include all README files
`!${root}**/solution2/**`, // exclude the solution 2 folder entirely
`${root}**/*.sln`, // include all sln files
`!${root}**/proj2/README.txt` // exclude proj2 README files
],
patternHelper.getOptions({implicitDescendants: false})
)
const matched = itemPaths.filter(
x => patternHelper.match(patterns, x) === MatchKind.All
)
expect(matched).toEqual([
`${root}solution1/proj1/proj1.proj`,
`${root}solution1/proj1/README.txt`,
`${root}solution1/proj2/proj2.proj`,
`${root}solution1/solution1.sln`,
`${root}solution2/solution2.sln`
])
})

it('match supports excluding directories', () => {
const root = IS_WINDOWS ? 'C:\\' : '/'
const itemPaths = [
root,
`${root}foo`,
`${root}foo/bar`,
`${root}foo/bar/baz`
]
const patterns = patternHelper.parse(
[
`${root}foo/**`, // include all files and directories
`!${root}foo/**/` // exclude directories
],
patternHelper.getOptions({implicitDescendants: false})
)
const matchKinds = itemPaths.map(x => patternHelper.match(patterns, x))
expect(matchKinds).toEqual([
MatchKind.None,
MatchKind.File,
MatchKind.File,
MatchKind.File
])
})

it('match supports including directories only', () => {
const root = IS_WINDOWS ? 'C:\\' : '/'
const itemPaths = [
root,
`${root}foo/`,
`${root}foo/bar`,
`${root}foo/bar/baz`
]
const patterns = patternHelper.parse(
[
`${root}foo/**/` // include directories only
],
patternHelper.getOptions({implicitDescendants: false})
)
const matchKinds = itemPaths.map(x => patternHelper.match(patterns, x))
expect(matchKinds).toEqual([
MatchKind.None,
MatchKind.Directory,
MatchKind.Directory,
MatchKind.Directory
])
})

it('parse skips comments', () => {
const patterns = patternHelper.parse(
['# comment 1', ' # comment 2', '!#hello-world.txt'],
patternHelper.getOptions({implicitDescendants: false})
)
expect(patterns).toHaveLength(1)
expect(patterns[0].negate).toBeTruthy()
expect(patterns[0].segments.reverse()[0]).toEqual('#hello-world.txt')
})

it('parse skips empty patterns', () => {
const patterns = patternHelper.parse(
['', ' ', 'hello-world.txt'],
patternHelper.getOptions({implicitDescendants: false})
)
expect(patterns).toHaveLength(1)
expect(patterns[0].segments.reverse()[0]).toEqual('hello-world.txt')
})

it('partialMatch skips negate patterns', () => {
const root = IS_WINDOWS ? 'C:\\' : '/'
const patterns = patternHelper.parse(
[
`${root}search1/foo/**`,
`${root}search2/bar/**`,
`!${root}search2/bar/**`,
`!${root}search3/baz/**`
],
patternHelper.getOptions({implicitDescendants: false})
)
expect(patternHelper.partialMatch(patterns, `${root}search1`)).toBeTruthy()
expect(
patternHelper.partialMatch(patterns, `${root}search1/foo`)
).toBeTruthy()
expect(patternHelper.partialMatch(patterns, `${root}search2`)).toBeTruthy()
expect(
patternHelper.partialMatch(patterns, `${root}search2/bar`)
).toBeTruthy()
expect(patternHelper.partialMatch(patterns, `${root}search3`)).toBeFalsy()
expect(
patternHelper.partialMatch(patterns, `${root}search3/bar`)
).toBeFalsy()
})
})
Loading

0 comments on commit a11539e

Please sign in to comment.