213 lines
7.0 KiB
TypeScript
213 lines
7.0 KiB
TypeScript
import ExpoFileSystem from './ExpoFileSystem';
|
||
import type { DownloadOptions, PathInfo } from './ExpoFileSystem.types';
|
||
import { PathUtilities } from './pathUtilities';
|
||
import { FileSystemReadableStreamSource, FileSystemWritableSink } from './streams';
|
||
|
||
export class Paths extends PathUtilities {
|
||
/**
|
||
* A property containing the cache directory – a place to store files that can be deleted by the system when the device runs low on storage.
|
||
*/
|
||
static get cache() {
|
||
return new Directory(ExpoFileSystem.cacheDirectory);
|
||
}
|
||
|
||
/**
|
||
* A property containing the bundle directory – the directory where assets bundled with the application are stored.
|
||
*/
|
||
static get bundle() {
|
||
return new Directory(ExpoFileSystem.bundleDirectory);
|
||
}
|
||
|
||
/**
|
||
* A property containing the document directory – a place to store files that are safe from being deleted by the system.
|
||
*/
|
||
static get document() {
|
||
return new Directory(ExpoFileSystem.documentDirectory);
|
||
}
|
||
static get appleSharedContainers() {
|
||
const containers: Record<string, string> = ExpoFileSystem.appleSharedContainers ?? {};
|
||
const result: Record<string, Directory> = {};
|
||
for (const appGroupId in containers) {
|
||
if (containers[appGroupId]) {
|
||
result[appGroupId] = new Directory(containers[appGroupId]);
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* A property that represents the total space on device's internal storage, represented in bytes.
|
||
*/
|
||
static get totalDiskSpace() {
|
||
return ExpoFileSystem.totalDiskSpace;
|
||
}
|
||
|
||
/**
|
||
* A property that represents the available space on device's internal storage, represented in bytes.
|
||
*/
|
||
static get availableDiskSpace() {
|
||
return ExpoFileSystem.availableDiskSpace;
|
||
}
|
||
|
||
/**
|
||
* Returns an object that indicates if the specified path represents a directory.
|
||
*/
|
||
static info(...uris: string[]): PathInfo {
|
||
return ExpoFileSystem.info(uris.join('/'));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Represents a file on the filesystem.
|
||
*
|
||
* A `File` instance can be created for any path, and does not need to exist on the filesystem during creation.
|
||
*
|
||
* The constructor accepts an array of strings that are joined to create the file URI. The first argument can also be a `Directory` instance (like `Paths.cache`) or a `File` instance (which creates a new reference to the same file).
|
||
* @example
|
||
* ```ts
|
||
* const file = new File(Paths.cache, "subdirName", "file.txt");
|
||
* ```
|
||
*/
|
||
export class File extends ExpoFileSystem.FileSystemFile implements Blob {
|
||
/**
|
||
* Creates an instance of a file. It can be created for any path, and does not need to exist on the filesystem during creation.
|
||
*
|
||
* The constructor accepts an array of strings that are joined to create the file URI. The first argument can also be a `Directory` instance (like `Paths.cache`) or a `File` instance (which creates a new reference to the same file).
|
||
* @param uris An array of: `file:///` string URIs, `File` instances, and `Directory` instances representing an arbitrary location on the file system.
|
||
* @example
|
||
* ```ts
|
||
* const file = new File(Paths.cache, "subdirName", "file.txt");
|
||
* ```
|
||
*/
|
||
constructor(...uris: (string | File | Directory)[]) {
|
||
super(Paths.join(...uris));
|
||
this.validatePath();
|
||
}
|
||
|
||
/*
|
||
* Directory containing the file.
|
||
*/
|
||
get parentDirectory() {
|
||
return new Directory(Paths.dirname(this.uri));
|
||
}
|
||
|
||
/**
|
||
* File extension.
|
||
* @example '.png'
|
||
*/
|
||
get extension() {
|
||
return Paths.extname(this.uri);
|
||
}
|
||
|
||
/**
|
||
* File name. Includes the extension.
|
||
*/
|
||
get name() {
|
||
return Paths.basename(this.uri);
|
||
}
|
||
|
||
readableStream() {
|
||
return new ReadableStream(new FileSystemReadableStreamSource(super.open()));
|
||
}
|
||
|
||
writableStream() {
|
||
return new WritableStream<Uint8Array>(new FileSystemWritableSink(super.open()));
|
||
}
|
||
|
||
async arrayBuffer(): Promise<ArrayBuffer> {
|
||
const bytes = await this.bytes();
|
||
return bytes.buffer as ArrayBuffer;
|
||
}
|
||
|
||
stream(): ReadableStream<Uint8Array<ArrayBuffer>> {
|
||
return this.readableStream();
|
||
}
|
||
|
||
slice(start?: number, end?: number, contentType?: string): Blob {
|
||
return new Blob([this.bytesSync().slice(start, end)], { type: contentType });
|
||
}
|
||
}
|
||
|
||
// Cannot use `static` keyword in class declaration because of a runtime error.
|
||
File.downloadFileAsync = async function downloadFileAsync(
|
||
url: string,
|
||
to: File | Directory,
|
||
options?: DownloadOptions
|
||
) {
|
||
const outputURI = await ExpoFileSystem.downloadFileAsync(url, to, options);
|
||
return new File(outputURI);
|
||
};
|
||
|
||
File.pickFileAsync = async function (initialUri?: string, mimeType?: string) {
|
||
const file = (await ExpoFileSystem.pickFileAsync(initialUri, mimeType)).uri;
|
||
return new File(file);
|
||
};
|
||
|
||
/**
|
||
* Represents a directory on the filesystem.
|
||
*
|
||
* A `Directory` instance can be created for any path, and does not need to exist on the filesystem during creation.
|
||
*
|
||
* The constructor accepts an array of strings that are joined to create the directory URI. The first argument can also be a `Directory` instance (like `Paths.cache`).
|
||
* @example
|
||
* ```ts
|
||
* const directory = new Directory(Paths.cache, "subdirName");
|
||
* ```
|
||
*/
|
||
export class Directory extends ExpoFileSystem.FileSystemDirectory {
|
||
/**
|
||
* Creates an instance of a directory. It can be created for any path, and does not need to exist on the filesystem during creation.
|
||
*
|
||
* The constructor accepts an array of strings that are joined to create the directory URI. The first argument can also be a `Directory` instance (like `Paths.cache`).
|
||
* @param uris An array of: `file:///` string URIs, `File` instances, and `Directory` instances representing an arbitrary location on the file system.
|
||
* @example
|
||
* ```ts
|
||
* const directory = new Directory(Paths.cache, "subdirName");
|
||
* ```
|
||
*/
|
||
constructor(...uris: (string | File | Directory)[]) {
|
||
super(Paths.join(...uris));
|
||
this.validatePath();
|
||
}
|
||
|
||
/*
|
||
* Directory containing the file.
|
||
*/
|
||
get parentDirectory() {
|
||
return new Directory(Paths.join(this.uri, '..'));
|
||
}
|
||
|
||
/**
|
||
* Lists the contents of a directory.
|
||
* Calling this method if the parent directory does not exist will throw an error.
|
||
* @returns An array of `Directory` and `File` instances.
|
||
*/
|
||
override list(): (Directory | File)[] {
|
||
// We need to wrap it in the JS File/Directory classes, and returning SharedObjects in lists is not supported yet on Android.
|
||
return super
|
||
.listAsRecords()
|
||
.map(({ isDirectory, uri }) => (isDirectory ? new Directory(uri) : new File(uri)));
|
||
}
|
||
|
||
/**
|
||
* Directory name.
|
||
*/
|
||
get name() {
|
||
return Paths.basename(this.uri);
|
||
}
|
||
|
||
createFile(name: string, mimeType: string | null): File {
|
||
// Wrapping with the JS child class for additional, JS-only methods.
|
||
return new File(super.createFile(name, mimeType).uri);
|
||
}
|
||
|
||
createDirectory(name: string): Directory {
|
||
return new Directory(super.createDirectory(name).uri);
|
||
}
|
||
}
|
||
|
||
Directory.pickDirectoryAsync = async function (initialUri?: string) {
|
||
const directory = (await ExpoFileSystem.pickDirectoryAsync(initialUri)).uri;
|
||
return new Directory(directory);
|
||
};
|