one
Version:
One is a React framework for web, iOS, and Android apps.
123 lines (108 loc) • 3.8 kB
text/typescript
import { FileMode, type FileDigestAlgorithm } from './types'
import type { FileEncoding } from '../specs/OneFileSystem.nitro'
// caller-mistake checks shared by the native and web classes: same check and
// message on both platforms, thrown synchronously at the js boundary.
const modes = new Set<string>(Object.values(FileMode))
const algorithms = new Set<string>(['MD5', 'SHA-1', 'SHA-256', 'SHA-384', 'SHA-512'])
const encodings = new Set<string>(['utf8', 'base64'])
export function assertUri(uri: unknown, owner: string): asserts uri is string {
if (typeof uri !== 'string') throw new Error(`${owner}: expected a uri string`)
let parsed: URL
try {
parsed = new URL(uri)
} catch {
throw new Error(`${owner}: expected an absolute file uri`)
}
if (
(parsed.protocol !== 'file:' && parsed.protocol !== 'opfs:') ||
!parsed.pathname.startsWith('/') ||
parsed.search ||
parsed.hash
) {
throw new Error(`${owner}: expected an absolute file uri`)
}
}
export function assertMode(mode: unknown, owner: string): asserts mode is FileMode {
if (typeof mode !== 'string' || !modes.has(mode)) {
throw new Error(`${owner}: expected a FileMode`)
}
}
export function assertEncoding(
encoding: unknown,
owner: string
): asserts encoding is FileEncoding {
if (typeof encoding !== 'string' || !encodings.has(encoding)) {
throw new Error(`${owner}: expected encoding 'utf8' or 'base64'`)
}
}
export function assertAlgorithm(
algorithm: unknown,
owner: string
): asserts algorithm is FileDigestAlgorithm {
if (typeof algorithm !== 'string' || !algorithms.has(algorithm)) {
throw new Error(`${owner}: expected a digest algorithm`)
}
}
export function assertByteLength(length: unknown, owner: string): asserts length is number {
if (typeof length !== 'number' || !Number.isInteger(length) || length < 0) {
throw new Error(`${owner}: expected a nonnegative integer byte length`)
}
}
export function assertOffset(offset: unknown, owner: string): asserts offset is number {
if (typeof offset !== 'number' || !Number.isFinite(offset) || offset < 0) {
throw new Error(`${owner}: expected a finite nonnegative offset`)
}
}
export function assertName(name: unknown, owner: string): asserts name is string {
if (
typeof name !== 'string' ||
name === '' ||
name.includes('/') ||
name === '.' ||
name === '..'
) {
throw new Error(`${owner}: expected a single path segment`)
}
}
export function assertWriteContent(
content: unknown,
owner: string
): asserts content is string | Uint8Array | ArrayBuffer {
if (
typeof content !== 'string' &&
!(content instanceof Uint8Array) &&
!(content instanceof ArrayBuffer)
) {
throw new Error(`${owner}: expected a string, Uint8Array or ArrayBuffer`)
}
}
export function assertWriteBytes(
bytes: unknown,
owner: string
): asserts bytes is Uint8Array | ArrayBuffer {
if (!(bytes instanceof Uint8Array) && !(bytes instanceof ArrayBuffer)) {
throw new Error(`${owner}: expected a Uint8Array or ArrayBuffer`)
}
}
export function assertReadable(mode: FileMode, verb: string): void {
if (mode !== FileMode.ReadOnly && mode !== FileMode.ReadWrite) {
throw new Error(`${verb}: the handle is not readable`)
}
}
export function assertWritable(mode: FileMode, verb: string): void {
if (mode === FileMode.ReadOnly) {
throw new Error(`${verb}: the handle is not writable`)
}
}
export function assertDestination(
destination: unknown,
owner: string
): asserts destination is { uri: string } {
if (
typeof destination !== 'object' ||
destination === null ||
typeof (destination as { uri?: unknown }).uri !== 'string'
) {
throw new Error(`${owner}: expected a File or Directory destination`)
}
}