@stryke/fs
Version:
A package containing various file system utilities that expand the functionality of NodeJs's built-in `fs` module.
228 lines (226 loc) • 7.93 kB
JavaScript
import { existsSync } from "./exists.mjs";
import { getWorkspaceRoot } from "./get-workspace-root.mjs";
import { appendExtension } from "@stryke/path";
import { joinPaths as joinPaths$1 } from "@stryke/path/join-paths";
import { correctPath, toAbsolutePath } from "@stryke/path/correct-path";
import { findFileName, findFilePath as findFilePath$1, findFolderName as findFolderName$1, hasFileExtension } from "@stryke/path/file-path-fns";
import { interopDefault, resolvePath, resolvePathSync } from "mlly";
import { cwd } from "@stryke/path/cwd";
import { getUnique } from "@stryke/helpers/get-unique";
import { isAbsolutePath, isNpmScopedPackage } from "@stryke/path/is-type";
//#region src/resolve.ts
const DEFAULT_EXTENSIONS = [
"js",
"jsx",
"mjs",
"cjs",
"ts",
"tsx",
"mts",
"cts",
"json",
"jsonc",
"json5",
"node"
];
/**
* Get the resolution paths based on the provided paths, current working directory, and workspace root.
*
* @param paths - An array of paths to include in the resolution.
* @returns An array of unique, corrected resolution paths.
*/
function getResolutionPaths(paths = []) {
let resolutionPaths = paths;
if (!resolutionPaths.includes(cwd())) resolutionPaths.push(cwd());
const workspaceRoot = getWorkspaceRoot();
if (!resolutionPaths.includes(workspaceRoot)) resolutionPaths.push(workspaceRoot);
resolutionPaths = getUnique(resolutionPaths.filter(Boolean).map((path) => correctPath(path)).reduce((ret, path, _, arr) => {
ret.push(path);
if (!isAbsolutePath(path)) {
ret.push(toAbsolutePath(path, cwd()));
ret.push(toAbsolutePath(path, workspaceRoot));
arr.forEach((existing) => {
ret.push(toAbsolutePath(path, existing));
});
}
return ret;
}, []));
return resolutionPaths;
}
/**
* Get the node_modules resolution paths based on the provided paths.
*
* @param paths - An array of paths to include in the resolution.
* @returns An array of unique, corrected node_modules resolution paths.
*/
function getNodeModulesPaths(paths = []) {
return getUnique(paths.reduce((ret, path) => {
if (findFolderName$1(path) === "node_modules") ret.push(correctPath(path));
if (existsSync(joinPaths$1(path, "node_modules"))) ret.push(correctPath(joinPaths$1(path, "node_modules")));
return ret;
}, []));
}
/**
* Get all combinations of resolution paths for a given path and options.
*
* @param path - The base path to combine with resolution paths.
* @param options - The options containing resolution paths.
* @returns An array of unique, corrected resolution paths.
*/
function getResolutionCombinations(path, options = {}) {
let paths = options.useAdditionalPaths ? getResolutionPaths(options.paths) : options.paths ?? [];
if (isNpmScopedPackage(path)) paths = getNodeModulesPaths(paths);
else paths.push(...getNodeModulesPaths(paths));
let combinations = paths.map((base) => joinPaths$1(base, path));
if (findFileName(path, { withExtension: false }) !== "index") combinations = combinations.reduce((ret, combination) => {
ret.push(combination);
ret.push(joinPaths$1(combination, "index"));
return ret;
}, []);
if (!hasFileExtension(path)) {
const extensions = options.extensions ?? DEFAULT_EXTENSIONS;
combinations = combinations.reduce((ret, combination) => {
ret.push(combination);
extensions.forEach((ext) => {
ret.push(appendExtension(combination, ext));
});
return ret;
}, []);
combinations.push(...extensions.map((ext) => getResolutionCombinations(appendExtension(path, ext), options)).flat());
}
paths.map((p) => {
if (hasFileExtension(p)) combinations.push(...getResolutionCombinations(path, {
...options,
useAdditionalPaths: false,
paths: [findFilePath$1(p)]
}));
});
return getUnique(combinations.filter(Boolean)).map((p) => correctPath(p));
}
/**
* Resolve the path to a specified module
*
* @param path - The path to the module
* @param options - The options to use when resolving the module
* @returns A promise for the path to the module
*/
async function resolve(path, options = {}) {
let paths = getResolutionPaths(options.paths);
if (isNpmScopedPackage(path)) paths = getNodeModulesPaths(paths);
else paths.push(...getNodeModulesPaths(paths));
let result;
let error;
try {
result = await resolvePath(path, {
url: paths,
extensions: options.extensions ?? DEFAULT_EXTENSIONS,
conditions: options.conditions
});
} catch (err) {
error = err;
}
if (!result) throw new Error(`Unable to resolve module "${path}". The following import paths were tried: \n${paths.join("\n")}`, { cause: error });
return correctPath(result);
}
/**
* Resolve the path to a specified module
*
* @param path - The path to the module
* @param options - The options to use when resolving the module
* @returns The path to the module or undefined
*/
function resolveSync(path, options = {}) {
let paths = getResolutionPaths(options.paths);
if (isNpmScopedPackage(path)) paths = getNodeModulesPaths(paths);
else paths.push(...getNodeModulesPaths(paths));
let result;
let error;
try {
result = resolvePathSync(path, {
url: paths,
extensions: options.extensions ?? DEFAULT_EXTENSIONS,
conditions: options.conditions
});
} catch (err) {
error = err;
}
if (!result) throw new Error(`Unable to resolve module "${path}". The following import paths were tried: \n${paths.join("\n")}`, { cause: error });
return correctPath(result);
}
/**
* Resolve the path to a specified module with error handling
*
* @param name - The name of the module
* @param options - The options to use when resolving the module
* @returns A promise for the path to the module
*/
async function resolveSafe(name, options = {}) {
try {
return await resolve(name, options);
} catch {
return;
}
}
/**
* Resolve the path to a specified module with error handling
*
* @param name - The name of the module
* @param options - The options to use when resolving the module
* @returns The path to the module or undefined
*/
function resolveSafeSync(name, options = {}) {
try {
return resolveSync(name, options);
} catch {
return;
}
}
/**
* Import a module from a specified path
*
* @param path - The path to the module
* @returns The module
*/
async function importModule(path) {
const i = await import(path);
if (i) return interopDefault(i);
return i;
}
/**
* Resolve the path to a specified package asynchronously
*
* @remarks
* This path points to the root of the package, which is usually the directory containing the `package.json` file. Please note: this path does not include the `package.json` file itself.
*
* @param name - The name of the module
* @returns A promise for the module or undefined
*/
async function resolvePackage(name, options = {}) {
let result = await resolveSafe(joinPaths$1(name, "package.json"), options);
if (!result) {
result = await resolveSafe(joinPaths$1(name, "index.js"), options);
if (!result) result = await resolveSafe(name, options);
}
return result ? findFilePath$1(result) : void 0;
}
/**
* Resolve the path to a specified package synchronously
*
* @remarks
* This path points to the root of the package, which is usually the directory containing the `package.json` file. Please note: this path does not include the `package.json` file itself.
*
* @param name - The name of the module
* @param options - The options to use when resolving the module
* @returns The module or undefined
*/
function resolvePackageSync(name, options = {}) {
let result = resolveSafeSync(joinPaths$1(name, "package.json"), options);
if (!result) {
result = resolveSafeSync(joinPaths$1(name, "index.js"), options);
if (!result) result = resolveSafeSync(name, options);
}
return result ? findFilePath$1(result) : void 0;
}
//#endregion
export { DEFAULT_EXTENSIONS, getNodeModulesPaths, getResolutionCombinations, getResolutionPaths, importModule, resolve, resolvePackage, resolvePackageSync, resolveSafe, resolveSafeSync, resolveSync };
//# sourceMappingURL=resolve.mjs.map