5
5
* Use of this source code is governed by an MIT-style license that can be
6
6
* found in the LICENSE file at https://angular.io/license
7
7
*/
8
- import * as fs from 'fs' ;
9
- import * as path from 'path' ;
8
+ import {
9
+ PathLike ,
10
+ Stats ,
11
+ constants ,
12
+ existsSync ,
13
+ mkdirSync ,
14
+ promises as fsPromises ,
15
+ readFileSync ,
16
+ readdirSync ,
17
+ renameSync ,
18
+ rmdirSync ,
19
+ statSync ,
20
+ unlinkSync ,
21
+ writeFileSync ,
22
+ } from 'fs' ;
23
+ import { dirname as pathDirname , join as pathJoin } from 'path' ;
10
24
import { Observable , concat , from as observableFrom , of , throwError } from 'rxjs' ;
11
25
import {
12
26
concatMap ,
13
- ignoreElements ,
14
27
map ,
15
28
mergeMap ,
16
29
publish ,
@@ -39,6 +52,16 @@ interface ChokidarWatcher {
39
52
close ( ) : void ;
40
53
}
41
54
55
+ async function exists ( path : PathLike ) : Promise < boolean > {
56
+ try {
57
+ await fsPromises . access ( path , constants . F_OK ) ;
58
+
59
+ return true ;
60
+ } catch {
61
+ return false ;
62
+ }
63
+ }
64
+
42
65
// This will only be initialized if the watch() method is called.
43
66
// Otherwise chokidar appears only in type positions, and shouldn't be referenced
44
67
// in the JavaScript output.
@@ -58,128 +81,83 @@ function loadFSWatcher() {
58
81
}
59
82
}
60
83
61
- type FsFunction0 < R > = ( cb : ( err ?: Error | null , result ?: R ) => void ) => void ;
62
- type FsFunction1 < R , T1 > = ( p1 : T1 , cb : ( err ?: Error | null , result ?: R ) => void ) => void ;
63
- type FsFunction2 < R , T1 , T2 >
64
- = ( p1 : T1 , p2 : T2 , cb : ( err ?: Error | null , result ?: R ) => void ) => void ;
65
-
66
-
67
- function _callFs < R > ( fn : FsFunction0 < R > ) : Observable < R > ;
68
- function _callFs < R , T1 > ( fn : FsFunction1 < R , T1 > , p1 : T1 ) : Observable < R > ;
69
- function _callFs < R , T1 , T2 > ( fn : FsFunction2 < R , T1 , T2 > , p1 : T1 , p2 : T2 ) : Observable < R > ;
70
-
71
- function _callFs < ResultT > ( fn : Function , ...args : { } [ ] ) : Observable < ResultT > {
72
- return new Observable ( obs => {
73
- fn ( ...args , ( err ?: Error | null , result ?: ResultT ) => {
74
- if ( err ) {
75
- obs . error ( err ) ;
76
- } else {
77
- obs . next ( result ) ;
78
- obs . complete ( ) ;
79
- }
80
- } ) ;
81
- } ) ;
82
- }
83
-
84
-
85
84
/**
86
85
* An implementation of the Virtual FS using Node as the background. There are two versions; one
87
86
* synchronous and one asynchronous.
88
87
*/
89
- export class NodeJsAsyncHost implements virtualFs . Host < fs . Stats > {
88
+ export class NodeJsAsyncHost implements virtualFs . Host < Stats > {
90
89
get capabilities ( ) : virtualFs . HostCapabilities {
91
90
return { synchronous : false } ;
92
91
}
93
92
94
93
write ( path : Path , content : virtualFs . FileBuffer ) : Observable < void > {
95
- return _callFs < void , string , fs . MakeDirectoryOptions > (
96
- fs . mkdir ,
97
- getSystemPath ( dirname ( path ) ) ,
98
- { recursive : true } ,
99
- ) . pipe (
100
- mergeMap ( ( ) => _callFs < void , string , Uint8Array > (
101
- fs . writeFile ,
102
- getSystemPath ( path ) ,
103
- new Uint8Array ( content ) ,
104
- ) ) ,
105
- ) ;
94
+ return observableFrom ( fsPromises . mkdir ( getSystemPath ( dirname ( path ) ) , { recursive : true } ) )
95
+ . pipe (
96
+ mergeMap ( ( ) => fsPromises . writeFile ( getSystemPath ( path ) , content ) ) ,
97
+ ) ;
106
98
}
107
99
108
100
read ( path : Path ) : Observable < virtualFs . FileBuffer > {
109
- return _callFs ( fs . readFile , getSystemPath ( path ) ) . pipe (
110
- map ( buffer => new Uint8Array ( buffer ) . buffer as virtualFs . FileBuffer ) ,
111
- ) ;
101
+ return observableFrom ( fsPromises . readFile ( getSystemPath ( path ) ) )
102
+ . pipe (
103
+ map ( buffer => new Uint8Array ( buffer ) . buffer as virtualFs . FileBuffer ) ,
104
+ ) ;
112
105
}
113
106
114
107
delete ( path : Path ) : Observable < void > {
115
108
return this . isDirectory ( path ) . pipe (
116
- mergeMap ( isDirectory => {
109
+ mergeMap ( async isDirectory => {
117
110
if ( isDirectory ) {
118
- const allFiles : Path [ ] = [ ] ;
119
- const allDirs : Path [ ] = [ ] ;
120
- const _recurseList = ( path : Path ) => {
121
- for ( const fragment of fs . readdirSync ( getSystemPath ( path ) ) ) {
122
- if ( fs . statSync ( getSystemPath ( join ( path , fragment ) ) ) . isDirectory ( ) ) {
123
- _recurseList ( join ( path , fragment ) ) ;
124
- allDirs . push ( join ( path , fragment ) ) ;
111
+ const recursiveDelete = async ( dirPath : string ) => {
112
+ for ( const fragment of ( await fsPromises . readdir ( dirPath ) ) ) {
113
+ const sysPath = pathJoin ( dirPath , fragment ) ;
114
+ const stats = await fsPromises . stat ( sysPath ) ;
115
+
116
+ if ( stats . isDirectory ( ) ) {
117
+ await recursiveDelete ( sysPath ) ;
118
+ await fsPromises . rmdir ( sysPath ) ;
125
119
} else {
126
- allFiles . push ( join ( path , fragment ) ) ;
120
+ await fsPromises . unlink ( sysPath ) ;
127
121
}
128
122
}
129
123
} ;
130
- _recurseList ( path ) ;
131
124
132
- return concat (
133
- observableFrom ( allFiles ) . pipe (
134
- mergeMap ( p => _callFs ( fs . unlink , getSystemPath ( p ) ) ) ,
135
- ignoreElements ( ) ,
136
- ) ,
137
- observableFrom ( allDirs ) . pipe (
138
- concatMap ( p => _callFs ( fs . rmdir , getSystemPath ( p ) ) ) ,
139
- ) ,
140
- ) ;
125
+ await recursiveDelete ( getSystemPath ( path ) ) ;
141
126
} else {
142
- return _callFs ( fs . unlink , getSystemPath ( path ) ) ;
127
+ await fsPromises . unlink ( getSystemPath ( path ) ) ;
143
128
}
144
129
} ) ,
145
- map ( ( ) => undefined ) ,
146
130
) ;
147
131
}
148
132
149
133
rename ( from : Path , to : Path ) : Observable < void > {
150
- return _callFs ( fs . rename , getSystemPath ( from ) , getSystemPath ( to ) ) ;
134
+ return observableFrom ( fsPromises . rename ( getSystemPath ( from ) , getSystemPath ( to ) ) ) ;
151
135
}
152
136
153
137
list ( path : Path ) : Observable < PathFragment [ ] > {
154
- return _callFs < string [ ] , string > ( fs . readdir , getSystemPath ( path ) ) . pipe (
138
+ return observableFrom ( fsPromises . readdir ( getSystemPath ( path ) ) ) . pipe (
155
139
map ( ( names ) => names . map ( name => fragment ( name ) ) ) ,
156
140
) ;
157
141
}
158
142
159
143
exists ( path : Path ) : Observable < boolean > {
160
- // Exists is a special case because it cannot error.
161
- return new Observable ( obs => {
162
- fs . exists ( path , exists => {
163
- obs . next ( exists ) ;
164
- obs . complete ( ) ;
165
- } ) ;
166
- } ) ;
144
+ return observableFrom ( exists ( path ) ) ;
167
145
}
168
146
169
147
isDirectory ( path : Path ) : Observable < boolean > {
170
- return _callFs ( fs . stat , getSystemPath ( path ) ) . pipe (
148
+ return this . stat ( path ) . pipe (
171
149
map ( stat => stat . isDirectory ( ) ) ,
172
150
) ;
173
151
}
174
152
isFile ( path : Path ) : Observable < boolean > {
175
- return _callFs ( fs . stat , getSystemPath ( path ) ) . pipe (
153
+ return this . stat ( path ) . pipe (
176
154
map ( stat => stat . isFile ( ) ) ,
177
155
) ;
178
156
}
179
157
180
158
// Some hosts may not support stat.
181
- stat ( path : Path ) : Observable < virtualFs . Stats < fs . Stats > > | null {
182
- return _callFs ( fs . stat , getSystemPath ( path ) ) ;
159
+ stat ( path : Path ) : Observable < virtualFs . Stats < Stats > > {
160
+ return observableFrom ( fsPromises . stat ( getSystemPath ( path ) ) ) ;
183
161
}
184
162
185
163
// Some hosts may not support watching.
@@ -226,23 +204,23 @@ export class NodeJsAsyncHost implements virtualFs.Host<fs.Stats> {
226
204
/**
227
205
* An implementation of the Virtual FS using Node as the backend, synchronously.
228
206
*/
229
- export class NodeJsSyncHost implements virtualFs . Host < fs . Stats > {
207
+ export class NodeJsSyncHost implements virtualFs . Host < Stats > {
230
208
get capabilities ( ) : virtualFs . HostCapabilities {
231
209
return { synchronous : true } ;
232
210
}
233
211
234
212
write ( path : Path , content : virtualFs . FileBuffer ) : Observable < void > {
235
213
return new Observable ( obs => {
236
- fs . mkdirSync ( getSystemPath ( dirname ( path ) ) , { recursive : true } ) ;
237
- fs . writeFileSync ( getSystemPath ( path ) , new Uint8Array ( content ) ) ;
214
+ mkdirSync ( getSystemPath ( dirname ( path ) ) , { recursive : true } ) ;
215
+ writeFileSync ( getSystemPath ( path ) , new Uint8Array ( content ) ) ;
238
216
obs . next ( ) ;
239
217
obs . complete ( ) ;
240
218
} ) ;
241
219
}
242
220
243
221
read ( path : Path ) : Observable < virtualFs . FileBuffer > {
244
222
return new Observable ( obs => {
245
- const buffer = fs . readFileSync ( getSystemPath ( path ) ) ;
223
+ const buffer = readFileSync ( getSystemPath ( path ) ) ;
246
224
247
225
obs . next ( new Uint8Array ( buffer ) . buffer as virtualFs . FileBuffer ) ;
248
226
obs . complete ( ) ;
@@ -253,9 +231,9 @@ export class NodeJsSyncHost implements virtualFs.Host<fs.Stats> {
253
231
return this . isDirectory ( path ) . pipe (
254
232
concatMap ( isDir => {
255
233
if ( isDir ) {
256
- const dirPaths = fs . readdirSync ( getSystemPath ( path ) ) ;
234
+ const dirPaths = readdirSync ( getSystemPath ( path ) ) ;
257
235
const rmDirComplete = new Observable < void > ( ( obs ) => {
258
- fs . rmdirSync ( getSystemPath ( path ) ) ;
236
+ rmdirSync ( getSystemPath ( path ) ) ;
259
237
obs . complete ( ) ;
260
238
} ) ;
261
239
@@ -265,7 +243,7 @@ export class NodeJsSyncHost implements virtualFs.Host<fs.Stats> {
265
243
) ;
266
244
} else {
267
245
try {
268
- fs . unlinkSync ( getSystemPath ( path ) ) ;
246
+ unlinkSync ( getSystemPath ( path ) ) ;
269
247
} catch ( err ) {
270
248
return throwError ( err ) ;
271
249
}
@@ -279,24 +257,24 @@ export class NodeJsSyncHost implements virtualFs.Host<fs.Stats> {
279
257
rename ( from : Path , to : Path ) : Observable < void > {
280
258
return new Observable ( obs => {
281
259
const toSystemPath = getSystemPath ( to ) ;
282
- fs . mkdirSync ( path . dirname ( toSystemPath ) , { recursive : true } ) ;
283
- fs . renameSync ( getSystemPath ( from ) , toSystemPath ) ;
260
+ mkdirSync ( pathDirname ( toSystemPath ) , { recursive : true } ) ;
261
+ renameSync ( getSystemPath ( from ) , toSystemPath ) ;
284
262
obs . next ( ) ;
285
263
obs . complete ( ) ;
286
264
} ) ;
287
265
}
288
266
289
267
list ( path : Path ) : Observable < PathFragment [ ] > {
290
268
return new Observable ( obs => {
291
- const names = fs . readdirSync ( getSystemPath ( path ) ) ;
269
+ const names = readdirSync ( getSystemPath ( path ) ) ;
292
270
obs . next ( names . map ( name => fragment ( name ) ) ) ;
293
271
obs . complete ( ) ;
294
272
} ) ;
295
273
}
296
274
297
275
exists ( path : Path ) : Observable < boolean > {
298
276
return new Observable ( obs => {
299
- obs . next ( fs . existsSync ( getSystemPath ( path ) ) ) ;
277
+ obs . next ( existsSync ( getSystemPath ( path ) ) ) ;
300
278
obs . complete ( ) ;
301
279
} ) ;
302
280
}
@@ -311,9 +289,9 @@ export class NodeJsSyncHost implements virtualFs.Host<fs.Stats> {
311
289
}
312
290
313
291
// Some hosts may not support stat.
314
- stat ( path : Path ) : Observable < virtualFs . Stats < fs . Stats > > {
292
+ stat ( path : Path ) : Observable < virtualFs . Stats < Stats > > {
315
293
return new Observable ( obs => {
316
- obs . next ( fs . statSync ( getSystemPath ( path ) ) ) ;
294
+ obs . next ( statSync ( getSystemPath ( path ) ) ) ;
317
295
obs . complete ( ) ;
318
296
} ) ;
319
297
}
0 commit comments