sourceverity 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +188 -0
- package/bin/sourceverity.js +12 -0
- package/dist/analysis/controlFlow.d.ts +10 -0
- package/dist/analysis/controlFlow.d.ts.map +1 -0
- package/dist/analysis/controlFlow.js +278 -0
- package/dist/analysis/controlFlow.js.map +1 -0
- package/dist/analysis/frameworks.d.ts +11 -0
- package/dist/analysis/frameworks.d.ts.map +1 -0
- package/dist/analysis/frameworks.js +189 -0
- package/dist/analysis/frameworks.js.map +1 -0
- package/dist/analysis/functions.d.ts +27 -0
- package/dist/analysis/functions.d.ts.map +1 -0
- package/dist/analysis/functions.js +628 -0
- package/dist/analysis/functions.js.map +1 -0
- package/dist/analysis/promiseFlow.d.ts +44 -0
- package/dist/analysis/promiseFlow.d.ts.map +1 -0
- package/dist/analysis/promiseFlow.js +261 -0
- package/dist/analysis/promiseFlow.js.map +1 -0
- package/dist/analysis/values.d.ts +24 -0
- package/dist/analysis/values.d.ts.map +1 -0
- package/dist/analysis/values.js +189 -0
- package/dist/analysis/values.js.map +1 -0
- package/dist/baseline/manager.d.ts +20 -0
- package/dist/baseline/manager.d.ts.map +1 -0
- package/dist/baseline/manager.js +77 -0
- package/dist/baseline/manager.js.map +1 -0
- package/dist/baseline/types.d.ts +20 -0
- package/dist/baseline/types.d.ts.map +1 -0
- package/dist/baseline/types.js +2 -0
- package/dist/baseline/types.js.map +1 -0
- package/dist/cli/args.d.ts +26 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +126 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/exitCodes.d.ts +8 -0
- package/dist/cli/exitCodes.d.ts.map +1 -0
- package/dist/cli/exitCodes.js +7 -0
- package/dist/cli/exitCodes.js.map +1 -0
- package/dist/cli/help.d.ts +5 -0
- package/dist/cli/help.d.ts.map +1 -0
- package/dist/cli/help.js +46 -0
- package/dist/cli/help.js.map +1 -0
- package/dist/cli/main.d.ts +7 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +156 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/core/fingerprint.d.ts +18 -0
- package/dist/core/fingerprint.d.ts.map +1 -0
- package/dist/core/fingerprint.js +26 -0
- package/dist/core/fingerprint.js.map +1 -0
- package/dist/core/paths.d.ts +10 -0
- package/dist/core/paths.d.ts.map +1 -0
- package/dist/core/paths.js +30 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/suppressions.d.ts +24 -0
- package/dist/core/suppressions.d.ts.map +1 -0
- package/dist/core/suppressions.js +100 -0
- package/dist/core/suppressions.js.map +1 -0
- package/dist/core/terminal.d.ts +18 -0
- package/dist/core/terminal.d.ts.map +1 -0
- package/dist/core/terminal.js +39 -0
- package/dist/core/terminal.js.map +1 -0
- package/dist/core/types.d.ts +119 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/engine/context.d.ts +16 -0
- package/dist/engine/context.d.ts.map +1 -0
- package/dist/engine/context.js +57 -0
- package/dist/engine/context.js.map +1 -0
- package/dist/engine/registry.d.ts +26 -0
- package/dist/engine/registry.d.ts.map +1 -0
- package/dist/engine/registry.js +38 -0
- package/dist/engine/registry.js.map +1 -0
- package/dist/engine/runner.d.ts +14 -0
- package/dist/engine/runner.d.ts.map +1 -0
- package/dist/engine/runner.js +166 -0
- package/dist/engine/runner.js.map +1 -0
- package/dist/engine/symbols.d.ts +46 -0
- package/dist/engine/symbols.d.ts.map +1 -0
- package/dist/engine/symbols.js +278 -0
- package/dist/engine/symbols.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/reporters/agent.d.ts +45 -0
- package/dist/reporters/agent.d.ts.map +1 -0
- package/dist/reporters/agent.js +40 -0
- package/dist/reporters/agent.js.map +1 -0
- package/dist/reporters/json.d.ts +6 -0
- package/dist/reporters/json.d.ts.map +1 -0
- package/dist/reporters/json.js +7 -0
- package/dist/reporters/json.js.map +1 -0
- package/dist/reporters/sarif.d.ts +6 -0
- package/dist/reporters/sarif.d.ts.map +1 -0
- package/dist/reporters/sarif.js +60 -0
- package/dist/reporters/sarif.js.map +1 -0
- package/dist/reporters/terminal.d.ts +10 -0
- package/dist/reporters/terminal.d.ts.map +1 -0
- package/dist/reporters/terminal.js +105 -0
- package/dist/reporters/terminal.js.map +1 -0
- package/dist/repository/detector.d.ts +6 -0
- package/dist/repository/detector.d.ts.map +1 -0
- package/dist/repository/detector.js +231 -0
- package/dist/repository/detector.js.map +1 -0
- package/dist/repository/fileFilter.d.ts +10 -0
- package/dist/repository/fileFilter.d.ts.map +1 -0
- package/dist/repository/fileFilter.js +78 -0
- package/dist/repository/fileFilter.js.map +1 -0
- package/dist/repository/git.d.ts +7 -0
- package/dist/repository/git.d.ts.map +1 -0
- package/dist/repository/git.js +53 -0
- package/dist/repository/git.js.map +1 -0
- package/dist/repository/tsLoader.d.ts +15 -0
- package/dist/repository/tsLoader.d.ts.map +1 -0
- package/dist/repository/tsLoader.js +27 -0
- package/dist/repository/tsLoader.js.map +1 -0
- package/dist/repository/types.d.ts +38 -0
- package/dist/repository/types.d.ts.map +1 -0
- package/dist/repository/types.js +2 -0
- package/dist/repository/types.js.map +1 -0
- package/dist/rules/async/asyncForeach.d.ts +3 -0
- package/dist/rules/async/asyncForeach.d.ts.map +1 -0
- package/dist/rules/async/asyncForeach.js +76 -0
- package/dist/rules/async/asyncForeach.js.map +1 -0
- package/dist/rules/async/floatingPromise.d.ts +3 -0
- package/dist/rules/async/floatingPromise.d.ts.map +1 -0
- package/dist/rules/async/floatingPromise.js +359 -0
- package/dist/rules/async/floatingPromise.js.map +1 -0
- package/dist/rules/browser/eventListenerCleanup.d.ts +3 -0
- package/dist/rules/browser/eventListenerCleanup.d.ts.map +1 -0
- package/dist/rules/browser/eventListenerCleanup.js +378 -0
- package/dist/rules/browser/eventListenerCleanup.js.map +1 -0
- package/dist/rules/browser/observerCleanup.d.ts +3 -0
- package/dist/rules/browser/observerCleanup.d.ts.map +1 -0
- package/dist/rules/browser/observerCleanup.js +184 -0
- package/dist/rules/browser/observerCleanup.js.map +1 -0
- package/dist/rules/browser/timerCleanup.d.ts +3 -0
- package/dist/rules/browser/timerCleanup.d.ts.map +1 -0
- package/dist/rules/browser/timerCleanup.js +115 -0
- package/dist/rules/browser/timerCleanup.js.map +1 -0
- package/dist/rules/index.d.ts +19 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +41 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/network/fetchStatusUnchecked.d.ts +3 -0
- package/dist/rules/network/fetchStatusUnchecked.d.ts.map +1 -0
- package/dist/rules/network/fetchStatusUnchecked.js +96 -0
- package/dist/rules/network/fetchStatusUnchecked.js.map +1 -0
- package/dist/rules/react/asyncEffectCallback.d.ts +3 -0
- package/dist/rules/react/asyncEffectCallback.d.ts.map +1 -0
- package/dist/rules/react/asyncEffectCallback.js +62 -0
- package/dist/rules/react/asyncEffectCallback.js.map +1 -0
- package/dist/rules/react/derivedStateEffect.d.ts +3 -0
- package/dist/rules/react/derivedStateEffect.d.ts.map +1 -0
- package/dist/rules/react/derivedStateEffect.js +172 -0
- package/dist/rules/react/derivedStateEffect.js.map +1 -0
- package/dist/rules/react/missingEffectCleanup.d.ts +3 -0
- package/dist/rules/react/missingEffectCleanup.d.ts.map +1 -0
- package/dist/rules/react/missingEffectCleanup.js +86 -0
- package/dist/rules/react/missingEffectCleanup.js.map +1 -0
- package/dist/rules/typescript/nonNullAssertionRisk.d.ts +3 -0
- package/dist/rules/typescript/nonNullAssertionRisk.d.ts.map +1 -0
- package/dist/rules/typescript/nonNullAssertionRisk.js +65 -0
- package/dist/rules/typescript/nonNullAssertionRisk.js.map +1 -0
- package/dist/rules/typescript/uncheckedIndexAccess.d.ts +3 -0
- package/dist/rules/typescript/uncheckedIndexAccess.d.ts.map +1 -0
- package/dist/rules/typescript/uncheckedIndexAccess.js +79 -0
- package/dist/rules/typescript/uncheckedIndexAccess.js.map +1 -0
- package/dist/rules/typescript/unsafeUnvalidatedAssertion.d.ts +3 -0
- package/dist/rules/typescript/unsafeUnvalidatedAssertion.d.ts.map +1 -0
- package/dist/rules/typescript/unsafeUnvalidatedAssertion.js +94 -0
- package/dist/rules/typescript/unsafeUnvalidatedAssertion.js.map +1 -0
- package/dist/strictness/evaluator.d.ts +28 -0
- package/dist/strictness/evaluator.d.ts.map +1 -0
- package/dist/strictness/evaluator.js +141 -0
- package/dist/strictness/evaluator.js.map +1 -0
- package/dist/strictness/matrix.d.ts +8 -0
- package/dist/strictness/matrix.d.ts.map +1 -0
- package/dist/strictness/matrix.js +63 -0
- package/dist/strictness/matrix.js.map +1 -0
- package/dist/typescript/programManager.d.ts +18 -0
- package/dist/typescript/programManager.d.ts.map +1 -0
- package/dist/typescript/programManager.js +46 -0
- package/dist/typescript/programManager.js.map +1 -0
- package/dist/typescript/projectResolver.d.ts +17 -0
- package/dist/typescript/projectResolver.d.ts.map +1 -0
- package/dist/typescript/projectResolver.js +75 -0
- package/dist/typescript/projectResolver.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { normalizePath } from "../core/paths.js";
|
|
5
|
+
const execFileAsync = promisify(execFile);
|
|
6
|
+
/**
|
|
7
|
+
* Discovers modified, added, or uncommitted files in a git repository.
|
|
8
|
+
* Uses safe argument arrays without shell interpolation.
|
|
9
|
+
* Returns null if Git is unavailable or target directory is not a git repository.
|
|
10
|
+
*/
|
|
11
|
+
export async function getChangedFiles(rootDir) {
|
|
12
|
+
const resolvedDir = path.resolve(rootDir);
|
|
13
|
+
try {
|
|
14
|
+
// 1. Get unstaged and staged modified files from status
|
|
15
|
+
const { stdout: statusOut } = await execFileAsync("git", ["status", "--porcelain", "-uall"], {
|
|
16
|
+
cwd: resolvedDir,
|
|
17
|
+
timeout: 10000,
|
|
18
|
+
});
|
|
19
|
+
const changedSet = new Set();
|
|
20
|
+
for (const line of statusOut.split("\n")) {
|
|
21
|
+
const trimmed = line.trim();
|
|
22
|
+
if (!trimmed)
|
|
23
|
+
continue;
|
|
24
|
+
// Status lines: " M src/index.ts", "?? src/new.ts", "A src/add.ts"
|
|
25
|
+
const filePath = trimmed.slice(2).trim().replace(/^"|"$/g, "");
|
|
26
|
+
if (filePath) {
|
|
27
|
+
changedSet.add(normalizePath(filePath));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// 2. Get files changed against HEAD
|
|
31
|
+
try {
|
|
32
|
+
const { stdout: diffOut } = await execFileAsync("git", ["diff", "--name-only", "HEAD"], {
|
|
33
|
+
cwd: resolvedDir,
|
|
34
|
+
timeout: 10000,
|
|
35
|
+
});
|
|
36
|
+
for (const line of diffOut.split("\n")) {
|
|
37
|
+
const filePath = line.trim().replace(/^"|"$/g, "");
|
|
38
|
+
if (filePath) {
|
|
39
|
+
changedSet.add(normalizePath(filePath));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// HEAD may not exist on empty repository; proceed with status
|
|
45
|
+
}
|
|
46
|
+
return Array.from(changedSet);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// Git not available or not a git repository
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=git.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/repository/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAe;IACnD,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAE1C,IAAI,CAAC;QACH,wDAAwD;QACxD,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE;YAC3F,GAAG,EAAE,WAAW;YAChB,OAAO,EAAE,KAAK;SACf,CAAC,CAAC;QAEH,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;QAErC,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACzC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5B,IAAI,CAAC,OAAO;gBAAE,SAAS;YAEvB,oEAAoE;YACpE,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YAC/D,IAAI,QAAQ,EAAE,CAAC;gBACb,UAAU,CAAC,GAAG,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;QAED,oCAAoC;QACpC,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE;gBACtF,GAAG,EAAE,WAAW;gBAChB,OAAO,EAAE,KAAK;aACf,CAAC,CAAC;YAEH,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;gBACnD,IAAI,QAAQ,EAAE,CAAC;oBACb,UAAU,CAAC,GAAG,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAC1C,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,8DAA8D;QAChE,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,4CAA4C;QAC5C,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type * as tsType from "typescript";
|
|
2
|
+
export interface TypeScriptInstance {
|
|
3
|
+
readonly ts: typeof tsType;
|
|
4
|
+
readonly version: string;
|
|
5
|
+
readonly isLocal: boolean;
|
|
6
|
+
readonly packagePath: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Dynamically resolves and loads the target repository's installed TypeScript compiler.
|
|
10
|
+
*
|
|
11
|
+
* Uses Node's module resolution originating at projectRoot.
|
|
12
|
+
* Returns null if TypeScript is not installed in the target repository.
|
|
13
|
+
*/
|
|
14
|
+
export declare function loadRepositoryTypeScript(projectRoot: string): TypeScriptInstance | null;
|
|
15
|
+
//# sourceMappingURL=tsLoader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tsLoader.d.ts","sourceRoot":"","sources":["../../src/repository/tsLoader.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,MAAM,YAAY,CAAC;AAE1C,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,EAAE,OAAO,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAiBvF"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* Dynamically resolves and loads the target repository's installed TypeScript compiler.
|
|
5
|
+
*
|
|
6
|
+
* Uses Node's module resolution originating at projectRoot.
|
|
7
|
+
* Returns null if TypeScript is not installed in the target repository.
|
|
8
|
+
*/
|
|
9
|
+
export function loadRepositoryTypeScript(projectRoot) {
|
|
10
|
+
try {
|
|
11
|
+
const fakePackageJson = path.join(path.resolve(projectRoot), "package.json");
|
|
12
|
+
const req = createRequire(fakePackageJson);
|
|
13
|
+
const tsPath = req.resolve("typescript");
|
|
14
|
+
const ts = req("typescript");
|
|
15
|
+
const version = ts.version ?? "unknown";
|
|
16
|
+
return {
|
|
17
|
+
ts,
|
|
18
|
+
version,
|
|
19
|
+
isLocal: true,
|
|
20
|
+
packagePath: tsPath,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=tsLoader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tsLoader.js","sourceRoot":"","sources":["../../src/repository/tsLoader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,IAAI,MAAM,WAAW,CAAC;AAU7B;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CAAC,WAAmB;IAC1D,IAAI,CAAC;QACH,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,cAAc,CAAC,CAAC;QAC7E,MAAM,GAAG,GAAG,aAAa,CAAC,eAAe,CAAC,CAAC;QAC3C,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QACzC,MAAM,EAAE,GAAG,GAAG,CAAC,YAAY,CAAkB,CAAC;QAC9C,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,IAAI,SAAS,CAAC;QAExC,OAAO;YACL,EAAE;YACF,OAAO;YACP,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,MAAM;SACpB,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export type PackageManagerType = "npm" | "pnpm" | "yarn" | "bun" | "unknown";
|
|
2
|
+
export interface PackageManifest {
|
|
3
|
+
readonly name?: string | undefined;
|
|
4
|
+
readonly version?: string | undefined;
|
|
5
|
+
readonly private?: boolean | undefined;
|
|
6
|
+
readonly type?: "module" | "commonjs" | undefined;
|
|
7
|
+
readonly workspaces?: readonly string[] | {
|
|
8
|
+
readonly packages?: readonly string[] | undefined;
|
|
9
|
+
} | undefined;
|
|
10
|
+
readonly dependencies?: Record<string, string> | undefined;
|
|
11
|
+
readonly devDependencies?: Record<string, string> | undefined;
|
|
12
|
+
readonly peerDependencies?: Record<string, string> | undefined;
|
|
13
|
+
}
|
|
14
|
+
export interface DiscoveredPackage {
|
|
15
|
+
readonly name: string;
|
|
16
|
+
readonly packageDir: string;
|
|
17
|
+
readonly relativePath: string;
|
|
18
|
+
readonly packageJson: PackageManifest;
|
|
19
|
+
readonly isRoot: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface FrameworkInfo {
|
|
22
|
+
readonly name: string;
|
|
23
|
+
readonly version?: string | undefined;
|
|
24
|
+
}
|
|
25
|
+
export interface RepositoryContext {
|
|
26
|
+
readonly rootDir: string;
|
|
27
|
+
readonly packageManager: PackageManagerType;
|
|
28
|
+
readonly isMonorepo: boolean;
|
|
29
|
+
readonly workspaceType?: "pnpm" | "npm" | "yarn" | "bun" | undefined;
|
|
30
|
+
readonly rootManifest?: PackageManifest | undefined;
|
|
31
|
+
readonly packages: readonly DiscoveredPackage[];
|
|
32
|
+
readonly reactVersion?: string | undefined;
|
|
33
|
+
readonly reactDomVersion?: string | undefined;
|
|
34
|
+
readonly hasReactCompiler: boolean;
|
|
35
|
+
readonly reactCompilerConfig?: Record<string, unknown> | undefined;
|
|
36
|
+
readonly frameworks: readonly FrameworkInfo[];
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/repository/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;AAE7E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;IAClD,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG;QAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAA;KAAE,GAAG,SAAS,CAAC;IAC5G,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IAC3D,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IAC9D,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;CAChE;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,eAAe,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,cAAc,EAAE,kBAAkB,CAAC;IAC5C,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;IACrE,QAAQ,CAAC,YAAY,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;IACpD,QAAQ,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAChD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9C,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IACnE,QAAQ,CAAC,UAAU,EAAE,SAAS,aAAa,EAAE,CAAC;CAC/C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/repository/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asyncForeach.d.ts","sourceRoot":"","sources":["../../../src/rules/async/asyncForeach.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAe,MAAM,qBAAqB,CAAC;AAE7D,eAAO,MAAM,gBAAgB,EAAE,IA0E9B,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { getNodeSourceRange, isPromiseLike } from "../../engine/symbols.js";
|
|
2
|
+
export const asyncForeachRule = {
|
|
3
|
+
meta: {
|
|
4
|
+
id: "async/async-foreach",
|
|
5
|
+
category: "async",
|
|
6
|
+
defaultSeverity: "error",
|
|
7
|
+
defaultConfidence: "high",
|
|
8
|
+
description: "Detects asynchronous callbacks passed to Array.prototype.forEach.",
|
|
9
|
+
requiresTypeInformation: false,
|
|
10
|
+
},
|
|
11
|
+
analyze(context) {
|
|
12
|
+
const { sourceFile, checker, ts } = context;
|
|
13
|
+
if (!ts)
|
|
14
|
+
return;
|
|
15
|
+
context.visitNodes((node) => {
|
|
16
|
+
if (!ts.isCallExpression(node))
|
|
17
|
+
return;
|
|
18
|
+
const expr = node.expression;
|
|
19
|
+
if (!ts.isPropertyAccessExpression(expr))
|
|
20
|
+
return;
|
|
21
|
+
if (expr.name.text !== "forEach")
|
|
22
|
+
return;
|
|
23
|
+
const args = node.arguments;
|
|
24
|
+
if (!args || args.length === 0)
|
|
25
|
+
return;
|
|
26
|
+
const callbackArg = args[0];
|
|
27
|
+
if (!callbackArg)
|
|
28
|
+
return;
|
|
29
|
+
// 1. Direct async arrow function or function expression
|
|
30
|
+
let isAsync = false;
|
|
31
|
+
if (ts.isArrowFunction(callbackArg) || ts.isFunctionExpression(callbackArg)) {
|
|
32
|
+
if (callbackArg.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword)) {
|
|
33
|
+
isAsync = true;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// 2. Semantic check if callback type returns a Promise
|
|
37
|
+
if (!isAsync && checker) {
|
|
38
|
+
try {
|
|
39
|
+
const type = checker.getTypeAtLocation(callbackArg);
|
|
40
|
+
const callSignatures = type.getCallSignatures();
|
|
41
|
+
for (const sig of callSignatures) {
|
|
42
|
+
const retType = sig.getReturnType();
|
|
43
|
+
if (isPromiseLike(retType, checker)) {
|
|
44
|
+
isAsync = true;
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// Fall back to syntactic check
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (isAsync) {
|
|
54
|
+
const range = getNodeSourceRange(node, sourceFile);
|
|
55
|
+
context.report({
|
|
56
|
+
ruleId: "async/async-foreach",
|
|
57
|
+
category: "async",
|
|
58
|
+
severity: "error",
|
|
59
|
+
confidence: "high",
|
|
60
|
+
message: "Asynchronous callback passed to forEach will not be awaited.",
|
|
61
|
+
file: sourceFile.fileName,
|
|
62
|
+
range,
|
|
63
|
+
evidence: [
|
|
64
|
+
{
|
|
65
|
+
message: "Array.prototype.forEach does not await returned Promises from its callback.",
|
|
66
|
+
range,
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
suggestedAction: "Use for...of with await for sequential execution, or Promise.all(items.map(...)) for concurrent execution.",
|
|
70
|
+
safeAutomaticFix: false,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=asyncForeach.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asyncForeach.js","sourceRoot":"","sources":["../../../src/rules/async/asyncForeach.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAG5E,MAAM,CAAC,MAAM,gBAAgB,GAAS;IACpC,IAAI,EAAE;QACJ,EAAE,EAAE,qBAAqB;QACzB,QAAQ,EAAE,OAAO;QACjB,eAAe,EAAE,OAAO;QACxB,iBAAiB,EAAE,MAAM;QACzB,WAAW,EAAE,mEAAmE;QAChF,uBAAuB,EAAE,KAAK;KAC/B;IAED,OAAO,CAAC,OAAoB;QAC1B,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC;QAC5C,IAAI,CAAC,EAAE;YAAE,OAAO;QAEhB,OAAO,CAAC,UAAU,CAAC,CAAC,IAAiB,EAAE,EAAE;YACvC,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC;gBAAE,OAAO;YACvC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC;YAC7B,IAAI,CAAC,EAAE,CAAC,0BAA0B,CAAC,IAAI,CAAC;gBAAE,OAAO;YACjD,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS;gBAAE,OAAO;YAEzC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;YAC5B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO;YAEvC,MAAM,WAAW,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;YAC5B,IAAI,CAAC,WAAW;gBAAE,OAAO;YAEzB,wDAAwD;YACxD,IAAI,OAAO,GAAG,KAAK,CAAC;YACpB,IAAI,EAAE,CAAC,eAAe,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,oBAAoB,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC5E,IAAI,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;oBAC9E,OAAO,GAAG,IAAI,CAAC;gBACjB,CAAC;YACH,CAAC;YAED,uDAAuD;YACvD,IAAI,CAAC,OAAO,IAAI,OAAO,EAAE,CAAC;gBACxB,IAAI,CAAC;oBACH,MAAM,IAAI,GAAG,OAAO,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;oBACpD,MAAM,cAAc,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;oBAChD,KAAK,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;wBACjC,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,EAAE,CAAC;wBACpC,IAAI,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;4BACpC,OAAO,GAAG,IAAI,CAAC;4BACf,MAAM;wBACR,CAAC;oBACH,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,+BAA+B;gBACjC,CAAC;YACH,CAAC;YAED,IAAI,OAAO,EAAE,CAAC;gBACZ,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;gBACnD,OAAO,CAAC,MAAM,CAAC;oBACb,MAAM,EAAE,qBAAqB;oBAC7B,QAAQ,EAAE,OAAO;oBACjB,QAAQ,EAAE,OAAO;oBACjB,UAAU,EAAE,MAAM;oBAClB,OAAO,EAAE,8DAA8D;oBACvE,IAAI,EAAE,UAAU,CAAC,QAAQ;oBACzB,KAAK;oBACL,QAAQ,EAAE;wBACR;4BACE,OAAO,EAAE,6EAA6E;4BACtF,KAAK;yBACN;qBACF;oBACD,eAAe,EACb,4GAA4G;oBAC9G,gBAAgB,EAAE,KAAK;iBACxB,CAAC,CAAC;YACL,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"floatingPromise.d.ts","sourceRoot":"","sources":["../../../src/rules/async/floatingPromise.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,IAAI,EAAe,MAAM,qBAAqB,CAAC;AA8D7D,eAAO,MAAM,mBAAmB,EAAE,IA4UjC,CAAC"}
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
import { getNodeSourceRange } from "../../engine/symbols.js";
|
|
2
|
+
import { unwrapExpression } from "../../analysis/values.js";
|
|
3
|
+
import { classifyPromiseType, evaluatePromiseConsumption, isVariableTargetReturnedInScope, } from "../../analysis/promiseFlow.js";
|
|
4
|
+
import { getFunctionSummary, resolveLocalOrProjectFunctionDeclaration, } from "../../analysis/functions.js";
|
|
5
|
+
import { evaluateFrameworkPromiseCall } from "../../analysis/frameworks.js";
|
|
6
|
+
function canSyntacticallyBePromise(expr, ts) {
|
|
7
|
+
const unwrapped = unwrapExpression(expr, ts);
|
|
8
|
+
const k = unwrapped.kind;
|
|
9
|
+
// Primitives and literals
|
|
10
|
+
if (k === ts.SyntaxKind.StringLiteral ||
|
|
11
|
+
k === ts.SyntaxKind.NumericLiteral ||
|
|
12
|
+
k === ts.SyntaxKind.BigIntLiteral ||
|
|
13
|
+
k === ts.SyntaxKind.TrueKeyword ||
|
|
14
|
+
k === ts.SyntaxKind.FalseKeyword ||
|
|
15
|
+
k === ts.SyntaxKind.NullKeyword ||
|
|
16
|
+
k === ts.SyntaxKind.NoSubstitutionTemplateLiteral ||
|
|
17
|
+
k === ts.SyntaxKind.RegularExpressionLiteral) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
// Function definitions (not function calls)
|
|
21
|
+
if (ts.isArrowFunction(unwrapped) || ts.isFunctionExpression(unwrapped)) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
// JSX elements and fragments
|
|
25
|
+
if (ts.isJsxElement(unwrapped) ||
|
|
26
|
+
ts.isJsxSelfClosingElement(unwrapped) ||
|
|
27
|
+
ts.isJsxFragment(unwrapped)) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
// Unary expressions (!x, typeof x, +x, -x, ~x, void x, delete x)
|
|
31
|
+
if (ts.isPrefixUnaryExpression(unwrapped) ||
|
|
32
|
+
ts.isPostfixUnaryExpression(unwrapped) ||
|
|
33
|
+
ts.isTypeOfExpression(unwrapped) ||
|
|
34
|
+
ts.isDeleteExpression(unwrapped)) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
// Array literals ([1, 2, 3])
|
|
38
|
+
if (ts.isArrayLiteralExpression(unwrapped)) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
// Object literals without 'then' property
|
|
42
|
+
if (ts.isObjectLiteralExpression(unwrapped)) {
|
|
43
|
+
for (const prop of unwrapped.properties) {
|
|
44
|
+
if (prop.name && "text" in prop.name && prop.name.text === "then") {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
export const floatingPromiseRule = {
|
|
53
|
+
meta: {
|
|
54
|
+
id: "async/floating-promise",
|
|
55
|
+
category: "async",
|
|
56
|
+
defaultSeverity: "error",
|
|
57
|
+
defaultConfidence: "high",
|
|
58
|
+
description: "Detects unhandled Promise returned in an expression statement position.",
|
|
59
|
+
requiresTypeInformation: true,
|
|
60
|
+
},
|
|
61
|
+
analyze(context) {
|
|
62
|
+
const { sourceFile, checker, ts } = context;
|
|
63
|
+
if (!checker || !ts)
|
|
64
|
+
return;
|
|
65
|
+
context.visitNodes((node) => {
|
|
66
|
+
// ── CASE 1: ExpressionStatement (e.g. doWork(); or p.then(); or cached = load();) ──
|
|
67
|
+
if (ts.isExpressionStatement(node)) {
|
|
68
|
+
const expr = node.expression;
|
|
69
|
+
const unwrapped = unwrapExpression(expr, ts);
|
|
70
|
+
// Fast path for explicit void operator or await expression
|
|
71
|
+
if (ts.isVoidExpression(unwrapped) || ts.isAwaitExpression(unwrapped)) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (!canSyntacticallyBePromise(expr, ts)) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
const type = checker.getTypeAtLocation(expr);
|
|
79
|
+
const classification = classifyPromiseType(type, checker, ts);
|
|
80
|
+
if (!classification.isPromise) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
// Only evaluate deep consumption if expression is genuinely a Promise
|
|
84
|
+
const consumption = evaluatePromiseConsumption(expr, ts, checker);
|
|
85
|
+
if (consumption.isConsumed) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const range = getNodeSourceRange(expr, sourceFile);
|
|
89
|
+
// Optional union return types (e.g. `void | Promise<void>`) on arbitrary unmodeled functions
|
|
90
|
+
// carry uncertainty and are reported with calibrated medium confidence rather than high confidence error.
|
|
91
|
+
if (classification.isOptionalPromiseUnion) {
|
|
92
|
+
context.report({
|
|
93
|
+
ruleId: "async/floating-promise",
|
|
94
|
+
category: "async",
|
|
95
|
+
severity: "warning",
|
|
96
|
+
confidence: "medium",
|
|
97
|
+
message: "Expression returns an optional Promise (void | Promise<void>) that is not explicitly consumed.",
|
|
98
|
+
file: sourceFile.fileName,
|
|
99
|
+
range,
|
|
100
|
+
evidence: [
|
|
101
|
+
{
|
|
102
|
+
message: "Optional Promise union return types may produce unhandled rejections if the asynchronous branch executes without handling.",
|
|
103
|
+
range,
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
suggestedAction: "Use `void` to make intentional discard explicit, or handle the returned Promise if completion matters.",
|
|
107
|
+
safeAutomaticFix: false,
|
|
108
|
+
});
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
// Definite Promise return types (Promise<T>) in expression statements without handling
|
|
112
|
+
if (classification.isDefinitePromise) {
|
|
113
|
+
// Pattern 1: Discarded `.finally(...)` or unhandled `.then(...)` in expression statement
|
|
114
|
+
if (ts.isCallExpression(unwrapped) && ts.isPropertyAccessExpression(unwrapped.expression)) {
|
|
115
|
+
const methodName = unwrapped.expression.name.text;
|
|
116
|
+
if (methodName === "finally") {
|
|
117
|
+
const receiver = unwrapped.expression.expression;
|
|
118
|
+
let isReceiverHandledLocally = false;
|
|
119
|
+
if (receiver && ts.isCallExpression(unwrapExpression(receiver, ts))) {
|
|
120
|
+
const callNode = unwrapExpression(receiver, ts);
|
|
121
|
+
const localDecl = resolveLocalOrProjectFunctionDeclaration(callNode, ts, checker);
|
|
122
|
+
if (localDecl) {
|
|
123
|
+
const summary = getFunctionSummary(localDecl, ts, checker);
|
|
124
|
+
if (summary.promiseBehavior === "handles-known-rejections") {
|
|
125
|
+
isReceiverHandledLocally = true;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (isReceiverHandledLocally) {
|
|
130
|
+
context.report({
|
|
131
|
+
ruleId: "async/floating-promise",
|
|
132
|
+
category: "async",
|
|
133
|
+
severity: "warning",
|
|
134
|
+
confidence: "medium",
|
|
135
|
+
message: "Promise returned by this call is not explicitly consumed.",
|
|
136
|
+
file: sourceFile.fileName,
|
|
137
|
+
range,
|
|
138
|
+
evidence: [
|
|
139
|
+
{
|
|
140
|
+
message: "The called function handles known failures internally, but SourceVerity cannot prove the returned Promise is non-rejecting.",
|
|
141
|
+
range,
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
suggestedAction: "Use `void` to make intentional discard explicit, or handle the returned Promise if completion matters.",
|
|
145
|
+
safeAutomaticFix: false,
|
|
146
|
+
});
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
context.report({
|
|
150
|
+
ruleId: "async/floating-promise",
|
|
151
|
+
category: "async",
|
|
152
|
+
severity: "error",
|
|
153
|
+
confidence: "high",
|
|
154
|
+
message: "Promise is discarded and its rejection can escape unhandled.",
|
|
155
|
+
file: sourceFile.fileName,
|
|
156
|
+
range,
|
|
157
|
+
evidence: [
|
|
158
|
+
{
|
|
159
|
+
message: "The Promise returned by '.finally()' is discarded and will propagate unhandled rejections if the underlying operation fails.",
|
|
160
|
+
range,
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
suggestedAction: "Await, return, or attach rejection handling.",
|
|
164
|
+
safeAutomaticFix: false,
|
|
165
|
+
});
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (methodName === "then" && unwrapped.arguments.length < 2) {
|
|
169
|
+
context.report({
|
|
170
|
+
ruleId: "async/floating-promise",
|
|
171
|
+
category: "async",
|
|
172
|
+
severity: "error",
|
|
173
|
+
confidence: "high",
|
|
174
|
+
message: "Promise is discarded and its rejection can escape unhandled.",
|
|
175
|
+
file: sourceFile.fileName,
|
|
176
|
+
range,
|
|
177
|
+
evidence: [
|
|
178
|
+
{
|
|
179
|
+
message: "The Promise returned by '.then()' is not chained with a rejection handler and is discarded in statement position.",
|
|
180
|
+
range,
|
|
181
|
+
},
|
|
182
|
+
],
|
|
183
|
+
suggestedAction: "Await, return, or attach rejection handling.",
|
|
184
|
+
safeAutomaticFix: false,
|
|
185
|
+
});
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// Pattern 2: Known rejecting framework / library API
|
|
190
|
+
if (ts.isCallExpression(unwrapped)) {
|
|
191
|
+
const frameworkCheck = evaluateFrameworkPromiseCall(unwrapped, ts, checker);
|
|
192
|
+
if (frameworkCheck.isKnownRejecting) {
|
|
193
|
+
context.report({
|
|
194
|
+
ruleId: "async/floating-promise",
|
|
195
|
+
category: "async",
|
|
196
|
+
severity: "error",
|
|
197
|
+
confidence: "high",
|
|
198
|
+
message: "Promise is discarded and its rejection can escape unhandled.",
|
|
199
|
+
file: sourceFile.fileName,
|
|
200
|
+
range,
|
|
201
|
+
evidence: [
|
|
202
|
+
{
|
|
203
|
+
message: frameworkCheck.reason ?? "The operation initiates an asynchronous process that may reject unhandled on failure.",
|
|
204
|
+
range,
|
|
205
|
+
},
|
|
206
|
+
],
|
|
207
|
+
suggestedAction: "Await, return, or attach rejection handling.",
|
|
208
|
+
safeAutomaticFix: false,
|
|
209
|
+
});
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
// Pattern 3: Resolved local / project function declaration
|
|
213
|
+
const localDecl = resolveLocalOrProjectFunctionDeclaration(unwrapped, ts, checker);
|
|
214
|
+
if (localDecl) {
|
|
215
|
+
const summary = getFunctionSummary(localDecl, ts, checker);
|
|
216
|
+
if (summary.promiseBehavior === "propagates") {
|
|
217
|
+
// Class B: Local function with proven rejection propagation
|
|
218
|
+
context.report({
|
|
219
|
+
ruleId: "async/floating-promise",
|
|
220
|
+
category: "async",
|
|
221
|
+
severity: "error",
|
|
222
|
+
confidence: "high",
|
|
223
|
+
message: "Promise is discarded and its rejection can escape unhandled.",
|
|
224
|
+
file: sourceFile.fileName,
|
|
225
|
+
range,
|
|
226
|
+
evidence: [
|
|
227
|
+
{
|
|
228
|
+
message: "The called function propagates unhandled rejections from its asynchronous operations.",
|
|
229
|
+
range,
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
suggestedAction: "Await, return, or attach rejection handling.",
|
|
233
|
+
safeAutomaticFix: false,
|
|
234
|
+
});
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
if (summary.promiseBehavior === "handles-known-rejections") {
|
|
238
|
+
// Class C: Floating Promise with substantial internal error handling
|
|
239
|
+
context.report({
|
|
240
|
+
ruleId: "async/floating-promise",
|
|
241
|
+
category: "async",
|
|
242
|
+
severity: "warning",
|
|
243
|
+
confidence: "medium",
|
|
244
|
+
message: "Promise returned by this call is not explicitly consumed.",
|
|
245
|
+
file: sourceFile.fileName,
|
|
246
|
+
range,
|
|
247
|
+
evidence: [
|
|
248
|
+
{
|
|
249
|
+
message: "The called function handles known failures internally, but SourceVerity cannot prove the returned Promise is non-rejecting.",
|
|
250
|
+
range,
|
|
251
|
+
},
|
|
252
|
+
],
|
|
253
|
+
suggestedAction: "Use `void` to make intentional discard explicit, or handle the returned Promise if completion matters.",
|
|
254
|
+
safeAutomaticFix: false,
|
|
255
|
+
});
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
// Class D: Unresolved / external / hook / imported function call
|
|
260
|
+
context.report({
|
|
261
|
+
ruleId: "async/floating-promise",
|
|
262
|
+
category: "async",
|
|
263
|
+
severity: "warning",
|
|
264
|
+
confidence: "medium",
|
|
265
|
+
message: "Promise returned by this call is not explicitly consumed.",
|
|
266
|
+
file: sourceFile.fileName,
|
|
267
|
+
range,
|
|
268
|
+
evidence: [
|
|
269
|
+
{
|
|
270
|
+
message: "The function implementation is unavailable, so rejection behavior cannot be proven.",
|
|
271
|
+
range,
|
|
272
|
+
},
|
|
273
|
+
],
|
|
274
|
+
suggestedAction: "Use `void` to make intentional discard explicit, or handle the returned Promise if completion matters.",
|
|
275
|
+
safeAutomaticFix: false,
|
|
276
|
+
});
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
// Fallback for other unhandled definite Promise expressions
|
|
280
|
+
context.report({
|
|
281
|
+
ruleId: "async/floating-promise",
|
|
282
|
+
category: "async",
|
|
283
|
+
severity: "error",
|
|
284
|
+
confidence: "high",
|
|
285
|
+
message: "Promise is discarded and its rejection can escape unhandled.",
|
|
286
|
+
file: sourceFile.fileName,
|
|
287
|
+
range,
|
|
288
|
+
evidence: [
|
|
289
|
+
{
|
|
290
|
+
message: "Floating promises can cause unhandled rejections and race conditions.",
|
|
291
|
+
range,
|
|
292
|
+
},
|
|
293
|
+
],
|
|
294
|
+
suggestedAction: "Await, return, or attach rejection handling.",
|
|
295
|
+
safeAutomaticFix: false,
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
catch {
|
|
300
|
+
// Fall through on type resolution failure
|
|
301
|
+
}
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
// ── CASE 2: VariableDeclaration with Promise initializer (e.g. let p = load();) ──
|
|
305
|
+
if (ts.isVariableDeclaration(node) && node.initializer && ts.isIdentifier(node.name)) {
|
|
306
|
+
const init = node.initializer;
|
|
307
|
+
const unwrappedInit = unwrapExpression(init, ts);
|
|
308
|
+
// Fast path for explicit await or void
|
|
309
|
+
if (ts.isAwaitExpression(unwrappedInit) || ts.isVoidExpression(unwrappedInit)) {
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
if (!canSyntacticallyBePromise(init, ts)) {
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
try {
|
|
316
|
+
const type = checker.getTypeAtLocation(init);
|
|
317
|
+
const classification = classifyPromiseType(type, checker, ts);
|
|
318
|
+
if (!classification.isDefinitePromise) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
// If initializer is explicitly catch-chained or safely consumed, skip
|
|
322
|
+
const consumption = evaluatePromiseConsumption(init, ts, checker);
|
|
323
|
+
if (consumption.isConsumed) {
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (ts.isIdentifier(node.name)) {
|
|
327
|
+
const varName = node.name.text;
|
|
328
|
+
const reachesReturn = isVariableTargetReturnedInScope(node, varName, ts);
|
|
329
|
+
if (reachesReturn) {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
const range = getNodeSourceRange(init, sourceFile);
|
|
333
|
+
context.report({
|
|
334
|
+
ruleId: "async/floating-promise",
|
|
335
|
+
category: "async",
|
|
336
|
+
severity: "error",
|
|
337
|
+
confidence: "high",
|
|
338
|
+
message: "Promise initialized in variable declaration is not returned or consumed, risking unhandled rejection.",
|
|
339
|
+
file: sourceFile.fileName,
|
|
340
|
+
range,
|
|
341
|
+
evidence: [
|
|
342
|
+
{
|
|
343
|
+
message: `Variable '${varName}' holds a Promise that is discarded or overwritten before reaching a return.`,
|
|
344
|
+
range,
|
|
345
|
+
},
|
|
346
|
+
],
|
|
347
|
+
suggestedAction: "Await the promise, return it from the function, or handle rejections with a terminal `.catch()` handler.",
|
|
348
|
+
safeAutomaticFix: false,
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
catch {
|
|
353
|
+
// Fall through
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
},
|
|
358
|
+
};
|
|
359
|
+
//# sourceMappingURL=floatingPromise.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"floatingPromise.js","sourceRoot":"","sources":["../../../src/rules/async/floatingPromise.ts"],"names":[],"mappings":"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"}
|