1
- import { promises as fs } from 'node:fs' ;
2
- import * as path from 'node:path' ;
3
-
1
+ import { toFileDirURL , toFilePathOrHref , toFileURL , urlDirname } from '@cspell/url' ;
4
2
import type { GlobMatchRule , GlobPatternNormalized , GlobPatternWithRoot } from 'cspell-glob' ;
5
3
import { GlobMatcher } from 'cspell-glob' ;
4
+ import { getDefaultVirtualFs , VFileSystem } from 'cspell-io' ;
6
5
7
- import { isDefined , isParentOf , makeRelativeTo } from './helpers .js' ;
6
+ import { isDefined , isParentOf , makeRelativeTo } from './utils .js' ;
8
7
9
8
export interface IsIgnoredExResult {
10
9
glob : string | undefined ;
@@ -20,56 +19,58 @@ export interface IsIgnoredExResult {
20
19
export class GitIgnoreFile {
21
20
constructor (
22
21
readonly matcher : GlobMatcher ,
23
- readonly gitignore : string ,
22
+ readonly gitignore : string | URL ,
24
23
) { }
25
24
26
25
get root ( ) : string {
27
26
return this . matcher . root ;
28
27
}
29
28
30
- isIgnored ( file : string ) : boolean {
31
- return this . matcher . match ( file ) ;
29
+ isIgnored ( file : string | URL ) : boolean {
30
+ return this . matcher . match ( file . toString ( ) ) ;
32
31
}
33
32
34
- isIgnoredEx ( file : string ) : IsIgnoredExResult {
35
- const m = this . matcher . matchEx ( file ) ;
33
+ isIgnoredEx ( file : string | URL ) : IsIgnoredExResult {
34
+ const m = this . matcher . matchEx ( file . toString ( ) ) ;
36
35
const { matched } = m ;
37
36
const partial : Partial < GlobMatchRule > = m ;
38
37
const pattern : Partial < GlobPatternNormalized > | undefined = partial . pattern ;
39
38
const glob = pattern ?. rawGlob ?? partial . glob ;
40
39
const root = partial . root ;
41
40
const line = pattern ?. line ;
42
- return { glob, matched, gitIgnoreFile : this . gitignore , root, line } ;
41
+ return { glob, matched, gitIgnoreFile : toFilePathOrHref ( this . gitignore ) , root, line } ;
43
42
}
44
43
45
44
getGlobPatters ( ) : GlobPatternWithRoot [ ] {
46
45
return this . matcher . patterns ;
47
46
}
48
47
49
- getGlobs ( relativeTo : string ) : string [ ] {
48
+ getGlobs ( relativeToDir : string | URL ) : string [ ] {
50
49
return this . getGlobPatters ( )
51
- . map ( ( pat ) => globToString ( pat , relativeTo ) )
50
+ . map ( ( pat ) => globToString ( pat , relativeToDir ) )
52
51
. filter ( isDefined ) ;
53
52
}
54
53
55
- static parseGitignore ( content : string , gitignoreFilename : string ) : GitIgnoreFile {
56
- const options = { root : path . dirname ( gitignoreFilename ) } ;
54
+ static parseGitignore ( content : string , gitignoreFilename : string | URL ) : GitIgnoreFile {
55
+ gitignoreFilename = toFileURL ( gitignoreFilename ) ;
56
+ const root = urlDirname ( gitignoreFilename ) . href ;
57
+ const options = { root } ;
57
58
const globs = content
58
59
. split ( / \r ? \n / g)
59
60
. map ( ( glob , index ) => ( {
60
61
glob : glob . replace ( / ^ # .* / , '' ) ,
61
- source : gitignoreFilename ,
62
+ source : gitignoreFilename . toString ( ) ,
62
63
line : index + 1 ,
63
64
} ) )
64
65
. filter ( ( g ) => ! ! g . glob ) ;
65
66
const globMatcher = new GlobMatcher ( globs , options ) ;
66
67
return new GitIgnoreFile ( globMatcher , gitignoreFilename ) ;
67
68
}
68
69
69
- static async loadGitignore ( gitignore : string ) : Promise < GitIgnoreFile > {
70
- gitignore = path . resolve ( gitignore ) ;
71
- const content = await fs . readFile ( gitignore , 'utf8' ) ;
72
- return this . parseGitignore ( content , gitignore ) ;
70
+ static async loadGitignore ( gitignore : string | URL , vfs : VFileSystem ) : Promise < GitIgnoreFile > {
71
+ gitignore = toFileURL ( gitignore ) ;
72
+ const file = await vfs . readFile ( gitignore , 'utf8' ) ;
73
+ return this . parseGitignore ( file . getText ( ) , gitignore ) ;
73
74
}
74
75
}
75
76
@@ -81,7 +82,7 @@ export class GitIgnoreHierarchy {
81
82
mustBeHierarchical ( gitIgnoreChain ) ;
82
83
}
83
84
84
- isIgnored ( file : string ) : boolean {
85
+ isIgnored ( file : string | URL ) : boolean {
85
86
for ( const git of this . gitIgnoreChain ) {
86
87
if ( git . isIgnored ( file ) ) return true ;
87
88
}
@@ -94,7 +95,7 @@ export class GitIgnoreHierarchy {
94
95
* @param file - fsPath to check.
95
96
* @returns IsIgnoredExResult of the match or undefined if there was no match.
96
97
*/
97
- isIgnoredEx ( file : string ) : IsIgnoredExResult | undefined {
98
+ isIgnoredEx ( file : string | URL ) : IsIgnoredExResult | undefined {
98
99
for ( const git of this . gitIgnoreChain ) {
99
100
const r = git . isIgnoredEx ( file ) ;
100
101
if ( r . matched ) return r ;
@@ -112,10 +113,12 @@ export class GitIgnoreHierarchy {
112
113
}
113
114
}
114
115
115
- export async function loadGitIgnore ( dir : string ) : Promise < GitIgnoreFile | undefined > {
116
- const file = path . join ( dir , '.gitignore' ) ;
116
+ export async function loadGitIgnore ( dir : string | URL , vfs ?: VFileSystem ) : Promise < GitIgnoreFile | undefined > {
117
+ dir = toFileDirURL ( dir ) ;
118
+ vfs ??= getDefaultVirtualFs ( ) . getFS ( dir ) ;
119
+ const file = new URL ( '.gitignore' , dir ) ;
117
120
try {
118
- return await GitIgnoreFile . loadGitignore ( file ) ;
121
+ return await GitIgnoreFile . loadGitignore ( file , vfs ) ;
119
122
} catch {
120
123
return undefined ;
121
124
}
@@ -131,12 +134,16 @@ function mustBeHierarchical(chain: GitIgnoreFile[]): void {
131
134
}
132
135
}
133
136
134
- function globToString ( glob : GlobPatternWithRoot , relativeTo : string ) : string | undefined {
137
+ function globToString ( glob : GlobPatternWithRoot , relativeToDir : string | URL ) : string | undefined {
135
138
if ( glob . isGlobalPattern ) return glob . glob ;
136
139
137
- if ( isParentOf ( glob . root , relativeTo ) && glob . glob . startsWith ( '**/' ) ) return glob . glob ;
140
+ relativeToDir = toFileDirURL ( relativeToDir ) ;
141
+
142
+ const root = toFileDirURL ( glob . root ) ;
143
+
144
+ if ( isParentOf ( root , relativeToDir ) && glob . glob . startsWith ( '**/' ) ) return glob . glob ;
138
145
139
- const base = makeRelativeTo ( glob . root , relativeTo ) ;
146
+ const base = makeRelativeTo ( root , relativeToDir ) ;
140
147
if ( base === undefined ) return undefined ;
141
148
return ( base ? base + '/' : '' ) + glob . glob ;
142
149
}
0 commit comments