@zenfs/core
Version:
A filesystem, anywhere
73 lines (72 loc) • 2.9 kB
JavaScript
// SPDX-License-Identifier: LGPL-3.0-or-later
/* eslint-disable @typescript-eslint/no-redundant-type-constituents */
import { withErrno } from 'kerium';
import { debug, err } from 'kerium/log';
/**
* @category Backends and Configuration
* @internal
*/
export function isBackend(arg) {
return arg != null && typeof arg == 'object' && 'create' in arg && typeof arg.create == 'function';
}
/**
* Use a function as the type of an option, but don't treat it as a class.
*
* Optionally sets the name of a function, useful for error messages.
* @category Backends and Configuration
* @internal
*/
export function _fnOpt(name, fn) {
Object.defineProperty(fn, 'prototype', { value: undefined });
if (name)
Object.defineProperty(fn, 'name', { value: name });
return fn;
}
function _isClass(func) {
if (!(func && func.constructor === Function) || func.prototype === undefined)
return false;
if (Function.prototype !== Object.getPrototypeOf(func))
return true;
return Object.getOwnPropertyNames(func.prototype).length > 1;
}
/**
* Checks that `options` object is valid for the file system options.
* @category Backends and Configuration
* @internal
*/
export function checkOptions(backend, options) {
if (typeof options != 'object' || options === null) {
throw err(withErrno('EINVAL', 'Invalid options'));
}
// Check for required options.
for (const [optName, opt] of Object.entries(backend.options)) {
const value = options?.[optName];
if (value === undefined || value === null) {
if (!opt.required) {
debug('Using default for option: ' + optName);
continue;
}
throw err(withErrno('EINVAL', 'Missing required option: ' + optName));
}
const isType = (type, _ = value) => typeof type == 'function'
? _isClass(type)
? value instanceof type
: type(value)
: typeof value === type || value?.constructor?.name === type;
if (Array.isArray(opt.type) ? opt.type.some(v => isType(v)) : isType(opt.type))
continue;
// The type of the value as a string
const type = typeof value == 'object' && 'constructor' in value ? value.constructor.name : typeof value;
// The expected type (as a string)
const name = (type) => (typeof type == 'function' ? (type.name != 'type' ? type.name : type.toString()) : type);
const expected = Array.isArray(opt.type) ? `one of ${opt.type.map(name).join(', ')}` : name(opt.type);
throw err(withErrno('EINVAL', `Incorrect type for "${optName}": ${type} (expected ${expected})`));
}
}
/**
* @internal
* @category Backends and Configuration
*/
export function isBackendConfig(arg) {
return arg != null && typeof arg == 'object' && 'backend' in arg && isBackend(arg.backend);
}