@parcel/utils
Version:
Blazing fast, zero configuration web application bundler
146 lines (131 loc) • 3.96 kB
JavaScript
// @flow
import path from 'path';
import type {FileSystem} from '@parcel/types';
import {fuzzySearch} from './schema';
import {relativePath} from './path';
import {resolveConfig} from './config';
export async function findAlternativeNodeModules(
fs: FileSystem,
moduleName: string,
dir: string,
): Promise<Array<string>> {
let potentialModules: Array<string> = [];
let root = path.parse(dir).root;
let isOrganisationModule = moduleName.startsWith('@');
while (dir !== root) {
// Skip node_modules directories
if (path.basename(dir) === 'node_modules') {
dir = path.dirname(dir);
}
try {
let modulesDir = path.join(dir, 'node_modules');
let stats = await fs.stat(modulesDir);
if (stats.isDirectory()) {
let dirContent = (await fs.readdir(modulesDir)).sort();
// Filter out the modules that interest us
let modules = dirContent.filter(i =>
isOrganisationModule ? i.startsWith('@') : !i.startsWith('@'),
);
// If it's an organisation module, loop through all the modules of that organisation
if (isOrganisationModule) {
await Promise.all(
modules.map(async item => {
let orgDirPath = path.join(modulesDir, item);
let orgDirContent = (await fs.readdir(orgDirPath)).sort();
// Add all org packages
potentialModules.push(...orgDirContent.map(i => `${item}/${i}`));
}),
);
} else {
potentialModules.push(...modules);
}
}
} catch (err) {
// ignore
}
// Move up a directory
dir = path.dirname(dir);
}
return fuzzySearch(potentialModules.sort(), moduleName).slice(0, 2);
}
async function findAllFilesUp({
fs,
dir,
root,
basedir,
maxlength,
collected,
leadingDotSlash = true,
includeDirectories = true,
}: {|
fs: FileSystem,
dir: string,
root: string,
basedir: string,
maxlength: number,
collected: Array<string>,
leadingDotSlash?: boolean,
includeDirectories?: boolean,
|}): Promise<mixed> {
let dirContent = (await fs.readdir(dir)).sort();
return Promise.all(
dirContent.map(async item => {
let fullPath = path.join(dir, item);
let relativeFilePath = relativePath(basedir, fullPath, leadingDotSlash);
if (relativeFilePath.length < maxlength) {
let stats = await fs.stat(fullPath);
let isDir = stats.isDirectory();
if ((isDir && includeDirectories) || stats.isFile()) {
collected.push(relativeFilePath);
}
// If it's a directory, run over each item within said directory...
if (isDir) {
return findAllFilesUp({
fs,
dir: fullPath,
root,
basedir,
maxlength,
collected,
});
}
}
}),
);
}
export async function findAlternativeFiles(
fs: FileSystem,
fileSpecifier: string,
dir: string,
projectRoot: string,
leadingDotSlash?: boolean = true,
includeDirectories?: boolean = true,
includeExtension?: boolean = false,
): Promise<Array<string>> {
let potentialFiles: Array<string> = [];
// Find our root, we won't recommend files above the package root as that's bad practise
let pkg = await resolveConfig(
fs,
path.join(dir, 'index'),
['package.json'],
projectRoot,
);
let pkgRoot = pkg ? path.dirname(pkg) : projectRoot;
await findAllFilesUp({
fs,
dir: pkgRoot,
root: pkgRoot,
basedir: dir,
maxlength: fileSpecifier.length + 10,
collected: potentialFiles,
leadingDotSlash,
includeDirectories,
});
if (path.extname(fileSpecifier) === '' && !includeExtension) {
potentialFiles = potentialFiles.map(p => {
let ext = path.extname(p);
return ext.length > 0 ? p.slice(0, -ext.length) : p;
});
}
return fuzzySearch(potentialFiles.sort(), fileSpecifier).slice(0, 2);
}