eslint-plugin-exception-handling
Version:
💣 Lints unhandled functions that might throw errors. For JavaScript/TypeScript eslint.
94 lines (93 loc) • 3.54 kB
JavaScript
import { existsSync, lstatSync, readFileSync } from "fs";
import path, { dirname, join } from "path";
function cleanTsConfig(content) {
return (content
// Remove comments
.replace(/(?:\r\n|\n|^)(?:[^'"])*?(?:'(?:[^\r\n\\']|\\'|[\\]{2})*'|"(?:[^\r\n\\"]|\\"|[\\]{2})*")*?(?:[^'"])*?(\/\*(?:[\s\S]*?)\*\/|\/\/.*)/g, "")
// Remove trailing commas
.replace(/,(\s+\])/gm, "$1")
.replace(/,(\s+\})/gm, "$1"));
}
function resolveTSAlias(tsconfigpath, to, cwd) {
const tsconfig = readFileSync(tsconfigpath, "utf-8");
const aliases = (JSON.parse(cleanTsConfig(tsconfig)).compilerOptions?.paths ??
{});
const res = Object.entries(aliases)
// sorting by longest - most qualified - alias
.sort((a, b) => b[0].length - a[0].length)
.find(([key]) => to.startsWith(key) || to.startsWith(key.replace(/\*$/, "")));
if (res) {
// eslint-disable-next-line prefer-const
let [key, val] = res;
key = key.replace(/\*$/, "");
const firstVal = val[0].replace(/\*$/, "");
to = to.replace(key, firstVal);
to = path.resolve(cwd, to);
}
return to;
}
const codeExt = [".ts", ".js", ".tsx", ".jsx"];
function endsWithAny(str, arr) {
return arr.some((ext) => str.endsWith(ext));
}
export function getImportDeclaration(context, impt) {
const from = context.physicalFilename;
let to = impt.source.value;
let res = null;
if (!to.startsWith(".")) {
let { project, tsconfigRootDir } = context.parserOptions;
if (project || tsconfigRootDir) {
if (project === true || !project)
project = "./tsconfig.json";
if (Array.isArray(project))
project = project[0];
if (!tsconfigRootDir)
tsconfigRootDir = context.cwd;
if (!lstatSync(tsconfigRootDir).isDirectory()) {
tsconfigRootDir = dirname(tsconfigRootDir);
}
to = resolveTSAlias(join(tsconfigRootDir, project), to, context.cwd);
res = to;
}
if (!to.startsWith(".") && !to.startsWith("/")) {
const split = to.split(":");
if (!existsSync(to)) {
return { module: split.at(-1), protocol: split.at(-2) };
}
// no relative path and no TS alias,
// considering it as a node_module
return { path: `./node_modules/${to}`, module: to };
}
}
else if (!to.startsWith("/")) {
res = path.resolve(path.dirname(from), to);
}
if (!res)
throw new Error(`Import path '${to}' could not resolved`);
if (!endsWithAny(res, codeExt)) {
res += path.extname(from);
}
if (!existsSync(res)) {
if (res.endsWith(".js")) {
res = findFileExtension(res.replace(".js", ""), [".jsx", ".ts", ".tsx"]);
}
else if (res.endsWith(".jsx")) {
res = findFileExtension(res.replace(".jsx", ""), [".js", ".tsx", ".ts"]);
}
else if (res.endsWith(".ts")) {
res = findFileExtension(res.replace(".ts", ""), [".tsx", ".js", ".jsx"]);
}
else if (res.endsWith(".tsx")) {
res = findFileExtension(res.replace(".tsx", ""), [".ts", ".jsx", ".js"]);
}
}
return { path: res, module: to };
}
function findFileExtension(extless, tries) {
for (const ext of tries) {
if (existsSync(extless + ext)) {
return extless + ext;
}
}
return null;
}