Skip to content

Commit 0572b35

Browse files
committed
fix: right context when deep resolving
1 parent e1bdf99 commit 0572b35

8 files changed

+127
-33
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "eslint-plugin-exception-handling",
3-
"version": "1.2.0",
3+
"version": "1.2.1",
44
"description": "💣 Lints unhandled functions that might throw errors. For JavaScript/TypeScript eslint.",
55
"author": {
66
"email": "[email protected]",

src/rules/no-unhandled/no-unhandled.spec.ts

+15
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,18 @@ await testFile(
5151
]
5252
);
5353
await testFile("src/rules/no-unhandled/tests/module-ok.ts", [rule.name], []);
54+
await testFile("src/rules/no-unhandled/tests/recursive-ok.ts", [rule.name], []);
55+
await testFile(
56+
"src/rules/no-unhandled/tests/recursive-err.ts",
57+
[rule.name],
58+
[
59+
{
60+
messageId: "noUnhandled",
61+
line: 15,
62+
},
63+
{
64+
messageId: "noUnhandled",
65+
line: 16,
66+
},
67+
]
68+
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
function a() {
2+
a();
3+
throw new Error("error");
4+
}
5+
6+
function b() {
7+
c();
8+
throw new Error("error");
9+
}
10+
11+
function c() {
12+
b();
13+
}
14+
15+
a();
16+
b();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
function a() {
2+
a();
3+
}
4+
5+
function b() {
6+
c();
7+
}
8+
9+
function c() {
10+
b();
11+
}
12+
13+
a();
14+
b();
15+
16+
export {};
+52-27
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { TSESTree } from "@typescript-eslint/utils";
22
import { RuleContext } from "@typescript-eslint/utils/ts-eslint";
3-
import { readFileSync } from "fs";
3+
import { existsSync, readFileSync } from "fs";
44
import path from "path";
55

66
function cleanTsConfig(content: string) {
@@ -17,45 +17,70 @@ function cleanTsConfig(content: string) {
1717
);
1818
}
1919

20+
function resolveTSAlias(tsconfigpath: string, to: string, cwd: string) {
21+
const tsconfig = readFileSync(tsconfigpath, "utf-8");
22+
const aliases = JSON.parse(cleanTsConfig(tsconfig)).compilerOptions
23+
.paths as Record<string, string[]>;
24+
25+
let res = Object.entries(aliases)
26+
// sorting by longest - most qualified - alias
27+
.sort((a, b) => b[0].length - a[0].length)
28+
.find(
29+
([key]) => to.startsWith(key) || to.startsWith(key.replace(/\*$/, ""))
30+
);
31+
32+
if (res) {
33+
let [key, val] = res;
34+
key = key.replace(/\*$/, "");
35+
const firstVal = val[0].replace(/\*$/, "");
36+
to = to.replace(key, firstVal);
37+
to = path.resolve(cwd, to);
38+
}
39+
40+
return to;
41+
}
42+
43+
const codeExt = [".ts", ".js", ".tsx", ".jsx"];
44+
45+
function endsWithAny(str: string, arr: string[]) {
46+
return arr.some((ext) => str.endsWith(ext));
47+
}
48+
2049
export function getImportDeclarationPath(
2150
context: RuleContext<string, unknown[]>,
2251
impt: TSESTree.ImportDeclaration
2352
) {
2453
const from = context.physicalFilename;
2554
let to = impt.source.value;
2655

27-
let ext = path.extname(to);
28-
if (ext === "") {
29-
ext = path.extname(from);
30-
}
56+
let res: string | null = null;
3157

3258
if (!to.startsWith(".")) {
3359
const project = context.parserOptions.project;
3460
if (project) {
35-
const tsconfig = readFileSync(project.toString(), "utf-8");
36-
const aliases = JSON.parse(cleanTsConfig(tsconfig)).compilerOptions
37-
.paths as Record<string, string[]>;
38-
39-
let res = Object.entries(aliases)
40-
// sorting by longest - most qualified - alias
41-
.sort((a, b) => b[0].length - a[0].length)
42-
.find(
43-
([key]) => to.startsWith(key) || to.startsWith(key.replace(/\*$/, ""))
44-
);
45-
46-
if (res) {
47-
let [key, val] = res;
48-
key = key.replace(/\*$/, "");
49-
const firstVal = val[0].replace(/\*$/, "");
50-
to = to.replace(key, firstVal);
51-
return path.resolve(context.cwd, to + ext);
52-
}
61+
to = resolveTSAlias(project.toString(), to, context.cwd);
62+
}
63+
64+
if (!to.startsWith(".")) {
65+
// no relative path and no TS alias,
66+
// considering it as a node_module
67+
return `./node_modules/${to}`;
5368
}
69+
} else {
70+
res = path.resolve(path.dirname(from), to);
71+
}
5472

55-
// no relative path and no TS alias,
56-
// considering it as a node_module
57-
return `./node_modules/${to}`;
73+
if (!res) throw new Error("Import path not resolved");
74+
75+
if (!endsWithAny(res, codeExt)) {
76+
res += path.extname(from);
77+
}
78+
79+
if (!existsSync(res)) {
80+
if (res.endsWith(".js")) {
81+
res = res.replace(".js", ".ts");
82+
}
5883
}
5984

60-
return path.resolve(path.dirname(from), to + ext);
85+
return res;
6186
}

src/utils/parse.ts

+16-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,28 @@
11
import { RuleContext, SourceCode } from "@typescript-eslint/utils/ts-eslint";
22
import { exploreChildren } from "./explore-children";
33

4+
function omitNullish<T extends {}>(obj: T): T {
5+
return Object.fromEntries(
6+
Object.entries(obj).filter(([, value]) => value != null)
7+
) as T;
8+
}
9+
410
export function parse(
511
code: string,
612
context: RuleContext<string, unknown[]>
713
): SourceCode.Program {
814
const opts = context.languageOptions;
915
// eslint-disable-next-line @typescript-eslint/no-explicit-any
10-
const parsed = (opts.parser as any).parseForESLint(code, {
11-
parser: opts.parserOptions,
12-
});
16+
const parsed = (opts.parser as any).parseForESLint(
17+
code,
18+
omitNullish({
19+
parser: opts.parserOptions,
20+
loc: true,
21+
range: true,
22+
tokens: true,
23+
comment: true,
24+
})
25+
);
1326

1427
const ast: SourceCode.Program = parsed.ast;
1528

src/utils/resolve-imported-func.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
isExportNamedDeclaration,
44
isFunctionDeclaration,
55
} from "@/src/utils/ast-guards";
6-
import { RuleContext } from "@typescript-eslint/utils/ts-eslint";
6+
import { RuleContext, SourceCode } from "@typescript-eslint/utils/ts-eslint";
77
import { parse } from "@/src/utils/parse";
88
import { findIdentifiersInChildren } from "@/src/utils/find-identifiers-in-children";
99
import { readFileSync } from "fs";
@@ -32,6 +32,15 @@ export function resolveImportedFunc(
3232
const ctxParsed = {
3333
...context,
3434
physicalFilename: importPath,
35+
sourceCode: new SourceCode(content, parsed),
36+
parser: (context as any).parser,
37+
parserOptions: context.parserOptions,
38+
cwd: context.cwd,
39+
id: context.id,
40+
languageOptions: context.languageOptions,
41+
parserPath: context.parserPath,
42+
report: context.report,
43+
settings: context.settings,
3544
};
3645

3746
return { func: funcInParsed, context: ctxParsed };

tsconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@
1717
},
1818
"include": [
1919
"src/**/*",
20-
"test/**/*"
2120
],
2221
"exclude": [
2322
"node_modules",
2423
"dist",
24+
"**/test/**/*",
2525
]
2626
}

0 commit comments

Comments
 (0)