UNPKG

@zenfs/core

Version:

A filesystem, anywhere

124 lines (123 loc) 3.71 kB
// SPDX-License-Identifier: LGPL-3.0-or-later import { withErrno } from 'kerium'; import { decodeUTF8, encodeUTF8 } from 'utilium'; import { resolve } from './path.js'; /** * Decodes a directory listing * @hidden */ export function decodeDirListing(data) { return JSON.parse(decodeUTF8(data), (k, v) => k == '' ? v : typeof v == 'string' ? BigInt(v).toString(16).slice(0, Math.min(v.length, 8)) : v); } /** * Encodes a directory listing * @hidden */ export function encodeDirListing(data) { return encodeUTF8(JSON.stringify(data)); } /** * Normalizes a mode * @param def default * @internal */ export function normalizeMode(mode, def) { if (typeof mode == 'number') return mode; if (typeof mode == 'string') { const parsed = parseInt(mode, 8); if (!isNaN(parsed)) { return parsed; } } if (typeof def == 'number') return def; throw withErrno('EINVAL', 'Invalid mode: ' + mode?.toString()); } /** * Normalizes a time * @internal */ export function normalizeTime(time) { if (time instanceof Date) return time.getTime(); try { return Number(time); } catch { throw withErrno('EINVAL', 'Invalid time.'); } } /** * Normalizes a path * @internal * @todo clean this up and make it so `path.resolve` is only called when an explicit context is passed (i.e. `normalizePath(..., $)` to use `path.resolve`) */ export function normalizePath(p, noResolve = false) { if (p instanceof URL) { if (p.protocol != 'file:') throw withErrno('EINVAL', 'URLs must use the file: protocol'); p = p.pathname; } p = p.toString(); if (p.startsWith('file://')) p = p.slice('file://'.length); if (p.includes('\x00')) throw withErrno('EINVAL', 'Path can not contain null character'); if (p.length == 0) throw withErrno('EINVAL', 'Path can not be empty'); p = p.replaceAll(/[/\\]+/g, '/'); // Note: PWD is not resolved here, it is resolved later. return noResolve ? p : resolve.call(this, p); } /** * Normalizes options * @param options options to normalize * @param encoding default encoding * @param flag default flag * @param mode default mode * @internal */ export function normalizeOptions(options, encoding = 'utf8', flag, mode = 0) { if (typeof options != 'object' || options === null) { return { encoding: typeof options == 'string' ? options : (encoding ?? null), flag, mode, }; } return { encoding: typeof options?.encoding == 'string' ? options.encoding : (encoding ?? null), flag: typeof options?.flag == 'string' ? options.flag : flag, mode: normalizeMode('mode' in options ? options?.mode : null, mode), }; } /** * Converts a glob pattern to a regular expression * @internal */ export function globToRegex(pattern) { const GLOBSTAR = '\0GS\0'; const STAR = '\0S\0'; pattern = pattern .replace(/\*\*/g, GLOBSTAR) .replace(/\*/g, STAR) .replace(/[.+^$(){}|[\]\\]/g, '\\$&') .replace(/\?/g, '.') .replaceAll('/' + GLOBSTAR + '/', '(?:/.*)?/') .replaceAll(GLOBSTAR, '.*') .replaceAll(STAR, '[^/]*'); return new RegExp(`^${pattern}$`); } export async function waitOnline(worker) { const online = Promise.withResolvers(); setTimeout(() => online.reject(withErrno('ETIMEDOUT')), 500); worker.on('online', online.resolve); await online.promise; } /** * @internal @hidden */ export function _tempDirName(prefix) { return `/tmp/${normalizePath(prefix, true)}${Date.now()}-${Math.random().toString(36).slice(2)}`; }