remove doc + saf
This commit is contained in:
@@ -4,13 +4,13 @@ import type {
|
||||
FileEntry,
|
||||
Folder,
|
||||
FolderInfo,
|
||||
PickDirectoryOptions,
|
||||
} from './safDirectory.types';
|
||||
import { __setSafWalkImpl, yieldToMainThread } from './safWalk';
|
||||
export { listFoldersChunked, yieldToMainThread, DEFAULT_WALK_BUDGET_MS } from './safWalk';
|
||||
|
||||
// Bootstrap: wire the real SAF implementation for the Expo runtime.
|
||||
__setSafWalkImpl({
|
||||
list: listDirectory,
|
||||
list: listDirectoryEntries,
|
||||
info: getFolderInfo,
|
||||
yield: yieldToMainThread,
|
||||
});
|
||||
@@ -20,43 +20,23 @@ export async function pickDirectory(initialUri?: string): Promise<Folder | null>
|
||||
const directory = await Directory.pickDirectoryAsync(initialUri);
|
||||
if (!directory || !directory.uri) return null;
|
||||
return toFolder({ uri: directory.uri, name: directory.name, exists: directory.exists });
|
||||
} catch {
|
||||
} catch (error) {
|
||||
console.warn('[safDirectory] pickDirectory failed:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function listDirectory(directoryUri: string): DirectoryEntry[] {
|
||||
export function listDirectoryEntries(directoryUri: string): DirectoryEntry[] {
|
||||
const directory = new Directory(directoryUri);
|
||||
if (!directory.exists) return [];
|
||||
try {
|
||||
return directory.list().map(toEntry);
|
||||
} catch {
|
||||
} catch (error) {
|
||||
console.warn('[safDirectory] listDirectoryEntries failed:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export function listFolders(directoryUri: string, options: PickDirectoryOptions = {}): Folder[] {
|
||||
const { recursive = false, includeRoot = false } = options;
|
||||
if (!recursive) {
|
||||
return listDirectory(directoryUri).filter((entry): entry is Folder => entry.isDirectory);
|
||||
}
|
||||
|
||||
const result: Folder[] = [];
|
||||
if (includeRoot) {
|
||||
result.push({ ...getFolderInfo(directoryUri), isDirectory: true });
|
||||
}
|
||||
const visit = (uri: string) => {
|
||||
for (const entry of listDirectory(uri)) {
|
||||
if (entry.isDirectory) {
|
||||
result.push(entry);
|
||||
visit(entry.uri);
|
||||
}
|
||||
}
|
||||
};
|
||||
visit(directoryUri);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function getFolderInfo(directoryUri: string): FolderInfo {
|
||||
const directory = new Directory(directoryUri);
|
||||
return {
|
||||
@@ -66,6 +46,7 @@ export function getFolderInfo(directoryUri: string): FolderInfo {
|
||||
};
|
||||
}
|
||||
|
||||
/** Creates a directory. Intentionally lets exceptions propagate (permissions, quota, etc). */
|
||||
export function createDirectory(directoryUri: string, name: string): Folder {
|
||||
const directory = new Directory(Paths.join(directoryUri, name));
|
||||
directory.create({ idempotent: true, intermediates: true });
|
||||
@@ -73,7 +54,10 @@ export function createDirectory(directoryUri: string, name: string): Folder {
|
||||
}
|
||||
|
||||
export function fileFromUri(uri: string): FileEntry {
|
||||
const file = new File(uri);
|
||||
return toFileEntry(new File(uri));
|
||||
}
|
||||
|
||||
function toFileEntry(file: File): FileEntry {
|
||||
return {
|
||||
uri: file.uri,
|
||||
name: file.name,
|
||||
@@ -87,21 +71,12 @@ export function fileFromUri(uri: string): FileEntry {
|
||||
}
|
||||
|
||||
function toEntry(item: Directory | File): DirectoryEntry {
|
||||
if (item instanceof Directory) {
|
||||
return toFolder({ uri: item.uri, name: item.name, exists: item.exists });
|
||||
}
|
||||
return {
|
||||
uri: item.uri,
|
||||
name: item.name,
|
||||
isDirectory: false,
|
||||
extension: item.extension,
|
||||
exists: item.exists,
|
||||
size: item.size,
|
||||
type: item.type,
|
||||
lastModified: item.lastModified,
|
||||
};
|
||||
return item instanceof Directory
|
||||
? toFolder({ uri: item.uri, name: item.name, exists: item.exists })
|
||||
: toFileEntry(item);
|
||||
}
|
||||
|
||||
// Perf: avoids constructing a Directory when all fields are already provided by the caller.
|
||||
function toFolder({ uri, name, exists }: { uri: string; name?: string; exists?: boolean }): Folder {
|
||||
const directory = exists === undefined ? new Directory(uri) : null;
|
||||
return {
|
||||
@@ -110,4 +85,4 @@ function toFolder({ uri, name, exists }: { uri: string; name?: string; exists?:
|
||||
isDirectory: true,
|
||||
exists: exists ?? directory?.exists,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ export type Folder = {
|
||||
uri: string;
|
||||
name: string;
|
||||
isDirectory: true;
|
||||
/** `undefined` when neither caller nor Directory fallback provided a value. */
|
||||
exists?: boolean;
|
||||
};
|
||||
|
||||
|
||||
@@ -52,19 +52,31 @@ export async function listFoldersChunked(
|
||||
}
|
||||
|
||||
let lastYield = Date.now();
|
||||
const visit = async (uri: string) => {
|
||||
if (Date.now() - lastYield >= budgetMs) {
|
||||
lastYield = Date.now();
|
||||
await impl.yield();
|
||||
}
|
||||
// Stack of Folders identified by uri; push in reverse so the first-listed
|
||||
// descendant is popped first, preserving the DFS pre-order of the recursive
|
||||
// traversal (a folder's subtree is fully explored before its later siblings).
|
||||
const stack: Folder[] = impl
|
||||
.list(directoryUri)
|
||||
.filter((entry): entry is Folder => entry.isDirectory)
|
||||
.reverse();
|
||||
while (stack.length > 0) {
|
||||
if (Date.now() - lastYield >= budgetMs) {
|
||||
lastYield = Date.now();
|
||||
await impl.yield();
|
||||
}
|
||||
for (const entry of impl.list(uri)) {
|
||||
if (entry.isDirectory) {
|
||||
result.push(entry);
|
||||
await visit(entry.uri);
|
||||
}
|
||||
const folder = stack.pop()!;
|
||||
result.push(folder);
|
||||
const children = impl
|
||||
.list(folder.uri)
|
||||
.filter((entry): entry is Folder => entry.isDirectory);
|
||||
for (let i = children.length - 1; i >= 0; i--) {
|
||||
stack.push(children[i]);
|
||||
}
|
||||
};
|
||||
await visit(directoryUri);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user