@@ -20,19 +20,19 @@ const Rejected = 2;
20
20
type PendingRecord = { |
21
21
status : 0 ,
22
22
value : Wakeable ,
23
- cache : Array < mixed > ,
23
+ cache : null ,
24
24
| } ;
25
25
26
26
type ResolvedRecord < T > = { |
27
27
status : 1 ,
28
28
value : T ,
29
- cache : Array < mixed > ,
29
+ cache : null | Array < mixed > ,
30
30
| } ;
31
31
32
32
type RejectedRecord = { |
33
33
status : 2 ,
34
34
value : mixed ,
35
- cache : Array < mixed > ,
35
+ cache : null ,
36
36
| } ;
37
37
38
38
type Record < T > = PendingRecord | ResolvedRecord < T > | RejectedRecord ;
@@ -41,7 +41,7 @@ function createRecordFromThenable<T>(thenable: Thenable<T>): Record<T> {
41
41
const record : Record < T > = {
42
42
status : Pending ,
43
43
value : thenable ,
44
- cache : [ ] ,
44
+ cache : null ,
45
45
} ;
46
46
thenable . then (
47
47
value => {
@@ -62,9 +62,10 @@ function createRecordFromThenable<T>(thenable: Thenable<T>): Record<T> {
62
62
return record ;
63
63
}
64
64
65
- function readRecordValue < T > (record: Record< T > ): T {
65
+ function readRecord < T > (record: Record< T > ): ResolvedRecord < T > {
66
66
if ( record . status === Resolved ) {
67
- return record . value ;
67
+ // This is just a type refinement.
68
+ return record ;
68
69
} else {
69
70
throw record . value ;
70
71
}
@@ -91,7 +92,122 @@ function checkPathInDev(path: string) {
91
92
}
92
93
}
93
94
94
- function createReadFileCache ( ) : Map < string , Record < Buffer > > {
95
+ function createAccessMap ( ) : Map < string , Array < number | Record < void > >> {
96
+ return new Map ( ) ;
97
+ }
98
+
99
+ export function access(path: string, mode?: number): void {
100
+ checkPathInDev ( path ) ;
101
+ if ( mode == null ) {
102
+ mode = 0 ; // fs.constants.F_OK
103
+ }
104
+ const map = unstable_getCacheForType(createAccessMap);
105
+ let accessCache = map.get(path);
106
+ if (!accessCache) {
107
+ accessCache = [ ] ;
108
+ map . set ( path , accessCache ) ;
109
+ }
110
+ let record;
111
+ for (let i = 0; i < accessCache . length ; i += 2 ) {
112
+ const cachedMode : number = ( accessCache [ i ] : any ) ;
113
+ if ( mode = = = cachedMode ) {
114
+ const cachedRecord : Record < void > = (accessCache[i + 1]: any);
115
+ record = cachedRecord;
116
+ break;
117
+ }
118
+ }
119
+ if ( ! record ) {
120
+ const thenable = fs . access ( path , mode ) ;
121
+ record = createRecordFromThenable ( thenable ) ;
122
+ accessCache . push ( mode , record ) ;
123
+ }
124
+ readRecord(record); // No return value.
125
+ }
126
+
127
+ function createLstatMap ( ) : Map < string , Array < boolean | Record < mixed > >> {
128
+ return new Map ( ) ;
129
+ }
130
+
131
+ export function lstat(path: string, options?: { bigint ? : boolean } ): mixed {
132
+ checkPathInDev ( path ) ;
133
+ let bigint = false ;
134
+ if ( options && options . bigint ) {
135
+ bigint = true ;
136
+ }
137
+ const map = unstable_getCacheForType ( createLstatMap ) ;
138
+ let lstatCache = map . get ( path ) ;
139
+ if ( ! lstatCache ) {
140
+ lstatCache = [ ] ;
141
+ map . set ( path , lstatCache ) ;
142
+ }
143
+ let record ;
144
+ for ( let i = 0 ; i < lstatCache . length ; i += 2 ) {
145
+ const cachedBigint : boolean = ( lstatCache [ i ] : any ) ;
146
+ if ( bigint === cachedBigint ) {
147
+ const cachedRecord : Record < void > = ( lstatCache [ i + 1 ] : any ) ;
148
+ record = cachedRecord ;
149
+ break ;
150
+ }
151
+ }
152
+ if ( ! record ) {
153
+ const thenable = fs . lstat ( path , { bigint} ) ;
154
+ record = createRecordFromThenable ( thenable ) ;
155
+ lstatCache . push ( bigint , record ) ;
156
+ }
157
+ const stats = readRecord ( record ) . value ;
158
+ return stats ;
159
+ }
160
+
161
+ function createReaddirMap(): Map<
162
+ string ,
163
+ Array < string | boolean | Record < mixed > > ,
164
+ > {
165
+ return new Map ( ) ;
166
+ }
167
+
168
+ export function readdir(
169
+ path: string,
170
+ options?: string | { encoding ? : string , withFileTypes ? : boolean } ,
171
+ ): mixed {
172
+ checkPathInDev ( path ) ;
173
+ let encoding = 'utf8' ;
174
+ let withFileTypes = false ;
175
+ if ( typeof options === 'string' ) {
176
+ encoding = options ;
177
+ } else if ( options != null ) {
178
+ if ( options . encoding ) {
179
+ encoding = options . encoding ;
180
+ }
181
+ if ( options . withFileTypes ) {
182
+ withFileTypes = true ;
183
+ }
184
+ }
185
+ const map = unstable_getCacheForType(createReaddirMap);
186
+ let readdirCache = map.get(path);
187
+ if (!readdirCache) {
188
+ readdirCache = [ ] ;
189
+ map . set ( path , readdirCache ) ;
190
+ }
191
+ let record;
192
+ for (let i = 0; i < readdirCache . length ; i += 3 ) {
193
+ const cachedEncoding : string = ( readdirCache [ i ] : any ) ;
194
+ const cachedWithFileTypes : boolean = ( readdirCache [ i + 1 ] : any ) ;
195
+ if ( encoding = = = cachedEncoding && withFileTypes = = = cachedWithFileTypes ) {
196
+ const cachedRecord : Record < void > = (readdirCache[i + 2]: any);
197
+ record = cachedRecord;
198
+ break;
199
+ }
200
+ }
201
+ if ( ! record ) {
202
+ const thenable = fs . readdir ( path , { encoding, withFileTypes} ) ;
203
+ record = createRecordFromThenable ( thenable ) ;
204
+ readdirCache . push ( encoding , withFileTypes , record ) ;
205
+ }
206
+ const files = readRecord(record).value;
207
+ return files;
208
+ }
209
+
210
+ function createReadFileMap ( ) : Map < string , Record < Buffer > > {
95
211
return new Map ( ) ;
96
212
}
97
213
@@ -106,15 +222,16 @@ export function readFile(
106
222
signal ? : mixed , // We'll have our own signal
107
223
} ,
108
224
): string | Buffer {
109
- const map = unstable_getCacheForType ( createReadFileCache ) ;
110
225
checkPathInDev ( path ) ;
226
+ const map = unstable_getCacheForType ( createReadFileMap ) ;
111
227
let record = map . get ( path ) ;
112
228
if ( ! record ) {
113
229
const thenable = fs . readFile ( path ) ;
114
230
record = createRecordFromThenable ( thenable ) ;
115
231
map . set ( path , record ) ;
116
232
}
117
- const buffer : Buffer = readRecordValue ( record ) ;
233
+ const resolvedRecord = readRecord ( record ) ;
234
+ const buffer : Buffer = resolvedRecord . value ;
118
235
if ( ! options ) {
119
236
return buffer ;
120
237
}
@@ -136,7 +253,7 @@ export function readFile(
136
253
if ( typeof encoding !== 'string' ) {
137
254
return buffer ;
138
255
}
139
- const textCache = record . cache ;
256
+ const textCache = resolvedRecord . cache || ( resolvedRecord . cache = [ ] ) ;
140
257
for ( let i = 0 ; i < textCache . length ; i += 2 ) {
141
258
if ( textCache [ i ] === encoding ) {
142
259
return ( textCache [ i + 1 ] : any ) ;
@@ -146,3 +263,119 @@ export function readFile(
146
263
textCache . push ( encoding , text ) ;
147
264
return text ;
148
265
}
266
+
267
+ function createReadlinkMap(): Map< string , Array < string | Record < mixed > >> {
268
+ return new Map ( ) ;
269
+ }
270
+
271
+ export function readlink(
272
+ path: string,
273
+ options?: string | { encoding ? : string } ,
274
+ ): mixed {
275
+ checkPathInDev ( path ) ;
276
+ let encoding = 'utf8' ;
277
+ if ( typeof options === 'string' ) {
278
+ encoding = options ;
279
+ } else if ( options != null ) {
280
+ if ( options . encoding ) {
281
+ encoding = options . encoding ;
282
+ }
283
+ }
284
+ const map = unstable_getCacheForType ( createReadlinkMap ) ;
285
+ let readlinkCache = map . get ( path ) ;
286
+ if ( ! readlinkCache ) {
287
+ readlinkCache = [ ] ;
288
+ map . set ( path , readlinkCache ) ;
289
+ }
290
+ let record ;
291
+ for ( let i = 0 ; i < readlinkCache . length ; i += 2 ) {
292
+ const cachedEncoding : string = ( readlinkCache [ i ] : any ) ;
293
+ if ( encoding === cachedEncoding ) {
294
+ const cachedRecord : Record < void > = ( readlinkCache [ i + 1 ] : any ) ;
295
+ record = cachedRecord ;
296
+ break ;
297
+ }
298
+ }
299
+ if ( ! record ) {
300
+ const thenable = fs . readlink ( path , { encoding} ) ;
301
+ record = createRecordFromThenable ( thenable ) ;
302
+ readlinkCache . push ( encoding , record ) ;
303
+ }
304
+ const linkString = readRecord ( record ) . value ;
305
+ return linkString ;
306
+ }
307
+
308
+ function createRealpathMap(): Map< string , Array < string | Record < mixed > >> {
309
+ return new Map ( ) ;
310
+ }
311
+
312
+ export function realpath(
313
+ path: string,
314
+ options?: string | { encoding ? : string } ,
315
+ ): mixed {
316
+ checkPathInDev ( path ) ;
317
+ let encoding = 'utf8' ;
318
+ if ( typeof options === 'string' ) {
319
+ encoding = options ;
320
+ } else if ( options != null ) {
321
+ if ( options . encoding ) {
322
+ encoding = options . encoding ;
323
+ }
324
+ }
325
+ const map = unstable_getCacheForType ( createRealpathMap ) ;
326
+ let realpathCache = map . get ( path ) ;
327
+ if ( ! realpathCache ) {
328
+ realpathCache = [ ] ;
329
+ map . set ( path , realpathCache ) ;
330
+ }
331
+ let record ;
332
+ for ( let i = 0 ; i < realpathCache . length ; i += 2 ) {
333
+ const cachedEncoding : string = ( realpathCache [ i ] : any ) ;
334
+ if ( encoding === cachedEncoding ) {
335
+ const cachedRecord : Record < void > = ( realpathCache [ i + 1 ] : any ) ;
336
+ record = cachedRecord ;
337
+ break ;
338
+ }
339
+ }
340
+ if ( ! record ) {
341
+ const thenable = fs . realpath ( path , { encoding} ) ;
342
+ record = createRecordFromThenable ( thenable ) ;
343
+ realpathCache . push ( encoding , record ) ;
344
+ }
345
+ const resolvedPath = readRecord ( record ) . value ;
346
+ return resolvedPath ;
347
+ }
348
+
349
+ function createStatMap(): Map< string , Array < boolean | Record < mixed > >> {
350
+ return new Map ( ) ;
351
+ }
352
+
353
+ export function stat(path: string, options?: { bigint ? : boolean } ): mixed {
354
+ checkPathInDev ( path ) ;
355
+ let bigint = false ;
356
+ if ( options && options . bigint ) {
357
+ bigint = true ;
358
+ }
359
+ const map = unstable_getCacheForType ( createStatMap ) ;
360
+ let statCache = map . get ( path ) ;
361
+ if ( ! statCache ) {
362
+ statCache = [ ] ;
363
+ map . set ( path , statCache ) ;
364
+ }
365
+ let record ;
366
+ for ( let i = 0 ; i < statCache . length ; i += 2 ) {
367
+ const cachedBigint : boolean = ( statCache [ i ] : any ) ;
368
+ if ( bigint === cachedBigint ) {
369
+ const cachedRecord : Record < void > = ( statCache [ i + 1 ] : any ) ;
370
+ record = cachedRecord ;
371
+ break ;
372
+ }
373
+ }
374
+ if ( ! record ) {
375
+ const thenable = fs . stat ( path , { bigint} ) ;
376
+ record = createRecordFromThenable ( thenable ) ;
377
+ statCache . push ( bigint , record ) ;
378
+ }
379
+ const stats = readRecord ( record ) . value ;
380
+ return stats ;
381
+ }
0 commit comments