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.
Files changed (192) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +188 -0
  3. package/bin/sourceverity.js +12 -0
  4. package/dist/analysis/controlFlow.d.ts +10 -0
  5. package/dist/analysis/controlFlow.d.ts.map +1 -0
  6. package/dist/analysis/controlFlow.js +278 -0
  7. package/dist/analysis/controlFlow.js.map +1 -0
  8. package/dist/analysis/frameworks.d.ts +11 -0
  9. package/dist/analysis/frameworks.d.ts.map +1 -0
  10. package/dist/analysis/frameworks.js +189 -0
  11. package/dist/analysis/frameworks.js.map +1 -0
  12. package/dist/analysis/functions.d.ts +27 -0
  13. package/dist/analysis/functions.d.ts.map +1 -0
  14. package/dist/analysis/functions.js +628 -0
  15. package/dist/analysis/functions.js.map +1 -0
  16. package/dist/analysis/promiseFlow.d.ts +44 -0
  17. package/dist/analysis/promiseFlow.d.ts.map +1 -0
  18. package/dist/analysis/promiseFlow.js +261 -0
  19. package/dist/analysis/promiseFlow.js.map +1 -0
  20. package/dist/analysis/values.d.ts +24 -0
  21. package/dist/analysis/values.d.ts.map +1 -0
  22. package/dist/analysis/values.js +189 -0
  23. package/dist/analysis/values.js.map +1 -0
  24. package/dist/baseline/manager.d.ts +20 -0
  25. package/dist/baseline/manager.d.ts.map +1 -0
  26. package/dist/baseline/manager.js +77 -0
  27. package/dist/baseline/manager.js.map +1 -0
  28. package/dist/baseline/types.d.ts +20 -0
  29. package/dist/baseline/types.d.ts.map +1 -0
  30. package/dist/baseline/types.js +2 -0
  31. package/dist/baseline/types.js.map +1 -0
  32. package/dist/cli/args.d.ts +26 -0
  33. package/dist/cli/args.d.ts.map +1 -0
  34. package/dist/cli/args.js +126 -0
  35. package/dist/cli/args.js.map +1 -0
  36. package/dist/cli/exitCodes.d.ts +8 -0
  37. package/dist/cli/exitCodes.d.ts.map +1 -0
  38. package/dist/cli/exitCodes.js +7 -0
  39. package/dist/cli/exitCodes.js.map +1 -0
  40. package/dist/cli/help.d.ts +5 -0
  41. package/dist/cli/help.d.ts.map +1 -0
  42. package/dist/cli/help.js +46 -0
  43. package/dist/cli/help.js.map +1 -0
  44. package/dist/cli/main.d.ts +7 -0
  45. package/dist/cli/main.d.ts.map +1 -0
  46. package/dist/cli/main.js +156 -0
  47. package/dist/cli/main.js.map +1 -0
  48. package/dist/core/fingerprint.d.ts +18 -0
  49. package/dist/core/fingerprint.d.ts.map +1 -0
  50. package/dist/core/fingerprint.js +26 -0
  51. package/dist/core/fingerprint.js.map +1 -0
  52. package/dist/core/paths.d.ts +10 -0
  53. package/dist/core/paths.d.ts.map +1 -0
  54. package/dist/core/paths.js +30 -0
  55. package/dist/core/paths.js.map +1 -0
  56. package/dist/core/suppressions.d.ts +24 -0
  57. package/dist/core/suppressions.d.ts.map +1 -0
  58. package/dist/core/suppressions.js +100 -0
  59. package/dist/core/suppressions.js.map +1 -0
  60. package/dist/core/terminal.d.ts +18 -0
  61. package/dist/core/terminal.d.ts.map +1 -0
  62. package/dist/core/terminal.js +39 -0
  63. package/dist/core/terminal.js.map +1 -0
  64. package/dist/core/types.d.ts +119 -0
  65. package/dist/core/types.d.ts.map +1 -0
  66. package/dist/core/types.js +2 -0
  67. package/dist/core/types.js.map +1 -0
  68. package/dist/engine/context.d.ts +16 -0
  69. package/dist/engine/context.d.ts.map +1 -0
  70. package/dist/engine/context.js +57 -0
  71. package/dist/engine/context.js.map +1 -0
  72. package/dist/engine/registry.d.ts +26 -0
  73. package/dist/engine/registry.d.ts.map +1 -0
  74. package/dist/engine/registry.js +38 -0
  75. package/dist/engine/registry.js.map +1 -0
  76. package/dist/engine/runner.d.ts +14 -0
  77. package/dist/engine/runner.d.ts.map +1 -0
  78. package/dist/engine/runner.js +166 -0
  79. package/dist/engine/runner.js.map +1 -0
  80. package/dist/engine/symbols.d.ts +46 -0
  81. package/dist/engine/symbols.d.ts.map +1 -0
  82. package/dist/engine/symbols.js +278 -0
  83. package/dist/engine/symbols.js.map +1 -0
  84. package/dist/index.d.ts +20 -0
  85. package/dist/index.d.ts.map +1 -0
  86. package/dist/index.js +32 -0
  87. package/dist/index.js.map +1 -0
  88. package/dist/reporters/agent.d.ts +45 -0
  89. package/dist/reporters/agent.d.ts.map +1 -0
  90. package/dist/reporters/agent.js +40 -0
  91. package/dist/reporters/agent.js.map +1 -0
  92. package/dist/reporters/json.d.ts +6 -0
  93. package/dist/reporters/json.d.ts.map +1 -0
  94. package/dist/reporters/json.js +7 -0
  95. package/dist/reporters/json.js.map +1 -0
  96. package/dist/reporters/sarif.d.ts +6 -0
  97. package/dist/reporters/sarif.d.ts.map +1 -0
  98. package/dist/reporters/sarif.js +60 -0
  99. package/dist/reporters/sarif.js.map +1 -0
  100. package/dist/reporters/terminal.d.ts +10 -0
  101. package/dist/reporters/terminal.d.ts.map +1 -0
  102. package/dist/reporters/terminal.js +105 -0
  103. package/dist/reporters/terminal.js.map +1 -0
  104. package/dist/repository/detector.d.ts +6 -0
  105. package/dist/repository/detector.d.ts.map +1 -0
  106. package/dist/repository/detector.js +231 -0
  107. package/dist/repository/detector.js.map +1 -0
  108. package/dist/repository/fileFilter.d.ts +10 -0
  109. package/dist/repository/fileFilter.d.ts.map +1 -0
  110. package/dist/repository/fileFilter.js +78 -0
  111. package/dist/repository/fileFilter.js.map +1 -0
  112. package/dist/repository/git.d.ts +7 -0
  113. package/dist/repository/git.d.ts.map +1 -0
  114. package/dist/repository/git.js +53 -0
  115. package/dist/repository/git.js.map +1 -0
  116. package/dist/repository/tsLoader.d.ts +15 -0
  117. package/dist/repository/tsLoader.d.ts.map +1 -0
  118. package/dist/repository/tsLoader.js +27 -0
  119. package/dist/repository/tsLoader.js.map +1 -0
  120. package/dist/repository/types.d.ts +38 -0
  121. package/dist/repository/types.d.ts.map +1 -0
  122. package/dist/repository/types.js +2 -0
  123. package/dist/repository/types.js.map +1 -0
  124. package/dist/rules/async/asyncForeach.d.ts +3 -0
  125. package/dist/rules/async/asyncForeach.d.ts.map +1 -0
  126. package/dist/rules/async/asyncForeach.js +76 -0
  127. package/dist/rules/async/asyncForeach.js.map +1 -0
  128. package/dist/rules/async/floatingPromise.d.ts +3 -0
  129. package/dist/rules/async/floatingPromise.d.ts.map +1 -0
  130. package/dist/rules/async/floatingPromise.js +359 -0
  131. package/dist/rules/async/floatingPromise.js.map +1 -0
  132. package/dist/rules/browser/eventListenerCleanup.d.ts +3 -0
  133. package/dist/rules/browser/eventListenerCleanup.d.ts.map +1 -0
  134. package/dist/rules/browser/eventListenerCleanup.js +378 -0
  135. package/dist/rules/browser/eventListenerCleanup.js.map +1 -0
  136. package/dist/rules/browser/observerCleanup.d.ts +3 -0
  137. package/dist/rules/browser/observerCleanup.d.ts.map +1 -0
  138. package/dist/rules/browser/observerCleanup.js +184 -0
  139. package/dist/rules/browser/observerCleanup.js.map +1 -0
  140. package/dist/rules/browser/timerCleanup.d.ts +3 -0
  141. package/dist/rules/browser/timerCleanup.d.ts.map +1 -0
  142. package/dist/rules/browser/timerCleanup.js +115 -0
  143. package/dist/rules/browser/timerCleanup.js.map +1 -0
  144. package/dist/rules/index.d.ts +19 -0
  145. package/dist/rules/index.d.ts.map +1 -0
  146. package/dist/rules/index.js +41 -0
  147. package/dist/rules/index.js.map +1 -0
  148. package/dist/rules/network/fetchStatusUnchecked.d.ts +3 -0
  149. package/dist/rules/network/fetchStatusUnchecked.d.ts.map +1 -0
  150. package/dist/rules/network/fetchStatusUnchecked.js +96 -0
  151. package/dist/rules/network/fetchStatusUnchecked.js.map +1 -0
  152. package/dist/rules/react/asyncEffectCallback.d.ts +3 -0
  153. package/dist/rules/react/asyncEffectCallback.d.ts.map +1 -0
  154. package/dist/rules/react/asyncEffectCallback.js +62 -0
  155. package/dist/rules/react/asyncEffectCallback.js.map +1 -0
  156. package/dist/rules/react/derivedStateEffect.d.ts +3 -0
  157. package/dist/rules/react/derivedStateEffect.d.ts.map +1 -0
  158. package/dist/rules/react/derivedStateEffect.js +172 -0
  159. package/dist/rules/react/derivedStateEffect.js.map +1 -0
  160. package/dist/rules/react/missingEffectCleanup.d.ts +3 -0
  161. package/dist/rules/react/missingEffectCleanup.d.ts.map +1 -0
  162. package/dist/rules/react/missingEffectCleanup.js +86 -0
  163. package/dist/rules/react/missingEffectCleanup.js.map +1 -0
  164. package/dist/rules/typescript/nonNullAssertionRisk.d.ts +3 -0
  165. package/dist/rules/typescript/nonNullAssertionRisk.d.ts.map +1 -0
  166. package/dist/rules/typescript/nonNullAssertionRisk.js +65 -0
  167. package/dist/rules/typescript/nonNullAssertionRisk.js.map +1 -0
  168. package/dist/rules/typescript/uncheckedIndexAccess.d.ts +3 -0
  169. package/dist/rules/typescript/uncheckedIndexAccess.d.ts.map +1 -0
  170. package/dist/rules/typescript/uncheckedIndexAccess.js +79 -0
  171. package/dist/rules/typescript/uncheckedIndexAccess.js.map +1 -0
  172. package/dist/rules/typescript/unsafeUnvalidatedAssertion.d.ts +3 -0
  173. package/dist/rules/typescript/unsafeUnvalidatedAssertion.d.ts.map +1 -0
  174. package/dist/rules/typescript/unsafeUnvalidatedAssertion.js +94 -0
  175. package/dist/rules/typescript/unsafeUnvalidatedAssertion.js.map +1 -0
  176. package/dist/strictness/evaluator.d.ts +28 -0
  177. package/dist/strictness/evaluator.d.ts.map +1 -0
  178. package/dist/strictness/evaluator.js +141 -0
  179. package/dist/strictness/evaluator.js.map +1 -0
  180. package/dist/strictness/matrix.d.ts +8 -0
  181. package/dist/strictness/matrix.d.ts.map +1 -0
  182. package/dist/strictness/matrix.js +63 -0
  183. package/dist/strictness/matrix.js.map +1 -0
  184. package/dist/typescript/programManager.d.ts +18 -0
  185. package/dist/typescript/programManager.d.ts.map +1 -0
  186. package/dist/typescript/programManager.js +46 -0
  187. package/dist/typescript/programManager.js.map +1 -0
  188. package/dist/typescript/projectResolver.d.ts +17 -0
  189. package/dist/typescript/projectResolver.d.ts.map +1 -0
  190. package/dist/typescript/projectResolver.js +75 -0
  191. package/dist/typescript/projectResolver.js.map +1 -0
  192. 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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/repository/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ import type { Rule } from "../../core/types.js";
2
+ export declare const asyncForeachRule: Rule;
3
+ //# sourceMappingURL=asyncForeach.d.ts.map
@@ -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,3 @@
1
+ import type { Rule } from "../../core/types.js";
2
+ export declare const floatingPromiseRule: Rule;
3
+ //# sourceMappingURL=floatingPromise.d.ts.map
@@ -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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"}