2021-06-22 19:18:21 +02:00
"use strict" ;
var _ _createBinding = ( this && this . _ _createBinding ) || ( Object . create ? ( function ( o , m , k , k2 ) {
if ( k2 === undefined ) k2 = k ;
2025-06-14 22:45:43 +02:00
var desc = Object . getOwnPropertyDescriptor ( m , k ) ;
if ( ! desc || ( "get" in desc ? ! m . _ _esModule : desc . writable || desc . configurable ) ) {
desc = { enumerable : true , get : function ( ) { return m [ k ] ; } } ;
}
Object . defineProperty ( o , k2 , desc ) ;
2021-06-22 19:18:21 +02:00
} ) : ( function ( o , m , k , k2 ) {
if ( k2 === undefined ) k2 = k ;
o [ k2 ] = m [ k ] ;
} ) ) ;
var _ _setModuleDefault = ( this && this . _ _setModuleDefault ) || ( Object . create ? ( function ( o , v ) {
Object . defineProperty ( o , "default" , { enumerable : true , value : v } ) ;
} ) : function ( o , v ) {
o [ "default" ] = v ;
} ) ;
var _ _importStar = ( this && this . _ _importStar ) || function ( mod ) {
if ( mod && mod . _ _esModule ) return mod ;
var result = { } ;
2025-06-14 22:45:43 +02:00
if ( mod != null ) for ( var k in mod ) if ( k !== "default" && Object . prototype . hasOwnProperty . call ( mod , k ) ) _ _createBinding ( result , mod , k ) ;
2021-06-22 19:18:21 +02:00
_ _setModuleDefault ( result , mod ) ;
return result ;
} ;
var _ _importDefault = ( this && this . _ _importDefault ) || function ( mod ) {
return ( mod && mod . _ _esModule ) ? mod : { "default" : mod } ;
} ;
Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
exports . Pattern = void 0 ;
const os = _ _importStar ( require ( "os" ) ) ;
const path = _ _importStar ( require ( "path" ) ) ;
const pathHelper = _ _importStar ( require ( "./internal-path-helper" ) ) ;
const assert _1 = _ _importDefault ( require ( "assert" ) ) ;
const minimatch _1 = require ( "minimatch" ) ;
const internal _match _kind _1 = require ( "./internal-match-kind" ) ;
const internal _path _1 = require ( "./internal-path" ) ;
const IS _WINDOWS = process . platform === 'win32' ;
class Pattern {
constructor ( patternOrNegate , isImplicitPattern = false , segments , homedir ) {
/ * *
* Indicates whether matches should be excluded from the result set
* /
this . negate = false ;
// Pattern overload
let pattern ;
if ( typeof patternOrNegate === 'string' ) {
pattern = patternOrNegate . trim ( ) ;
}
// Segments overload
else {
// Convert to pattern
segments = segments || [ ] ;
2025-06-14 22:45:43 +02:00
( 0 , assert _1 . default ) ( segments . length , ` Parameter 'segments' must not empty ` ) ;
2021-06-22 19:18:21 +02:00
const root = Pattern . getLiteral ( segments [ 0 ] ) ;
2025-06-14 22:45:43 +02:00
( 0 , assert _1 . default ) ( root && pathHelper . hasAbsoluteRoot ( root ) , ` Parameter 'segments' first element must be a root path ` ) ;
2021-06-22 19:18:21 +02:00
pattern = new internal _path _1 . Path ( segments ) . toString ( ) . trim ( ) ;
if ( patternOrNegate ) {
pattern = ` ! ${ pattern } ` ;
}
}
// Negate
while ( pattern . startsWith ( '!' ) ) {
this . negate = ! this . negate ;
pattern = pattern . substr ( 1 ) . trim ( ) ;
}
// Normalize slashes and ensures absolute root
pattern = Pattern . fixupPattern ( pattern , homedir ) ;
// Segments
this . segments = new internal _path _1 . Path ( pattern ) . segments ;
// Trailing slash indicates the pattern should only match directories, not regular files
this . trailingSeparator = pathHelper
. normalizeSeparators ( pattern )
. endsWith ( path . sep ) ;
pattern = pathHelper . safeTrimTrailingSeparator ( pattern ) ;
// Search path (literal path prior to the first glob segment)
let foundGlob = false ;
const searchSegments = this . segments
. map ( x => Pattern . getLiteral ( x ) )
. filter ( x => ! foundGlob && ! ( foundGlob = x === '' ) ) ;
this . searchPath = new internal _path _1 . Path ( searchSegments ) . toString ( ) ;
// Root RegExp (required when determining partial match)
this . rootRegExp = new RegExp ( Pattern . regExpEscape ( searchSegments [ 0 ] ) , IS _WINDOWS ? 'i' : '' ) ;
this . isImplicitPattern = isImplicitPattern ;
// Create minimatch
const minimatchOptions = {
dot : true ,
nobrace : true ,
nocase : IS _WINDOWS ,
nocomment : true ,
noext : true ,
nonegate : true
} ;
pattern = IS _WINDOWS ? pattern . replace ( /\\/g , '/' ) : pattern ;
this . minimatch = new minimatch _1 . Minimatch ( pattern , minimatchOptions ) ;
}
/ * *
* Matches the pattern against the specified path
* /
match ( itemPath ) {
// Last segment is globstar?
if ( this . segments [ this . segments . length - 1 ] === '**' ) {
// Normalize slashes
itemPath = pathHelper . normalizeSeparators ( itemPath ) ;
// 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 ) && 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 } ` ;
}
}
else {
// Normalize slashes and trim unnecessary trailing slash
itemPath = pathHelper . safeTrimTrailingSeparator ( itemPath ) ;
}
// Match
if ( this . minimatch . match ( itemPath ) ) {
return this . trailingSeparator ? internal _match _kind _1 . MatchKind . Directory : internal _match _kind _1 . MatchKind . All ;
}
return internal _match _kind _1 . MatchKind . None ;
}
/ * *
* Indicates whether the pattern may match descendants of the specified path
* /
partialMatch ( itemPath ) {
// Normalize slashes and trim unnecessary trailing slash
itemPath = pathHelper . safeTrimTrailingSeparator ( itemPath ) ;
// matchOne does not handle root path correctly
if ( pathHelper . dirname ( itemPath ) === itemPath ) {
return this . rootRegExp . test ( itemPath ) ;
}
return this . minimatch . matchOne ( itemPath . split ( IS _WINDOWS ? /\\+/ : /\/+/ ) , this . minimatch . set [ 0 ] , true ) ;
}
/ * *
* Escapes glob patterns within a path
* /
static globEscape ( s ) {
return ( IS _WINDOWS ? s : s . replace ( /\\/g , '\\\\' ) ) // escape '\' on Linux/macOS
. replace ( /(\[)(?=[^/]+\])/g , '[[]' ) // escape '[' when ']' follows within the path segment
. replace ( /\?/g , '[?]' ) // escape '?'
. replace ( /\*/g , '[*]' ) ; // escape '*'
}
/ * *
* Normalizes slashes and ensures absolute root
* /
static fixupPattern ( pattern , homedir ) {
// Empty
2025-06-14 22:45:43 +02:00
( 0 , assert _1 . default ) ( pattern , 'pattern cannot be empty' ) ;
2021-06-22 19:18:21 +02:00
// Must not contain `.` segment, unless first segment
// Must not contain `..` segment
const literalSegments = new internal _path _1 . Path ( pattern ) . segments . map ( x => Pattern . getLiteral ( x ) ) ;
2025-06-14 22:45:43 +02:00
( 0 , assert _1 . default ) ( literalSegments . every ( ( x , i ) => ( x !== '.' || i === 0 ) && x !== '..' ) , ` Invalid pattern ' ${ pattern } '. Relative pathing '.' and '..' is not allowed. ` ) ;
2021-06-22 19:18:21 +02:00
// Must not contain globs in root, e.g. Windows UNC path \\foo\b*r
2025-06-14 22:45:43 +02:00
( 0 , assert _1 . default ) ( ! pathHelper . hasRoot ( pattern ) || literalSegments [ 0 ] , ` Invalid pattern ' ${ pattern } '. Root segment must not contain globs. ` ) ;
2021-06-22 19:18:21 +02:00
// Normalize slashes
pattern = pathHelper . normalizeSeparators ( pattern ) ;
// Replace leading `.` segment
if ( pattern === '.' || pattern . startsWith ( ` . ${ path . sep } ` ) ) {
pattern = Pattern . globEscape ( process . cwd ( ) ) + pattern . substr ( 1 ) ;
}
// Replace leading `~` segment
else if ( pattern === '~' || pattern . startsWith ( ` ~ ${ path . sep } ` ) ) {
homedir = homedir || os . homedir ( ) ;
2025-06-14 22:45:43 +02:00
( 0 , assert _1 . default ) ( homedir , 'Unable to determine HOME directory' ) ;
( 0 , assert _1 . default ) ( pathHelper . hasAbsoluteRoot ( homedir ) , ` Expected HOME directory to be a rooted path. Actual ' ${ homedir } ' ` ) ;
2021-06-22 19:18:21 +02:00
pattern = Pattern . globEscape ( homedir ) + pattern . substr ( 1 ) ;
}
// Replace relative drive root, e.g. pattern is C: or C:foo
else if ( IS _WINDOWS &&
( pattern . match ( /^[A-Z]:$/i ) || pattern . match ( /^[A-Z]:[^\\]/i ) ) ) {
let root = pathHelper . ensureAbsoluteRoot ( 'C:\\dummy-root' , pattern . substr ( 0 , 2 ) ) ;
if ( pattern . length > 2 && ! root . endsWith ( '\\' ) ) {
root += '\\' ;
}
pattern = Pattern . globEscape ( root ) + pattern . substr ( 2 ) ;
}
// Replace relative root, e.g. pattern is \ or \foo
else if ( IS _WINDOWS && ( pattern === '\\' || pattern . match ( /^\\[^\\]/ ) ) ) {
let root = pathHelper . ensureAbsoluteRoot ( 'C:\\dummy-root' , '\\' ) ;
if ( ! root . endsWith ( '\\' ) ) {
root += '\\' ;
}
pattern = Pattern . globEscape ( root ) + pattern . substr ( 1 ) ;
}
// Otherwise ensure absolute root
else {
pattern = pathHelper . ensureAbsoluteRoot ( Pattern . globEscape ( process . cwd ( ) ) , pattern ) ;
}
return pathHelper . normalizeSeparators ( pattern ) ;
}
/ * *
* Attempts to unescape a pattern segment to create a literal path segment .
* Otherwise returns empty string .
* /
static getLiteral ( segment ) {
let literal = '' ;
for ( let i = 0 ; i < segment . length ; i ++ ) {
const c = segment [ i ] ;
// Escape
if ( c === '\\' && ! IS _WINDOWS && i + 1 < segment . length ) {
literal += segment [ ++ i ] ;
continue ;
}
// Wildcard
else if ( c === '*' || c === '?' ) {
return '' ;
}
// Character set
else if ( c === '[' && i + 1 < segment . length ) {
let set = '' ;
let closed = - 1 ;
for ( let i2 = i + 1 ; i2 < segment . length ; i2 ++ ) {
const c2 = segment [ i2 ] ;
// Escape
if ( c2 === '\\' && ! IS _WINDOWS && i2 + 1 < segment . length ) {
set += segment [ ++ i2 ] ;
continue ;
}
// Closed
else if ( c2 === ']' ) {
closed = i2 ;
break ;
}
// Otherwise
else {
set += c2 ;
}
}
// Closed?
if ( closed >= 0 ) {
// Cannot convert
if ( set . length > 1 ) {
return '' ;
}
// Convert to literal
if ( set ) {
literal += set ;
i = closed ;
continue ;
}
}
// Otherwise fall thru
}
// Append
literal += c ;
}
return literal ;
}
/ * *
* Escapes regexp special characters
* https : //javascript.info/regexp-escaping
* /
static regExpEscape ( s ) {
return s . replace ( /[[\\^$.|?*+()]/g , '\\$&' ) ;
}
}
exports . Pattern = Pattern ;
//# sourceMappingURL=internal-pattern.js.map