Skip to content

Commit

Permalink
fix: right context when deep resolving
Browse files Browse the repository at this point in the history
  • Loading branch information
Akronae committed Jun 2, 2024
1 parent e1bdf99 commit 0572b35
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 33 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "eslint-plugin-exception-handling",
"version": "1.2.0",
"version": "1.2.1",
"description": "💣 Lints unhandled functions that might throw errors. For JavaScript/TypeScript eslint.",
"author": {
"email": "alexandre@daubricourt.com",
Expand Down
15 changes: 15 additions & 0 deletions src/rules/no-unhandled/no-unhandled.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,18 @@ await testFile(
]
);
await testFile("src/rules/no-unhandled/tests/module-ok.ts", [rule.name], []);
await testFile("src/rules/no-unhandled/tests/recursive-ok.ts", [rule.name], []);
await testFile(
"src/rules/no-unhandled/tests/recursive-err.ts",
[rule.name],
[
{
messageId: "noUnhandled",
line: 15,
},
{
messageId: "noUnhandled",
line: 16,
},
]
);
16 changes: 16 additions & 0 deletions src/rules/no-unhandled/tests/recursive-err.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
function a() {
a();
throw new Error("error");
}

function b() {
c();
throw new Error("error");
}

function c() {
b();
}

a();
b();
16 changes: 16 additions & 0 deletions src/rules/no-unhandled/tests/recursive-ok.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
function a() {
a();
}

function b() {
c();
}

function c() {
b();
}

a();
b();

export {};
79 changes: 52 additions & 27 deletions src/utils/get-import-declaration-path.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { TSESTree } from "@typescript-eslint/utils";
import { RuleContext } from "@typescript-eslint/utils/ts-eslint";
import { readFileSync } from "fs";
import { existsSync, readFileSync } from "fs";
import path from "path";

function cleanTsConfig(content: string) {
Expand All @@ -17,45 +17,70 @@ function cleanTsConfig(content: string) {
);
}

function resolveTSAlias(tsconfigpath: string, to: string, cwd: string) {
const tsconfig = readFileSync(tsconfigpath, "utf-8");
const aliases = JSON.parse(cleanTsConfig(tsconfig)).compilerOptions
.paths as Record<string, string[]>;

let 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) {
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: string, arr: string[]) {
return arr.some((ext) => str.endsWith(ext));
}

export function getImportDeclarationPath(
context: RuleContext<string, unknown[]>,
impt: TSESTree.ImportDeclaration
) {
const from = context.physicalFilename;
let to = impt.source.value;

let ext = path.extname(to);
if (ext === "") {
ext = path.extname(from);
}
let res: string | null = null;

if (!to.startsWith(".")) {
const project = context.parserOptions.project;
if (project) {
const tsconfig = readFileSync(project.toString(), "utf-8");
const aliases = JSON.parse(cleanTsConfig(tsconfig)).compilerOptions
.paths as Record<string, string[]>;

let 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) {
let [key, val] = res;
key = key.replace(/\*$/, "");
const firstVal = val[0].replace(/\*$/, "");
to = to.replace(key, firstVal);
return path.resolve(context.cwd, to + ext);
}
to = resolveTSAlias(project.toString(), to, context.cwd);
}

if (!to.startsWith(".")) {
// no relative path and no TS alias,
// considering it as a node_module
return `./node_modules/${to}`;
}
} else {
res = path.resolve(path.dirname(from), to);
}

// no relative path and no TS alias,
// considering it as a node_module
return `./node_modules/${to}`;
if (!res) throw new Error("Import path not resolved");

if (!endsWithAny(res, codeExt)) {
res += path.extname(from);
}

if (!existsSync(res)) {
if (res.endsWith(".js")) {
res = res.replace(".js", ".ts");
}
}

return path.resolve(path.dirname(from), to + ext);
return res;
}
19 changes: 16 additions & 3 deletions src/utils/parse.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
import { RuleContext, SourceCode } from "@typescript-eslint/utils/ts-eslint";
import { exploreChildren } from "./explore-children";

function omitNullish<T extends {}>(obj: T): T {
return Object.fromEntries(
Object.entries(obj).filter(([, value]) => value != null)
) as T;
}

export function parse(
code: string,
context: RuleContext<string, unknown[]>
): SourceCode.Program {
const opts = context.languageOptions;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const parsed = (opts.parser as any).parseForESLint(code, {
parser: opts.parserOptions,
});
const parsed = (opts.parser as any).parseForESLint(
code,
omitNullish({
parser: opts.parserOptions,
loc: true,
range: true,
tokens: true,
comment: true,
})
);

const ast: SourceCode.Program = parsed.ast;

Expand Down
11 changes: 10 additions & 1 deletion src/utils/resolve-imported-func.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
isExportNamedDeclaration,
isFunctionDeclaration,
} from "@/src/utils/ast-guards";
import { RuleContext } from "@typescript-eslint/utils/ts-eslint";
import { RuleContext, SourceCode } from "@typescript-eslint/utils/ts-eslint";
import { parse } from "@/src/utils/parse";
import { findIdentifiersInChildren } from "@/src/utils/find-identifiers-in-children";
import { readFileSync } from "fs";
Expand Down Expand Up @@ -32,6 +32,15 @@ export function resolveImportedFunc(
const ctxParsed = {
...context,
physicalFilename: importPath,
sourceCode: new SourceCode(content, parsed),
parser: (context as any).parser,
parserOptions: context.parserOptions,
cwd: context.cwd,
id: context.id,
languageOptions: context.languageOptions,
parserPath: context.parserPath,
report: context.report,
settings: context.settings,
};

return { func: funcInParsed, context: ctxParsed };
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
},
"include": [
"src/**/*",
"test/**/*"
],
"exclude": [
"node_modules",
"dist",
"**/test/**/*",
]
}

0 comments on commit 0572b35

Please sign in to comment.