Skip to content

Commit b45e03b

Browse files
committed
feat: stat directory listing
Closes #47
1 parent 4b143ac commit b45e03b

File tree

6 files changed

+70
-20
lines changed

6 files changed

+70
-20
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,10 @@ type FileStat = {
156156

157157
- Read file metadata.
158158

159+
`FileSystem.statDir(path: string): Promise<FileStat[]>`
160+
161+
- Read metadata of all files in a directory.
162+
159163
`FileSystem.unlink(path: string): Promise<void>`
160164

161165
- Delete a file.

android/src/main/java/com/alpha0010/fs/FileAccessModule.kt

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -373,17 +373,7 @@ class FileAccessModule(reactContext: ReactApplicationContext) :
373373
try {
374374
val file = parsePathToFile(path)
375375
if (file.exists()) {
376-
promise.resolve(
377-
Arguments.makeNativeMap(
378-
mapOf(
379-
"filename" to file.name,
380-
"lastModified" to file.lastModified(),
381-
"path" to file.path,
382-
"size" to file.length(),
383-
"type" to if (file.isDirectory) "directory" else "file",
384-
)
385-
)
386-
)
376+
promise.resolve(statFile(file))
387377
} else {
388378
promise.reject("ENOENT", "'$path' does not exist.")
389379
}
@@ -393,6 +383,21 @@ class FileAccessModule(reactContext: ReactApplicationContext) :
393383
}
394384
}
395385

386+
@ReactMethod
387+
fun statDir(path: String, promise: Promise) {
388+
ioScope.launch {
389+
try {
390+
val fileList = Arguments.createArray()
391+
parsePathToFile(path).listFiles()?.forEach {
392+
fileList.pushMap(statFile(it))
393+
}
394+
promise.resolve(fileList)
395+
} catch (e: Throwable) {
396+
promise.reject(e)
397+
}
398+
}
399+
}
400+
396401
@ReactMethod
397402
fun unlink(path: String, promise: Promise) {
398403
ioScope.launch {
@@ -472,4 +477,16 @@ class FileAccessModule(reactContext: ReactApplicationContext) :
472477
parsePathToFile(path).inputStream()
473478
}
474479
}
480+
481+
private fun statFile(file: File): ReadableMap {
482+
return Arguments.makeNativeMap(
483+
mapOf(
484+
"filename" to file.name,
485+
"lastModified" to file.lastModified(),
486+
"path" to file.path,
487+
"size" to file.length(),
488+
"type" to if (file.isDirectory) "directory" else "file",
489+
)
490+
)
491+
}
475492
}

ios/FileAccess.m

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ @interface RCT_EXTERN_REMAP_MODULE(RNFileAccess, FileAccess, NSObject)
7373
withResolver:(RCTPromiseResolveBlock)resolve
7474
withRejecter:(RCTPromiseRejectBlock)reject)
7575

76+
RCT_EXTERN_METHOD(statDir:(NSString *)path
77+
withResolver:(RCTPromiseResolveBlock)resolve
78+
withRejecter:(RCTPromiseRejectBlock)reject)
79+
7680
RCT_EXTERN_METHOD(unlink:(NSString *)path
7781
withResolver:(RCTPromiseResolveBlock)resolve
7882
withRejecter:(RCTPromiseRejectBlock)reject)

ios/FileAccess.swift

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -276,21 +276,26 @@ class FileAccess: RCTEventEmitter {
276276
func stat(path: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
277277
DispatchQueue.global().async {
278278
do {
279-
let pathUrl = URL(fileURLWithPath: path.path())
280-
let attrs = try FileManager.default.attributesOfItem(atPath: path.path())
281-
resolve([
282-
"filename": pathUrl.lastPathComponent,
283-
"lastModified": 1000 * (attrs[.modificationDate] as! NSDate).timeIntervalSince1970,
284-
"path": pathUrl.path,
285-
"size": attrs[.size],
286-
"type": self.checkIfIsDirectory(path: path).isDirectory ? "directory" : "file"
287-
])
279+
resolve(try self.statFile(path: path))
288280
} catch {
289281
reject("ERR", "Failed to stat '\(path)'.", error)
290282
}
291283
}
292284
}
293285

286+
@objc(statDir:withResolver:withRejecter:)
287+
func statDir(path: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
288+
DispatchQueue.global().async {
289+
do {
290+
try resolve(FileManager.default.contentsOfDirectory(atPath: path.path())
291+
.map { try self.statFile(path: "\(path)/\($0)") }
292+
)
293+
} catch {
294+
reject("ERR", "Failed to list '\(path)'.", error)
295+
}
296+
}
297+
}
298+
294299
@objc(unlink:withResolver:withRejecter:)
295300
func unlink(path: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
296301
DispatchQueue.global().async {
@@ -340,4 +345,16 @@ class FileAccess: RCTEventEmitter {
340345
let isDirectory = isDir.boolValue
341346
return (exists, isDirectory)
342347
}
348+
349+
private func statFile(path: String) throws -> [String : Any?] {
350+
let pathUrl = URL(fileURLWithPath: path.path())
351+
let attrs = try FileManager.default.attributesOfItem(atPath: path.path())
352+
return [
353+
"filename": pathUrl.lastPathComponent,
354+
"lastModified": 1000 * (attrs[.modificationDate] as! NSDate).timeIntervalSince1970,
355+
"path": pathUrl.path,
356+
"size": attrs[.size],
357+
"type": self.checkIfIsDirectory(path: path).isDirectory ? "directory" : "file"
358+
]
359+
}
343360
}

src/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,13 @@ export const FileSystem = {
227227
return FileAccessNative.stat(path);
228228
},
229229

230+
/**
231+
* Read metadata of all files in a directory.
232+
*/
233+
statDir(path: string): Promise<FileStat[]> {
234+
return FileAccessNative.statDir(path);
235+
},
236+
230237
/**
231238
* Delete a file.
232239
*/

src/native.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ type FileAccessType = {
5252
mv(source: string, target: string): Promise<void>;
5353
readFile(path: string, encoding: Encoding): Promise<string>;
5454
stat(path: string): Promise<FileStat>;
55+
statDir(path: string): Promise<FileStat[]>;
5556
unlink(path: string): Promise<void>;
5657
unzip(source: string, target: string): Promise<void>;
5758
writeFile(path: string, data: string, encoding: Encoding): Promise<void>;

0 commit comments

Comments
 (0)