mono/packages/vfs/ref/fs/find.ts

122 lines
3.8 KiB
TypeScript

import * as pathUtil from "path";
import { sync as treeWalkerSync, stream as treeWalkerStream } from './utils/tree_walker';
import { sync as inspectSync, async as inspectASync } from './inspect';
import { create as matcher } from './utils/matcher';
import { validateArgument, validateOptions } from './utils/validate';
import { INode, ENodeType } from './interfaces';
import { ErrDoesntExists, ErrIsNotDirectory } from './errors';
export interface IOptions {
matching?: string[];
files?: boolean;
directories?: boolean;
recursive?: boolean;
cwd?: string;
}
export function validateInput(methodName: string, path: string, options?: IOptions): void {
const methodSignature = methodName + '([path], options)';
validateArgument(methodSignature, 'path', path, ['string']);
validateOptions(methodSignature, 'options', options, {
matching: ['string', 'array of string'],
files: ['boolean'],
directories: ['boolean'],
recursive: ['boolean']
});
};
const defaults = (options?: IOptions): IOptions => {
let opts = options || {} as IOptions;
// defaults:
if (opts.files === undefined) {
opts.files = true;
}
if (opts.directories === undefined) {
opts.directories = false;
}
if (opts.recursive === undefined) {
opts.recursive = true;
}
return opts;
};
const processFoundObjects = (foundObjects: any, cwd: string): string[] => {
return foundObjects.map((inspectObj: INode) => {
return pathUtil.relative(cwd, inspectObj.absolutePath);
});
};
// ---------------------------------------------------------
// Sync
// ---------------------------------------------------------
function findSync(path: string, options: IOptions): string[] {
const foundInspectObjects: INode[] = [];
const matchesAnyOfGlobs = matcher(path, options.matching);
treeWalkerSync(path, {
maxLevelsDeep: options.recursive ? Infinity : 1,
inspectOptions: {
absolutePath: true
}
}, (itemPath, item) => {
if (itemPath !== path && matchesAnyOfGlobs(itemPath)) {
if ((item.type === ENodeType.FILE && options.files === true)
|| (item.type === ENodeType.DIR && options.directories === true)) {
foundInspectObjects.push(item);
}
}
});
return processFoundObjects(foundInspectObjects, options.cwd);
};
export function sync(path: string, options: IOptions): string[] {
const entryPointInspect = inspectSync(path);
if (entryPointInspect === undefined) {
throw ErrDoesntExists(path);
} else if (entryPointInspect.type !== 'dir') {
throw ErrIsNotDirectory(path);
}
return findSync(path, defaults(options));
};
// ---------------------------------------------------------
// Async
// ---------------------------------------------------------
function findAsync(path: string, options: IOptions): Promise<string[]> {
return new Promise<string[]>((resolve, reject) => {
const foundInspectObjects: INode[] = [];
const matchesAnyOfGlobs = matcher(path, options.matching);
const walker = treeWalkerStream(path, {
maxLevelsDeep: options.recursive ? Infinity : 1,
inspectOptions: {
absolutePath: true
}
}).on('readable', () => {
const data = walker.read();
let item: INode;
if (data && data.path !== path && matchesAnyOfGlobs(data.path)) {
item = data.item;
if ((item.type === ENodeType.FILE && options.files === true)
|| (item.type === ENodeType.DIR && options.directories === true)) {
foundInspectObjects.push(item);
}
}
}).on('error', reject)
.on('end', () => {
resolve(processFoundObjects(foundInspectObjects, options.cwd));
});
});
};
export function async(path: string, options: IOptions): Promise<string[]> {
return inspectASync(path)
.then(entryPointInspect => {
if (entryPointInspect === undefined) {
throw ErrDoesntExists(path);
} else if ((entryPointInspect as any).type !== ENodeType.DIR) {
throw ErrIsNotDirectory(path);
}
return findAsync(path, defaults(options));
});
};