Skip to content

Commit

Permalink
Removed undocumented and unused mkdirpSync
Browse files Browse the repository at this point in the history
Removed internal levenshtein distance function
Streamlined `checkOptions` errors
  • Loading branch information
james-pre committed Dec 11, 2024
1 parent 9421489 commit f7e30d6
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 130 deletions.
52 changes: 22 additions & 30 deletions src/backends/backend.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { Entries, RequiredKeys } from 'utilium';
import { ErrnoError, Errno } from '../error.js';
import type { FileSystem } from '../filesystem.js';
import { levenshtein } from '../utils.js';

type OptionType = 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function';
type OptionType = 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function' | (abstract new (...args: any[]) => any);

/**
* Resolves the type of Backend.options from the options interface
Expand Down Expand Up @@ -104,43 +104,35 @@ export async function checkOptions<T extends Backend>(backend: T, options: Recor

// Check for required options.
for (const [optName, opt] of Object.entries(backend.options) as Entries<OptionsConfig<Record<string, any>>>) {
const providedValue = options?.[optName];
const value = options?.[optName];

if (providedValue === undefined || providedValue === null) {
if (value === undefined || value === null) {
if (!opt.required) {
continue;
}
/* Required option not provided.
if any incorrect options provided, which ones are close to the provided one?
(edit distance 5 === close)*/
const incorrectOptions = Object.keys(options)
.filter(o => !(o in backend.options))
.map((a: string) => {
return { str: a, distance: levenshtein(optName, a) };
})
.filter(o => o.distance < 5)
.sort((a, b) => a.distance - b.distance);

throw new ErrnoError(
Errno.EINVAL,
`${backend.name}: Required option '${optName}' not provided.${
incorrectOptions.length > 0 ? ` You provided '${incorrectOptions[0].str}', did you mean '${optName}'.` : ''
}`
);

throw new ErrnoError(Errno.EINVAL, 'Missing required option: ' + optName);
}

// Option provided, check type.
const typeMatches = Array.isArray(opt.type) ? opt.type.indexOf(typeof providedValue) != -1 : typeof providedValue == opt.type;
if (!typeMatches) {
throw new ErrnoError(
Errno.EINVAL,
`${backend.name}: Value provided for option ${optName} is not the proper type. Expected ${
Array.isArray(opt.type) ? `one of {${opt.type.join(', ')}}` : (opt.type as string)
}, but received ${typeof providedValue}`
);

type T = typeof opt.type extends (infer U)[] ? U : typeof opt.type;

const isType = (value: unknown): value is T => (typeof opt.type == 'function' ? value instanceof opt.type : typeof value === opt.type);

if (Array.isArray(opt.type) ? !opt.type.some(isType) : !isType(value)) {
// 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: OptionType) => (typeof type == 'function' ? type.name : type);
const expected = Array.isArray(opt.type) ? `one of ${opt.type.map(name).join(', ')}` : name(opt.type as OptionType);

throw new ErrnoError(Errno.EINVAL, `Incorrect type for "${optName}": ${type} (expected ${expected})`);
}

if (opt.validator) {
await opt.validator(providedValue);
await opt.validator(value);
}
// Otherwise: All good!
}
Expand Down
101 changes: 1 addition & 100 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,113 +1,14 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-return */
import type * as fs from 'node:fs';
import { randomHex, type ClassLike, type OptionalTuple } from 'utilium';
import { dirname, resolve, type AbsolutePath } from './emulation/path.js';
import { resolve, type AbsolutePath } from './emulation/path.js';
import { Errno, ErrnoError } from './error.js';
import type { FileSystem } from './filesystem.js';

declare global {
function atob(data: string): string;
function btoa(data: string): string;
}

/**
* Synchronous recursive makedir.
* @hidden
*/
export function mkdirpSync(path: string, mode: number, fs: FileSystem): void {
if (!fs.existsSync(path)) {
mkdirpSync(dirname(path), mode, fs);
fs.mkdirSync(path, mode);
}
}

function _min(d0: number, d1: number, d2: number, bx: number, ay: number): number {
return Math.min(d0 + 1, d1 + 1, d2 + 1, bx === ay ? d1 : d1 + 1);
}

/**
* Calculates levenshtein distance.
* @hidden
*/
export function levenshtein(a: string, b: string): number {
if (a === b) {
return 0;
}

if (a.length > b.length) {
[a, b] = [b, a]; // Swap a and b
}

let la = a.length;
let lb = b.length;

// Trim common suffix
while (la > 0 && a.charCodeAt(la - 1) === b.charCodeAt(lb - 1)) {
la--;
lb--;
}

let offset = 0;

// Trim common prefix
while (offset < la && a.charCodeAt(offset) === b.charCodeAt(offset)) {
offset++;
}

la -= offset;
lb -= offset;

if (la === 0 || lb === 1) {
return lb;
}

const vector = new Array<number>(la << 1);

for (let y = 0; y < la; ) {
vector[la + y] = a.charCodeAt(offset + y);
vector[y] = ++y;
}

let x: number;
let d0: number;
let d1: number;
let d2: number;
let d3: number;
for (x = 0; x + 3 < lb; ) {
const bx0 = b.charCodeAt(offset + (d0 = x));
const bx1 = b.charCodeAt(offset + (d1 = x + 1));
const bx2 = b.charCodeAt(offset + (d2 = x + 2));
const bx3 = b.charCodeAt(offset + (d3 = x + 3));
let dd = (x += 4);
for (let y = 0; y < la; ) {
const ay = vector[la + y];
const dy = vector[y];
d0 = _min(dy, d0, d1, bx0, ay);
d1 = _min(d0, d1, d2, bx1, ay);
d2 = _min(d1, d2, d3, bx2, ay);
dd = _min(d2, d3, dd, bx3, ay);
vector[y++] = dd;
d3 = d2;
d2 = d1;
d1 = d0;
d0 = dy;
}
}

let dd: number = 0;
for (; x < lb; ) {
const bx0 = b.charCodeAt(offset + (d0 = x));
dd = ++x;
for (let y = 0; y < la; y++) {
const dy = vector[y];
vector[y] = dd = dy < d0 || dd < d0 ? (dy > dd ? dd + 1 : dy + 1) : bx0 === vector[la + y] ? d0 : d0 + 1;
d0 = dy;
}
}

return dd;
}

/**
* Encodes a string into a buffer
* @internal
Expand Down

0 comments on commit f7e30d6

Please sign in to comment.