2019-12-31 15:16:18 +00:00
import * as child from 'child_process'
import * as io from '../../io/src/io'
2020-01-09 20:05:31 +00:00
import * as os from 'os'
2019-12-31 15:16:18 +00:00
import * as path from 'path'
2020-01-09 20:05:31 +00:00
import { Globber , DefaultGlobber } from '../src/internal-globber'
import { GlobOptions } from '../src/internal-glob-options'
2019-12-31 15:16:18 +00:00
import { promises as fs } from 'fs'
const IS_WINDOWS = process . platform === 'win32'
/ * *
2020-01-09 20:05:31 +00:00
* These test focus on the ability of globber to find files
2019-12-31 15:16:18 +00:00
* and not on the pattern matching aspect
* /
2020-01-09 20:05:31 +00:00
describe ( 'globber' , ( ) = > {
2019-12-31 15:16:18 +00:00
beforeAll ( async ( ) = > {
await io . rmRF ( getTestTemp ( ) )
} )
2020-01-09 20:05:31 +00:00
it ( 'captures cwd' , async ( ) = > {
// Create the following layout:
// first-cwd
// first-cwd/the-correct-file
// second-cwd
// second-cwd/the-wrong-file
const root = path . join ( getTestTemp ( ) , 'preserves-cwd' )
await fs . mkdir ( path . join ( root , 'first-cwd' ) , { recursive : true } )
await fs . writeFile (
path . join ( root , 'first-cwd' , 'the-correct-file.txt' ) ,
'test file content'
)
await fs . mkdir ( path . join ( root , 'second-cwd' ) , { recursive : true } )
await fs . writeFile (
path . join ( root , 'second-cwd' , 'the-wrong-file.txt' ) ,
'test file content'
)
const originalCwd = process . cwd ( )
try {
process . chdir ( path . join ( root , 'first-cwd' ) )
const globber = await DefaultGlobber . create ( '*' )
process . chdir ( path . join ( root , 'second-cwd' ) )
expect ( globber . getSearchPaths ( ) ) . toEqual ( [ path . join ( root , 'first-cwd' ) ] )
const itemPaths = await globber . glob ( )
expect ( itemPaths ) . toEqual ( [
path . join ( root , 'first-cwd' , 'the-correct-file.txt' )
] )
} finally {
process . chdir ( originalCwd )
}
} )
it ( 'defaults to followSymbolicLinks=true' , async ( ) = > {
// Create the following layout:
// <root>
// <root>/folder-a
// <root>/folder-a/file
// <root>/symDir -> <root>/folder-a
const root = path . join (
getTestTemp ( ) ,
'defaults-to-follow-symbolic-links-true'
)
await fs . mkdir ( path . join ( root , 'folder-a' ) , { recursive : true } )
await fs . writeFile ( path . join ( root , 'folder-a' , 'file' ) , 'test file content' )
await createSymlinkDir (
path . join ( root , 'folder-a' ) ,
path . join ( root , 'symDir' )
)
const itemPaths = await glob ( root , { } )
expect ( itemPaths ) . toEqual ( [
root ,
path . join ( root , 'folder-a' ) ,
path . join ( root , 'folder-a' , 'file' ) ,
path . join ( root , 'symDir' ) ,
path . join ( root , 'symDir' , 'file' )
] )
} )
it ( 'defaults to implicitDescendants=true' , async ( ) = > {
// Create the following layout:
// <root>
// <root>/folder-a
// <root>/folder-a/file
const root = path . join (
getTestTemp ( ) ,
'defaults-to-implicit-descendants-true'
)
await fs . mkdir ( path . join ( root , 'folder-a' ) , { recursive : true } )
await fs . writeFile ( path . join ( root , 'folder-a' , 'file' ) , 'test file content' )
const itemPaths = await glob ( root , { } )
expect ( itemPaths ) . toEqual ( [
root ,
path . join ( root , 'folder-a' ) ,
path . join ( root , 'folder-a' , 'file' )
] )
} )
2021-06-01 19:57:03 +00:00
it ( 'defaults to matchDirectories=true' , async ( ) = > {
// Create the following layout:
// <root>
// <root>/folder-a
// <root>/folder-a/file
const root = path . join ( getTestTemp ( ) , 'defaults-to-match-directories-true' )
await fs . mkdir ( path . join ( root , 'folder-a' ) , { recursive : true } )
await fs . writeFile ( path . join ( root , 'folder-a' , 'file' ) , 'test file content' )
const itemPaths = await glob ( root , { } )
expect ( itemPaths ) . toEqual ( [
root ,
path . join ( root , 'folder-a' ) ,
path . join ( root , 'folder-a' , 'file' )
] )
} )
2021-05-14 18:12:26 +00:00
it ( 'does not match file with trailing slash when implicitDescendants=true' , async ( ) = > {
// Create the following layout:
// <root>
// <root>/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 ( [ ] )
} )
2020-01-09 20:05:31 +00:00
it ( 'defaults to omitBrokenSymbolicLinks=true' , async ( ) = > {
// Create the following layout:
// <root>
// <root>/folder-a
// <root>/folder-a/file
// <root>/symDir -> <root>/no-such
const root = path . join (
getTestTemp ( ) ,
'defaults-to-omit-broken-symbolic-links-true'
)
await fs . mkdir ( path . join ( root , 'folder-a' ) , { recursive : true } )
await fs . writeFile ( path . join ( root , 'folder-a' , 'file' ) , 'test file content' )
await createSymlinkDir (
path . join ( root , 'no-such' ) ,
path . join ( root , 'symDir' )
)
const itemPaths = await glob ( root , { } )
expect ( itemPaths ) . toEqual ( [
root ,
path . join ( root , 'folder-a' ) ,
path . join ( root , 'folder-a' , 'file' )
] )
} )
it ( 'detects cycle when followSymbolicLinks=true' , async ( ) = > {
2019-12-31 15:16:18 +00:00
// Create the following layout:
// <root>
// <root>/file
// <root>/symDir -> <root>
2020-01-09 20:05:31 +00:00
const root = path . join ( getTestTemp ( ) , 'detects-cycle-when-follow-true' )
2019-12-31 15:16:18 +00:00
await fs . mkdir ( root , { recursive : true } )
await fs . writeFile ( path . join ( root , 'file' ) , 'test file content' )
await createSymlinkDir ( root , path . join ( root , 'symDir' ) )
2020-01-09 20:05:31 +00:00
const itemPaths = await glob ( root , { followSymbolicLinks : true } )
2019-12-31 15:16:18 +00:00
expect ( itemPaths ) . toEqual ( [ root , path . join ( root , 'file' ) ] )
} )
2020-01-09 20:05:31 +00:00
it ( 'detects deep cycle starting from middle when followSymbolicLinks=true' , async ( ) = > {
2019-12-31 15:16:18 +00:00
// Create the following layout:
// <root>
// <root>/file-under-root
// <root>/folder-a
// <root>/folder-a/file-under-a
// <root>/folder-a/folder-b
// <root>/folder-a/folder-b/file-under-b
// <root>/folder-a/folder-b/folder-c
// <root>/folder-a/folder-b/folder-c/file-under-c
// <root>/folder-a/folder-b/folder-c/sym-folder -> <root>
const root = path . join (
getTestTemp ( ) ,
2020-01-09 20:05:31 +00:00
'detects-deep-cycle-starting-from-middle-when-follow-true'
2019-12-31 15:16:18 +00:00
)
await fs . mkdir ( path . join ( root , 'folder-a' , 'folder-b' , 'folder-c' ) , {
recursive : true
} )
await fs . writeFile (
path . join ( root , 'file-under-root' ) ,
'test file under root contents'
)
await fs . writeFile (
path . join ( root , 'folder-a' , 'file-under-a' ) ,
'test file under a contents'
)
await fs . writeFile (
path . join ( root , 'folder-a' , 'folder-b' , 'file-under-b' ) ,
'test file under b contents'
)
await fs . writeFile (
path . join ( root , 'folder-a' , 'folder-b' , 'folder-c' , 'file-under-c' ) ,
'test file under c contents'
)
await createSymlinkDir (
root ,
path . join ( root , 'folder-a' , 'folder-b' , 'folder-c' , 'sym-folder' )
)
await fs . stat (
path . join (
root ,
'folder-a' ,
'folder-b' ,
'folder-c' ,
'sym-folder' ,
'file-under-root'
)
)
2020-01-09 20:05:31 +00:00
const itemPaths = await glob ( path . join ( root , 'folder-a' , 'folder-b' ) , {
followSymbolicLinks : true
} )
2019-12-31 15:16:18 +00:00
expect ( itemPaths ) . toEqual ( [
path . join ( root , 'folder-a' , 'folder-b' ) ,
path . join ( root , 'folder-a' , 'folder-b' , 'file-under-b' ) ,
path . join ( root , 'folder-a' , 'folder-b' , 'folder-c' ) ,
path . join ( root , 'folder-a' , 'folder-b' , 'folder-c' , 'file-under-c' ) ,
path . join ( root , 'folder-a' , 'folder-b' , 'folder-c' , 'sym-folder' ) ,
path . join (
root ,
'folder-a' ,
'folder-b' ,
'folder-c' ,
'sym-folder' ,
'file-under-root'
) ,
path . join (
root ,
'folder-a' ,
'folder-b' ,
'folder-c' ,
'sym-folder' ,
'folder-a'
) ,
path . join (
root ,
'folder-a' ,
'folder-b' ,
'folder-c' ,
'sym-folder' ,
'folder-a' ,
'file-under-a'
)
] )
} )
2020-01-09 20:05:31 +00:00
it ( 'detects cycle starting from symlink when followSymbolicLinks=true' , async ( ) = > {
2019-12-31 15:16:18 +00:00
// Create the following layout:
// <root>
// <root>/file
// <root>/symDir -> <root>
const root : string = path . join (
getTestTemp ( ) ,
2020-01-09 20:05:31 +00:00
'detects-cycle-starting-from-symlink-when-follow-true'
2019-12-31 15:16:18 +00:00
)
await fs . mkdir ( root , { recursive : true } )
await fs . writeFile ( path . join ( root , 'file' ) , 'test file content' )
await createSymlinkDir ( root , path . join ( root , 'symDir' ) )
await fs . stat ( path . join ( root , 'symDir' ) )
2020-01-09 20:05:31 +00:00
const itemPaths = await glob ( path . join ( root , 'symDir' ) , {
followSymbolicLinks : true
} )
2019-12-31 15:16:18 +00:00
expect ( itemPaths ) . toEqual ( [
path . join ( root , 'symDir' ) ,
path . join ( root , 'symDir' , 'file' )
] )
} )
2020-01-09 20:05:31 +00:00
it ( 'does not follow symlink when followSymbolicLinks=false' , async ( ) = > {
2019-12-31 15:16:18 +00:00
// Create the following layout:
// <root>
// <root>/realDir
// <root>/realDir/file
// <root>/symDir -> <root>/realDir
const root = path . join (
getTestTemp ( ) ,
'does-not-follow-symlink-when-follow-false'
)
await fs . mkdir ( path . join ( root , 'realDir' ) , { recursive : true } )
await fs . writeFile ( path . join ( root , 'realDir' , 'file' ) , 'test file content' )
await createSymlinkDir (
path . join ( root , 'realDir' ) ,
path . join ( root , 'symDir' )
)
2020-01-09 20:05:31 +00:00
const itemPaths = await glob ( root , { followSymbolicLinks : false } )
2019-12-31 15:16:18 +00:00
expect ( itemPaths ) . toEqual ( [
root ,
path . join ( root , 'realDir' ) ,
path . join ( root , 'realDir' , 'file' ) ,
path . join ( root , 'symDir' )
] )
} )
2020-01-09 20:05:31 +00:00
it ( 'does not follow symlink when search path is symlink and followSymbolicLinks=false' , async ( ) = > {
2019-12-31 15:16:18 +00:00
// Create the following layout:
// realDir
// realDir/file
// symDir -> realDir
const root = path . join (
getTestTemp ( ) ,
'does-not-follow-symlink-when-search-path-is-symlink-and-follow-false'
)
await fs . mkdir ( path . join ( root , 'realDir' ) , { recursive : true } )
await fs . writeFile ( path . join ( root , 'realDir' , 'file' ) , 'test file content' )
await createSymlinkDir (
path . join ( root , 'realDir' ) ,
path . join ( root , 'symDir' )
)
2020-01-09 20:05:31 +00:00
const itemPaths = await glob ( path . join ( root , 'symDir' ) , {
2019-12-31 15:16:18 +00:00
followSymbolicLinks : false
} )
expect ( itemPaths ) . toEqual ( [ path . join ( root , 'symDir' ) ] )
} )
2020-01-09 20:05:31 +00:00
it ( 'does not return broken symlink when follow-true and omit-true' , async ( ) = > {
2019-12-31 15:16:18 +00:00
// Create the following layout:
// <root>
// <root>/brokenSym -> <root>/noSuch
// <root>/realDir
// <root>/realDir/file
// <root>/symDir -> <root>/realDir
2020-01-09 20:05:31 +00:00
const root = path . join (
getTestTemp ( ) ,
'does-not-return-broken-symlink-when-follow-true-and-omit-true'
)
2019-12-31 15:16:18 +00:00
await fs . mkdir ( root , { recursive : true } )
await createSymlinkDir (
path . join ( root , 'noSuch' ) ,
path . join ( root , 'brokenSym' )
)
await fs . mkdir ( path . join ( root , 'realDir' ) , { recursive : true } )
await fs . writeFile ( path . join ( root , 'realDir' , 'file' ) , 'test file content' )
await createSymlinkDir (
path . join ( root , 'realDir' ) ,
path . join ( root , 'symDir' )
)
2020-01-09 20:05:31 +00:00
const itemPaths = await glob ( root , { followSymbolicLinks : true } )
2019-12-31 15:16:18 +00:00
expect ( itemPaths ) . toEqual ( [
root ,
path . join ( root , 'realDir' ) ,
path . join ( root , 'realDir' , 'file' ) ,
path . join ( root , 'symDir' ) ,
path . join ( root , 'symDir' , 'file' )
] )
} )
2020-01-09 20:05:31 +00:00
it ( 'does not return broken symlink when search path is broken symlink and followSymbolicLinks=true' , async ( ) = > {
2019-12-31 15:16:18 +00:00
// Create the following layout:
// <root>
// <root>/brokenSym -> <root>/noSuch
const root = path . join (
getTestTemp ( ) ,
2020-01-09 20:05:31 +00:00
'does-not-return-broken-symlink-when-search-path-is-broken-symlink-and-follow-true'
2019-12-31 15:16:18 +00:00
)
await fs . mkdir ( root , { recursive : true } )
const brokenSymPath = path . join ( root , 'brokenSym' )
await createSymlinkDir ( path . join ( root , 'noSuch' ) , brokenSymPath )
await fs . lstat ( brokenSymPath )
2020-01-09 20:05:31 +00:00
const itemPaths = await glob ( brokenSymPath , { followSymbolicLinks : true } )
2019-12-31 15:16:18 +00:00
expect ( itemPaths ) . toEqual ( [ ] )
} )
2021-06-01 19:57:03 +00:00
it ( 'does not return directories when match directories false' , async ( ) = > {
// Create the following layout:
// <root>/file-1
// <root>/dir-1
// <root>/dir-1/file-2
// <root>/dir-1/dir-2
// <root>/dir-1/dir-2/file-3
const root = path . join (
getTestTemp ( ) ,
'does-not-return-directories-when-match-directories-false'
)
await fs . mkdir ( path . join ( root , 'dir-1' , 'dir-2' ) , { recursive : true } )
await fs . writeFile ( path . join ( root , 'file-1' ) , '' )
await fs . writeFile ( path . join ( root , 'dir-1' , 'file-2' ) , '' )
await fs . writeFile ( path . join ( root , 'dir-1' , 'dir-2' , 'file-3' ) , '' )
const pattern = ` ${ root } ${ path . sep } ** `
expect (
await glob ( pattern , {
matchDirectories : false
} )
) . toEqual ( [
path . join ( root , 'dir-1' , 'dir-2' , 'file-3' ) ,
path . join ( root , 'dir-1' , 'file-2' ) ,
path . join ( root , 'file-1' )
] )
} )
2019-12-31 15:16:18 +00:00
it ( 'does not search paths that are not partial matches' , async ( ) = > {
// Create the following layout:
// <root>
// <root>/realDir
// <root>/realDir/nested
// <root>/realDir/nested/file
// <root>/realDir2
// <root>/realDir2/nested2
// <root>/realDir2/nested2/symDir -> <root>/noSuch
const root = path . join (
getTestTemp ( ) ,
'does-not-search-paths-that-are-not-partial-matches'
)
await fs . mkdir ( path . join ( root , 'realDir' , 'nested' ) , { recursive : true } )
await fs . writeFile (
path . join ( root , 'realDir' , 'nested' , 'file' ) ,
'test file content'
)
await fs . mkdir ( path . join ( root , 'realDir2' , 'nested2' ) , { recursive : true } )
await createSymlinkDir (
path . join ( root , 'noSuch' ) ,
path . join ( root , 'realDir2' , 'nested2' , 'symDir' )
)
2020-01-09 20:05:31 +00:00
const options : GlobOptions = {
2019-12-31 15:16:18 +00:00
followSymbolicLinks : true ,
omitBrokenSymbolicLinks : false
}
// Should throw
try {
2020-01-09 20:05:31 +00:00
await glob ( ` ${ root } /*Dir*/*nested*/* ` , options )
2019-12-31 15:16:18 +00:00
throw new Error ( 'should not reach here' )
} catch ( err ) {
expect ( err . message ) . toMatch ( /broken symbolic link/i )
}
// Not partial match
2020-01-09 20:05:31 +00:00
let itemPaths = await glob ( ` ${ root } /*Dir/*nested*/* ` , options )
2019-12-31 15:16:18 +00:00
expect ( itemPaths ) . toEqual ( [ path . join ( root , 'realDir' , 'nested' , 'file' ) ] )
// Not partial match
2020-01-09 20:05:31 +00:00
itemPaths = await glob ( ` ${ root } /*Dir*/*nested/* ` , options )
2019-12-31 15:16:18 +00:00
expect ( itemPaths ) . toEqual ( [ path . join ( root , 'realDir' , 'nested' , 'file' ) ] )
} )
2020-01-09 20:05:31 +00:00
it ( 'does not throw for broken symlinks that are not matches or partial matches when followSymbolicLinks=true and omitBrokenSymbolicLinks=false' , async ( ) = > {
2019-12-31 15:16:18 +00:00
// Create the following layout:
// <root>
// <root>/realDir
// <root>/realDir/file
// <root>/symDir -> <root>/noSuch
const root = path . join (
getTestTemp ( ) ,
2020-01-09 20:05:31 +00:00
'does-not-throw-for-broken-symlinks-that-are-not-matches-or-partial-matches-when-follow-true-and-omit-false'
2019-12-31 15:16:18 +00:00
)
await fs . mkdir ( path . join ( root , 'realDir' ) , { recursive : true } )
await fs . writeFile ( path . join ( root , 'realDir' , 'file' ) , 'test file content' )
await createSymlinkDir ( path . join ( root , 'noSuch' ) , path . join ( root , 'symDir' ) )
2020-01-09 20:05:31 +00:00
const options : GlobOptions = {
2019-12-31 15:16:18 +00:00
followSymbolicLinks : true ,
omitBrokenSymbolicLinks : false
}
// Match should throw
try {
2020-01-09 20:05:31 +00:00
await glob ( ` ${ root } /* ` , options )
2019-12-31 15:16:18 +00:00
throw new Error ( 'should not reach here' )
} catch ( err ) {
expect ( err . message ) . toMatch ( /broken symbolic link/i )
}
// Partial match should throw
try {
2020-01-09 20:05:31 +00:00
await glob ( ` ${ root } /*/* ` , options )
2019-12-31 15:16:18 +00:00
throw new Error ( 'should not reach here' )
} catch ( err ) {
expect ( err . message ) . toMatch ( /broken symbolic link/i )
}
// Not match or partial match
2020-01-09 20:05:31 +00:00
const itemPaths = await glob ( ` ${ root } /*eal*/* ` , options )
2019-12-31 15:16:18 +00:00
expect ( itemPaths ) . toEqual ( [ path . join ( root , 'realDir' , 'file' ) ] )
} )
2020-01-09 20:05:31 +00:00
it ( 'follows symlink when follow-symbolic-links=true' , async ( ) = > {
2019-12-31 15:16:18 +00:00
// Create the following layout:
// <root>
// <root>/realDir
// <root>/realDir/file
// <root>/symDir -> <root>/realDir
const root = path . join ( getTestTemp ( ) , 'follows-symlink' )
await fs . mkdir ( path . join ( root , 'realDir' ) , { recursive : true } )
await fs . writeFile ( path . join ( root , 'realDir' , 'file' ) , 'test file content' )
await createSymlinkDir (
path . join ( root , 'realDir' ) ,
path . join ( root , 'symDir' )
)
2020-01-09 20:05:31 +00:00
const itemPaths = await glob ( root , { followSymbolicLinks : true } )
2019-12-31 15:16:18 +00:00
expect ( itemPaths ) . toEqual ( [
root ,
path . join ( root , 'realDir' ) ,
path . join ( root , 'realDir' , 'file' ) ,
path . join ( root , 'symDir' ) ,
path . join ( root , 'symDir' , 'file' )
] )
} )
2020-01-09 20:05:31 +00:00
it ( 'follows symlink when search path is symlink and follow-symbolic-links=true' , async ( ) = > {
2019-12-31 15:16:18 +00:00
// Create the following layout:
// realDir
// realDir/file
// symDir -> realDir
const root = path . join (
getTestTemp ( ) ,
2020-01-09 20:05:31 +00:00
'follows-symlink-when-search-path-is-symlink-and-follow-true'
2019-12-31 15:16:18 +00:00
)
await fs . mkdir ( path . join ( root , 'realDir' ) , { recursive : true } )
await fs . writeFile ( path . join ( root , 'realDir' , 'file' ) , 'test file content' )
await createSymlinkDir (
path . join ( root , 'realDir' ) ,
path . join ( root , 'symDir' )
)
2020-01-09 20:05:31 +00:00
const itemPaths = await glob ( path . join ( root , 'symDir' ) , {
followSymbolicLinks : true
} )
2019-12-31 15:16:18 +00:00
expect ( itemPaths ) . toEqual ( [
path . join ( root , 'symDir' ) ,
path . join ( root , 'symDir' , 'file' )
] )
} )
it ( 'returns broken symlink when followSymbolicLinks=false' , async ( ) = > {
// Create the following layout:
// <root>
// <root>/brokenSym -> <root>/noSuch
// <root>/realDir
// <root>/realDir/file
// <root>/symDir -> <root>/realDir
const root = path . join (
getTestTemp ( ) ,
'returns-broken-symlink-when-follow-false'
)
await fs . mkdir ( root , { recursive : true } )
await createSymlinkDir (
path . join ( root , 'noSuch' ) ,
path . join ( root , 'brokenSym' )
)
await fs . mkdir ( path . join ( root , 'realDir' ) , { recursive : true } )
await fs . writeFile ( path . join ( root , 'realDir' , 'file' ) , 'test file content' )
await createSymlinkDir (
path . join ( root , 'realDir' ) ,
path . join ( root , 'symDir' )
)
2020-01-09 20:05:31 +00:00
const itemPaths = await glob ( root , { followSymbolicLinks : false } )
2019-12-31 15:16:18 +00:00
expect ( itemPaths ) . toEqual ( [
root ,
path . join ( root , 'brokenSym' ) ,
path . join ( root , 'realDir' ) ,
path . join ( root , 'realDir' , 'file' ) ,
path . join ( root , 'symDir' )
] )
} )
it ( 'returns broken symlink when search path is broken symlink and followSymbolicLinks=false' , async ( ) = > {
// Create the following layout:
// <root>
// <root>/brokenSym -> <root>/noSuch
const root = path . join (
getTestTemp ( ) ,
'returns-broken-symlink-when-search-path-is-broken-symlink-and-follow-false'
)
await fs . mkdir ( root , { recursive : true } )
const brokenSymPath = path . join ( root , 'brokenSym' )
await createSymlinkDir ( path . join ( root , 'noSuch' ) , brokenSymPath )
2020-01-09 20:05:31 +00:00
const itemPaths = await glob ( brokenSymPath , { followSymbolicLinks : false } )
2019-12-31 15:16:18 +00:00
expect ( itemPaths ) . toEqual ( [ brokenSymPath ] )
} )
it ( 'returns depth first' , async ( ) = > {
// Create the following layout:
// <root>/a-file
// <root>/b-folder
// <root>/b-folder/a-file
// <root>/b-folder/b-folder
// <root>/b-folder/b-folder/file
// <root>/b-folder/c-file
// <root>/c-file
const root = path . join ( getTestTemp ( ) , 'returns-depth-first' )
await fs . mkdir ( path . join ( root , 'b-folder' , 'b-folder' ) , { recursive : true } )
await fs . writeFile ( path . join ( root , 'a-file' ) , 'test a-file content' )
await fs . writeFile (
path . join ( root , 'b-folder' , 'a-file' ) ,
'test b-folder/a-file content'
)
await fs . writeFile (
path . join ( root , 'b-folder' , 'b-folder' , 'file' ) ,
'test b-folder/b-folder/file content'
)
await fs . writeFile (
path . join ( root , 'b-folder' , 'c-file' ) ,
'test b-folder/c-file content'
)
await fs . writeFile ( path . join ( root , 'c-file' ) , 'test c-file content' )
2020-01-09 20:05:31 +00:00
const itemPaths = await glob ( root )
2019-12-31 15:16:18 +00:00
expect ( itemPaths ) . toEqual ( [
root ,
path . join ( root , 'a-file' ) ,
path . join ( root , 'b-folder' ) ,
path . join ( root , 'b-folder' , 'a-file' ) ,
path . join ( root , 'b-folder' , 'b-folder' ) ,
path . join ( root , 'b-folder' , 'b-folder' , 'file' ) ,
path . join ( root , 'b-folder' , 'c-file' ) ,
path . join ( root , 'c-file' )
] )
} )
it ( 'returns descendants' , async ( ) = > {
// Create the following layout:
// <root>/file-1
// <root>/dir-1
// <root>/dir-1/file-2
// <root>/dir-1/dir-2
// <root>/dir-1/dir-2/file-3
const root = path . join ( getTestTemp ( ) , 'returns-descendants' )
await fs . mkdir ( path . join ( root , 'dir-1' , 'dir-2' ) , { recursive : true } )
await fs . writeFile ( path . join ( root , 'file-1' ) , '' )
await fs . writeFile ( path . join ( root , 'dir-1' , 'file-2' ) , '' )
await fs . writeFile ( path . join ( root , 'dir-1' , 'dir-2' , 'file-3' ) , '' )
// When pattern ends with `/**/`
let pattern = ` ${ root } ${ path . sep } ** ${ path . sep } `
expect (
2020-01-09 20:05:31 +00:00
await glob ( pattern , {
2019-12-31 15:16:18 +00:00
implicitDescendants : false
} )
) . toHaveLength ( 3 ) // sanity check
2020-01-09 20:05:31 +00:00
expect ( await glob ( pattern ) ) . toEqual ( [
2019-12-31 15:16:18 +00:00
root ,
path . join ( root , 'dir-1' ) ,
path . join ( root , 'dir-1' , 'dir-2' ) ,
path . join ( root , 'dir-1' , 'dir-2' , 'file-3' ) ,
path . join ( root , 'dir-1' , 'file-2' ) ,
path . join ( root , 'file-1' )
] )
// When pattern ends with something other than `/**/`
pattern = ` ${ root } ${ path . sep } ** ${ path . sep } dir-? `
expect (
2020-01-09 20:05:31 +00:00
await glob ( pattern , {
2019-12-31 15:16:18 +00:00
implicitDescendants : false
} )
) . toHaveLength ( 2 ) // sanity check
2020-01-09 20:05:31 +00:00
expect ( await glob ( pattern ) ) . toEqual ( [
2019-12-31 15:16:18 +00:00
path . join ( root , 'dir-1' ) ,
path . join ( root , 'dir-1' , 'dir-2' ) ,
path . join ( root , 'dir-1' , 'dir-2' , 'file-3' ) ,
path . join ( root , 'dir-1' , 'file-2' )
] )
} )
it ( 'returns directories only when trailing slash and implicit descendants false' , async ( ) = > {
// Create the following layout:
// <root>/file-1
// <root>/dir-1
// <root>/dir-1/file-2
// <root>/dir-1/dir-2
// <root>/dir-1/dir-2/file-3
const root = path . join (
getTestTemp ( ) ,
'returns-directories-only-when-trailing-slash-and-implicit-descendants-false'
)
await fs . mkdir ( path . join ( root , 'dir-1' , 'dir-2' ) , { recursive : true } )
await fs . writeFile ( path . join ( root , 'file-1' ) , '' )
await fs . writeFile ( path . join ( root , 'dir-1' , 'file-2' ) , '' )
await fs . writeFile ( path . join ( root , 'dir-1' , 'dir-2' , 'file-3' ) , '' )
const pattern = ` ${ root } ${ path . sep } ** ${ path . sep } `
2020-01-09 20:05:31 +00:00
expect ( await glob ( pattern ) ) . toHaveLength ( 6 ) // sanity check
2019-12-31 15:16:18 +00:00
expect (
2020-01-09 20:05:31 +00:00
await glob ( pattern , {
2019-12-31 15:16:18 +00:00
implicitDescendants : false
} )
) . toEqual ( [
root ,
path . join ( root , 'dir-1' ) ,
path . join ( root , 'dir-1' , 'dir-2' )
] )
} )
it ( 'returns empty when search path does not exist' , async ( ) = > {
2020-01-09 20:05:31 +00:00
const itemPaths = await glob ( path . join ( getTestTemp ( ) , 'nosuch' ) )
2019-12-31 15:16:18 +00:00
expect ( itemPaths ) . toEqual ( [ ] )
} )
it ( 'returns hidden files' , async ( ) = > {
// Create the following layout:
// <root>
// <root>/.emptyFolder
// <root>/.file
// <root>/.folder
// <root>/.folder/file
const root = path . join ( getTestTemp ( ) , 'returns-hidden-files' )
await createHiddenDirectory ( path . join ( root , '.emptyFolder' ) )
await createHiddenDirectory ( path . join ( root , '.folder' ) )
await createHiddenFile ( path . join ( root , '.file' ) , 'test .file content' )
await fs . writeFile (
path . join ( root , '.folder' , 'file' ) ,
'test .folder/file content'
)
2020-01-09 20:05:31 +00:00
const itemPaths = await glob ( root )
2019-12-31 15:16:18 +00:00
expect ( itemPaths ) . toEqual ( [
root ,
path . join ( root , '.emptyFolder' ) ,
path . join ( root , '.file' ) ,
path . join ( root , '.folder' ) ,
path . join ( root , '.folder' , 'file' )
] )
} )
it ( 'returns normalized paths' , async ( ) = > {
// Create the following layout:
// <root>/hello/world.txt
const root : string = path . join ( getTestTemp ( ) , 'returns-normalized-paths' )
await fs . mkdir ( path . join ( root , 'hello' ) , { recursive : true } )
await fs . writeFile ( path . join ( root , 'hello' , 'world.txt' ) , '' )
2020-01-09 20:05:31 +00:00
const itemPaths = await glob (
2019-12-31 15:16:18 +00:00
` ${ root } ${ path . sep } ${ path . sep } ${ path . sep } hello `
)
expect ( itemPaths ) . toEqual ( [
path . join ( root , 'hello' ) ,
path . join ( root , 'hello' , 'world.txt' )
] )
} )
2020-01-09 20:05:31 +00:00
it ( 'skips comments' , async ( ) = > {
const searchPaths = await getSearchPaths (
` #aaa/* ${ os . EOL } /foo/* ${ os . EOL } #bbb/* ${ os . EOL } /bar/* `
)
const drive = IS_WINDOWS ? process . cwd ( ) . substr ( 0 , 2 ) : ''
expect ( searchPaths ) . toEqual ( [
IS_WINDOWS ? ` ${ drive } \\ foo ` : '/foo' ,
IS_WINDOWS ? ` ${ drive } \\ bar ` : '/bar'
] )
} )
it ( 'skips empty lines' , async ( ) = > {
const searchPaths = await getSearchPaths (
` ${ os . EOL } ${ os . EOL } /foo/* ${ os . EOL } ${ os . EOL } /bar/* ${ os . EOL } /baz/** ${ os . EOL } `
)
const drive = IS_WINDOWS ? process . cwd ( ) . substr ( 0 , 2 ) : ''
expect ( searchPaths ) . toEqual ( [
IS_WINDOWS ? ` ${ drive } \\ foo ` : '/foo' ,
IS_WINDOWS ? ` ${ drive } \\ bar ` : '/bar' ,
IS_WINDOWS ? ` ${ drive } \\ baz ` : '/baz'
] )
} )
it ( 'throws when match broken symlink and followSymbolicLinks=true and omitBrokenSymbolicLinks=false' , async ( ) = > {
2019-12-31 15:16:18 +00:00
// Create the following layout:
// <root>
// <root>/brokenSym -> <root>/noSuch
const root = path . join (
getTestTemp ( ) ,
2020-01-09 20:05:31 +00:00
'throws-when-match-broken-symlink-and-follow-true-and-omit-false'
2019-12-31 15:16:18 +00:00
)
await fs . mkdir ( root , { recursive : true } )
await createSymlinkDir (
path . join ( root , 'noSuch' ) ,
path . join ( root , 'brokenSym' )
)
try {
2020-01-09 20:05:31 +00:00
await glob ( root , {
followSymbolicLinks : true ,
omitBrokenSymbolicLinks : false
} )
2019-12-31 15:16:18 +00:00
throw new Error ( 'Expected tl.find to throw' )
} catch ( err ) {
expect ( err . message ) . toMatch ( /broken symbolic link/ )
}
} )
2020-01-09 20:05:31 +00:00
it ( 'throws when search path is broken symlink and followSymbolicLinks=true and omitBrokenSymbolicLinks=false' , async ( ) = > {
2019-12-31 15:16:18 +00:00
// Create the following layout:
// <root>
// <root>/brokenSym -> <root>/noSuch
const root = path . join (
getTestTemp ( ) ,
2020-01-09 20:05:31 +00:00
'throws-when-search-path-is-broken-symlink-and-follow-true-and-omit-false'
2019-12-31 15:16:18 +00:00
)
await fs . mkdir ( root , { recursive : true } )
const brokenSymPath = path . join ( root , 'brokenSym' )
await createSymlinkDir ( path . join ( root , 'noSuch' ) , brokenSymPath )
await fs . lstat ( brokenSymPath )
try {
2020-01-09 20:05:31 +00:00
await glob ( brokenSymPath , {
followSymbolicLinks : true ,
omitBrokenSymbolicLinks : false
} )
2019-12-31 15:16:18 +00:00
throw new Error ( 'Expected tl.find to throw' )
} catch ( err ) {
expect ( err . message ) . toMatch ( /broken symbolic link/ )
}
} )
} )
async function createHiddenDirectory ( dir : string ) : Promise < void > {
if ( ! path . basename ( dir ) . match ( /^\./ ) ) {
throw new Error ( ` Expected dir ' ${ dir } ' to start with '.'. ` )
}
await fs . mkdir ( dir , { recursive : true } )
if ( IS_WINDOWS ) {
const result = child . spawnSync ( 'attrib.exe' , [ '+H' , dir ] )
if ( result . status !== 0 ) {
const message : string = ( result . output || [ ] ) . join ( ' ' ) . trim ( )
throw new Error (
` Failed to set hidden attribute for directory ' ${ dir } '. ${ message } `
)
}
}
}
async function createHiddenFile ( file : string , content : string ) : Promise < void > {
if ( ! path . basename ( file ) . match ( /^\./ ) ) {
throw new Error ( ` Expected dir ' ${ file } ' to start with '.'. ` )
}
await fs . mkdir ( path . dirname ( file ) , { recursive : true } )
await fs . writeFile ( file , content )
if ( IS_WINDOWS ) {
const result = child . spawnSync ( 'attrib.exe' , [ '+H' , file ] )
if ( result . status !== 0 ) {
const message : string = ( result . output || [ ] ) . join ( ' ' ) . trim ( )
throw new Error (
` Failed to set hidden attribute for file ' ${ file } '. ${ message } `
)
}
}
}
function getTestTemp ( ) : string {
return path . join ( __dirname , '_temp' , 'glob' )
}
/ * *
* Creates a symlink directory on OSX / Linux , and a junction point directory on Windows .
* A symlink directory is not created on Windows since it requires an elevated context .
* /
async function createSymlinkDir ( real : string , link : string ) : Promise < void > {
if ( IS_WINDOWS ) {
await fs . symlink ( real , link , 'junction' )
} else {
await fs . symlink ( real , link )
}
}
2020-01-09 20:05:31 +00:00
async function getSearchPaths ( patterns : string ) : Promise < string [ ] > {
const globber : Globber = await DefaultGlobber . create ( patterns )
return globber . getSearchPaths ( )
}
async function glob (
patterns : string ,
options? : GlobOptions
) : Promise < string [ ] > {
const globber : Globber = await DefaultGlobber . create ( patterns , options )
return await globber . glob ( )
}