Skip to content

Commit a11539e

Browse files
authored
1 parent a94e244 commit a11539e

16 files changed

+3065
-0
lines changed

packages/glob/__tests__/glob.test.ts

Lines changed: 671 additions & 0 deletions
Large diffs are not rendered by default.

packages/glob/__tests__/internal-path-helper.test.ts

Lines changed: 640 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import * as path from 'path'
2+
import {Path} from '../src/internal-path'
3+
4+
const IS_WINDOWS = process.platform === 'win32'
5+
6+
describe('path', () => {
7+
it('constructs from rooted path', () => {
8+
assertPath(`/`, `${path.sep}`, [path.sep])
9+
assertPath(`/foo`, `${path.sep}foo`, [path.sep, 'foo'])
10+
if (IS_WINDOWS) {
11+
assertPath(`C:\\foo`, `C:\\foo`, ['C:\\', 'foo'])
12+
assertPath(`C:foo`, `C:foo`, ['C:', 'foo'])
13+
assertPath(`\\\\foo\\bar\\baz`, `\\\\foo\\bar\\baz`, [
14+
'\\\\foo\\bar',
15+
'baz'
16+
])
17+
}
18+
})
19+
20+
it('constructs from rooted segments', () => {
21+
assertPath([`/`], `${path.sep}`, [path.sep])
22+
assertPath([`/`, `foo`], `${path.sep}foo`, [path.sep, 'foo'])
23+
if (IS_WINDOWS) {
24+
assertPath([`C:\\`, `foo`], `C:\\foo`, ['C:\\', 'foo'])
25+
assertPath([`C:`, `foo`], `C:foo`, ['C:', 'foo'])
26+
assertPath([`\\\\foo\\bar`, `baz`], `\\\\foo\\bar\\baz`, [
27+
'\\\\foo\\bar',
28+
'baz'
29+
])
30+
}
31+
})
32+
33+
it('constructs from relative path', () => {
34+
assertPath(`foo`, `foo`, ['foo'])
35+
assertPath(`foo/bar`, `foo${path.sep}bar`, ['foo', 'bar'])
36+
})
37+
38+
it('constructs from relative segments', () => {
39+
assertPath([`foo`], `foo`, ['foo'])
40+
assertPath([`foo`, `bar`], `foo${path.sep}bar`, ['foo', 'bar'])
41+
})
42+
43+
it('normalizes slashes', () => {
44+
assertPath(
45+
`/foo///bar${path.sep}${path.sep}${path.sep}baz`,
46+
`${path.sep}foo${path.sep}bar${path.sep}baz`,
47+
[path.sep, 'foo', 'bar', 'baz']
48+
)
49+
})
50+
51+
it('preserves relative pathing', () => {
52+
assertPath(
53+
'/foo/../bar/./baz',
54+
`${path.sep}foo${path.sep}..${path.sep}bar${path.sep}.${path.sep}baz`,
55+
[path.sep, 'foo', '..', 'bar', '.', 'baz']
56+
)
57+
})
58+
59+
it('trims unnecessary trailing slash', () => {
60+
assertPath('/', path.sep, [path.sep])
61+
assertPath('/foo/', `${path.sep}foo`, [path.sep, 'foo'])
62+
assertPath('foo/', 'foo', ['foo'])
63+
assertPath('foo/bar/', `foo${path.sep}bar`, ['foo', 'bar'])
64+
if (IS_WINDOWS) {
65+
assertPath('\\', '\\', ['\\'])
66+
assertPath('C:\\', 'C:\\', ['C:\\'])
67+
assertPath('C:\\foo\\', 'C:\\foo', ['C:\\', 'foo'])
68+
assertPath('C:foo\\', 'C:foo', ['C:', 'foo'])
69+
assertPath('\\\\computer\\share\\', '\\\\computer\\share', [
70+
'\\\\computer\\share'
71+
])
72+
assertPath('\\\\computer\\share\\foo', '\\\\computer\\share\\foo', [
73+
'\\\\computer\\share',
74+
'foo'
75+
])
76+
assertPath('\\\\computer\\share\\foo\\', '\\\\computer\\share\\foo', [
77+
'\\\\computer\\share',
78+
'foo'
79+
])
80+
}
81+
})
82+
})
83+
84+
function assertPath(
85+
itemPath: string | string[],
86+
expectedPath: string,
87+
expectedSegments: string[]
88+
): void {
89+
const actual = new Path(itemPath)
90+
expect(actual.toString()).toBe(expectedPath)
91+
expect(actual.segments).toEqual(expectedSegments)
92+
}
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
import * as path from 'path'
2+
import * as patternHelper from '../src/internal-pattern-helper'
3+
import {MatchKind} from '../src/internal-match-kind'
4+
import {IS_WINDOWS} from '../../io/src/io-util'
5+
6+
describe('pattern-helper', () => {
7+
it('getSearchPaths omits negate search paths', () => {
8+
const root = IS_WINDOWS ? 'C:\\' : '/'
9+
const patterns = patternHelper.parse(
10+
[
11+
`${root}search1/foo/**`,
12+
`${root}search2/bar/**`,
13+
`!${root}search3/baz/**`
14+
],
15+
patternHelper.getOptions()
16+
)
17+
const searchPaths = patternHelper.getSearchPaths(patterns)
18+
expect(searchPaths).toEqual([
19+
`${root}search1${path.sep}foo`,
20+
`${root}search2${path.sep}bar`
21+
])
22+
})
23+
24+
it('getSearchPaths omits search path when ancestor is also a search path', () => {
25+
if (IS_WINDOWS) {
26+
const patterns = patternHelper.parse(
27+
[
28+
'C:\\Search1\\Foo\\**',
29+
'C:\\sEARCH1\\fOO\\bar\\**',
30+
'C:\\sEARCH1\\foo\\bar',
31+
'C:\\Search2\\**',
32+
'C:\\Search3\\Foo\\Bar\\**',
33+
'C:\\sEARCH3\\fOO\\bAR\\**'
34+
],
35+
patternHelper.getOptions()
36+
)
37+
const searchPaths = patternHelper.getSearchPaths(patterns)
38+
expect(searchPaths).toEqual([
39+
'C:\\Search1\\Foo',
40+
'C:\\Search2',
41+
'C:\\Search3\\Foo\\Bar'
42+
])
43+
} else {
44+
const patterns = patternHelper.parse(
45+
[
46+
'/search1/foo/**',
47+
'/search1/foo/bar/**',
48+
'/search2/foo/bar',
49+
'/search2/**',
50+
'/search3/foo/bar/**',
51+
'/search3/foo/bar/**'
52+
],
53+
patternHelper.getOptions()
54+
)
55+
const searchPaths = patternHelper.getSearchPaths(patterns)
56+
expect(searchPaths).toEqual([
57+
'/search1/foo',
58+
'/search2',
59+
'/search3/foo/bar'
60+
])
61+
}
62+
})
63+
64+
it('match supports interleaved exclude patterns', () => {
65+
const root = IS_WINDOWS ? 'C:\\' : '/'
66+
const itemPaths = [
67+
`${root}solution1/proj1/proj1.proj`,
68+
`${root}solution1/proj1/README.txt`,
69+
`${root}solution1/proj2/proj2.proj`,
70+
`${root}solution1/proj2/README.txt`,
71+
`${root}solution1/solution1.sln`,
72+
`${root}solution2/proj1/proj1.proj`,
73+
`${root}solution2/proj1/README.txt`,
74+
`${root}solution2/proj2/proj2.proj`,
75+
`${root}solution2/proj2/README.txt`,
76+
`${root}solution2/solution2.sln`
77+
]
78+
const patterns = patternHelper.parse(
79+
[
80+
`${root}**/*.proj`, // include all proj files
81+
`${root}**/README.txt`, // include all README files
82+
`!${root}**/solution2/**`, // exclude the solution 2 folder entirely
83+
`${root}**/*.sln`, // include all sln files
84+
`!${root}**/proj2/README.txt` // exclude proj2 README files
85+
],
86+
patternHelper.getOptions({implicitDescendants: false})
87+
)
88+
const matched = itemPaths.filter(
89+
x => patternHelper.match(patterns, x) === MatchKind.All
90+
)
91+
expect(matched).toEqual([
92+
`${root}solution1/proj1/proj1.proj`,
93+
`${root}solution1/proj1/README.txt`,
94+
`${root}solution1/proj2/proj2.proj`,
95+
`${root}solution1/solution1.sln`,
96+
`${root}solution2/solution2.sln`
97+
])
98+
})
99+
100+
it('match supports excluding directories', () => {
101+
const root = IS_WINDOWS ? 'C:\\' : '/'
102+
const itemPaths = [
103+
root,
104+
`${root}foo`,
105+
`${root}foo/bar`,
106+
`${root}foo/bar/baz`
107+
]
108+
const patterns = patternHelper.parse(
109+
[
110+
`${root}foo/**`, // include all files and directories
111+
`!${root}foo/**/` // exclude directories
112+
],
113+
patternHelper.getOptions({implicitDescendants: false})
114+
)
115+
const matchKinds = itemPaths.map(x => patternHelper.match(patterns, x))
116+
expect(matchKinds).toEqual([
117+
MatchKind.None,
118+
MatchKind.File,
119+
MatchKind.File,
120+
MatchKind.File
121+
])
122+
})
123+
124+
it('match supports including directories only', () => {
125+
const root = IS_WINDOWS ? 'C:\\' : '/'
126+
const itemPaths = [
127+
root,
128+
`${root}foo/`,
129+
`${root}foo/bar`,
130+
`${root}foo/bar/baz`
131+
]
132+
const patterns = patternHelper.parse(
133+
[
134+
`${root}foo/**/` // include directories only
135+
],
136+
patternHelper.getOptions({implicitDescendants: false})
137+
)
138+
const matchKinds = itemPaths.map(x => patternHelper.match(patterns, x))
139+
expect(matchKinds).toEqual([
140+
MatchKind.None,
141+
MatchKind.Directory,
142+
MatchKind.Directory,
143+
MatchKind.Directory
144+
])
145+
})
146+
147+
it('parse skips comments', () => {
148+
const patterns = patternHelper.parse(
149+
['# comment 1', ' # comment 2', '!#hello-world.txt'],
150+
patternHelper.getOptions({implicitDescendants: false})
151+
)
152+
expect(patterns).toHaveLength(1)
153+
expect(patterns[0].negate).toBeTruthy()
154+
expect(patterns[0].segments.reverse()[0]).toEqual('#hello-world.txt')
155+
})
156+
157+
it('parse skips empty patterns', () => {
158+
const patterns = patternHelper.parse(
159+
['', ' ', 'hello-world.txt'],
160+
patternHelper.getOptions({implicitDescendants: false})
161+
)
162+
expect(patterns).toHaveLength(1)
163+
expect(patterns[0].segments.reverse()[0]).toEqual('hello-world.txt')
164+
})
165+
166+
it('partialMatch skips negate patterns', () => {
167+
const root = IS_WINDOWS ? 'C:\\' : '/'
168+
const patterns = patternHelper.parse(
169+
[
170+
`${root}search1/foo/**`,
171+
`${root}search2/bar/**`,
172+
`!${root}search2/bar/**`,
173+
`!${root}search3/baz/**`
174+
],
175+
patternHelper.getOptions({implicitDescendants: false})
176+
)
177+
expect(patternHelper.partialMatch(patterns, `${root}search1`)).toBeTruthy()
178+
expect(
179+
patternHelper.partialMatch(patterns, `${root}search1/foo`)
180+
).toBeTruthy()
181+
expect(patternHelper.partialMatch(patterns, `${root}search2`)).toBeTruthy()
182+
expect(
183+
patternHelper.partialMatch(patterns, `${root}search2/bar`)
184+
).toBeTruthy()
185+
expect(patternHelper.partialMatch(patterns, `${root}search3`)).toBeFalsy()
186+
expect(
187+
patternHelper.partialMatch(patterns, `${root}search3/bar`)
188+
).toBeFalsy()
189+
})
190+
})

0 commit comments

Comments
 (0)