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
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 SourceVerity Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# SourceVerity
|
|
2
|
+
|
|
3
|
+
SourceVerity is a repository-aware frontend correctness and quality auditor for JavaScript, TypeScript, and React applications.
|
|
4
|
+
|
|
5
|
+
It identifies high-value correctness defects, resource leaks, async hazards, and hidden type-safety gaps that standard compilation, weak TypeScript configurations, or style linters do not reject.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx sourceverity scan .
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Philosophy & Scope
|
|
14
|
+
|
|
15
|
+
SourceVerity operates on the principle: **Respect the repository. Audit beyond the repository.**
|
|
16
|
+
|
|
17
|
+
Many production codebases maintain loose TypeScript compiler options (such as `strictNullChecks: false` or `noUncheckedIndexedAccess: false`) for historical migration reasons. SourceVerity understands what your compiler accepts while independently determining whether runtime operations are genuinely safe.
|
|
18
|
+
|
|
19
|
+
### What SourceVerity Detects
|
|
20
|
+
- **Async Hazards**: Unawaited callbacks in array iterations, floating/unhandled Promises, missing error rejection handling.
|
|
21
|
+
- **Hidden Type-Safety Gaps**: Unvalidated runtime data (`JSON.parse()`, `response.json()`) asserted directly to domain types, risky non-null assertions on nullable types, unsafe unchecked index accesses.
|
|
22
|
+
- **Browser Resource Leaks**: Missing or mismatched `addEventListener` cleanup in lifecycle scopes, uncleaned intervals (`setInterval`), un-disconnected DOM Observers (`ResizeObserver`, `MutationObserver`).
|
|
23
|
+
- **Network Misuse**: Unchecked HTTP response status prior to consuming response bodies.
|
|
24
|
+
- **React Lifecycle Deficiencies**: Direct async callbacks passed to `useEffect`, derived local state unnecessarily synchronized inside effects, uncleaned resource subscriptions.
|
|
25
|
+
- **TypeScript Strictness Migration Gaps**: Measurable evaluation of potential compiler diagnostics if strict compiler flags were enabled.
|
|
26
|
+
|
|
27
|
+
### What SourceVerity Is Not
|
|
28
|
+
- Not a code formatter or style enforcer (not an alternative to Prettier or Biome formatting).
|
|
29
|
+
- Not a subjective opinion generator or naming linter.
|
|
30
|
+
- Not an LLM wrapper or AI reviewer (all diagnostics are computed deterministically via static AST and TypeScript semantic analysis).
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Installation & CLI Usage
|
|
35
|
+
|
|
36
|
+
Run SourceVerity directly using `npx`:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Audit the current repository
|
|
40
|
+
npx sourceverity scan .
|
|
41
|
+
|
|
42
|
+
# Run with custom failure threshold (error, warning, never)
|
|
43
|
+
npx sourceverity scan . --fail-on warning
|
|
44
|
+
|
|
45
|
+
# Report only high-confidence findings
|
|
46
|
+
npx sourceverity scan . --min-confidence high
|
|
47
|
+
|
|
48
|
+
# Analyze only git-changed files
|
|
49
|
+
npx sourceverity scan . --changed
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Output Formats
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Default human-readable terminal format
|
|
56
|
+
npx sourceverity scan . --format pretty
|
|
57
|
+
|
|
58
|
+
# Deterministic JSON format
|
|
59
|
+
npx sourceverity scan . --format json
|
|
60
|
+
|
|
61
|
+
# Machine format tailored for LLMs and coding agents (e.g. Codex)
|
|
62
|
+
npx sourceverity scan . --format agent
|
|
63
|
+
|
|
64
|
+
# Standard SARIF 2.1.0 format for GitHub Code Scanning
|
|
65
|
+
npx sourceverity scan . --format sarif
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Using SourceVerity with Coding Agents
|
|
71
|
+
|
|
72
|
+
SourceVerity's `agent` format provides structured, deterministic diagnostics optimized for coding assistants like Codex.
|
|
73
|
+
|
|
74
|
+
Example prompt for a coding agent:
|
|
75
|
+
|
|
76
|
+
```text
|
|
77
|
+
Run `npx sourceverity scan . --format agent`.
|
|
78
|
+
Review high-confidence correctness findings.
|
|
79
|
+
Fix verified correctness issues without modifying unrelated formatting or architecture.
|
|
80
|
+
Run the project's test suite to verify no regressions.
|
|
81
|
+
Run SourceVerity again to verify resolution.
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## TypeScript Strictness Gap Analysis
|
|
87
|
+
|
|
88
|
+
Inspect the safety gaps in your existing `tsconfig.json` and measure migration impact:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
npx sourceverity strictness .
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Example output:
|
|
95
|
+
|
|
96
|
+
```text
|
|
97
|
+
TypeScript Strictness Gap Analysis
|
|
98
|
+
|
|
99
|
+
Current Configuration:
|
|
100
|
+
strict false
|
|
101
|
+
strictNullChecks false
|
|
102
|
+
noUncheckedIndexedAccess false
|
|
103
|
+
exactOptionalPropertyTypes false
|
|
104
|
+
|
|
105
|
+
Migration Impact (New Compiler Diagnostics):
|
|
106
|
+
strictNullChecks 42 diagnostics
|
|
107
|
+
noUncheckedIndexedAccess 18 diagnostics
|
|
108
|
+
exactOptionalPropertyTypes 4 diagnostics
|
|
109
|
+
|
|
110
|
+
Top Affected Files:
|
|
111
|
+
src/api/client.ts 12
|
|
112
|
+
src/state/user.ts 8
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Baseline Management
|
|
118
|
+
|
|
119
|
+
When adopting SourceVerity on an existing codebase with existing findings, generate a baseline to track new regressions without blocking current work:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
# Create or update baseline
|
|
123
|
+
npx sourceverity baseline create
|
|
124
|
+
|
|
125
|
+
# Run scan checking only new findings against baseline
|
|
126
|
+
npx sourceverity scan . --baseline
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Suppressions
|
|
132
|
+
|
|
133
|
+
To suppress an intentional exception, use a line-level suppression comment with a required or strongly recommended explanation:
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
// sourceverity-disable-next-line typescript/unsafe-unvalidated-assertion -- verified by upstream API gateway schema
|
|
137
|
+
const user = JSON.parse(payload) as User;
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Initial Production Rule Set
|
|
143
|
+
|
|
144
|
+
| Rule ID | Category | Default Severity | Confidence | Description |
|
|
145
|
+
| ------- | -------- | ---------------- | ---------- | ----------- |
|
|
146
|
+
| `async/async-foreach` | Async | Error | High | Asynchronous callback passed to `Array.prototype.forEach`. |
|
|
147
|
+
| `async/floating-promise` | Async | Error | High | Unhandled Promise returned in statement position without handling or void operator. |
|
|
148
|
+
| `typescript/unsafe-unvalidated-assertion` | TypeScript | Error | High | Unvalidated runtime data (`JSON.parse`, `response.json()`) asserted directly to a type. |
|
|
149
|
+
| `typescript/non-null-assertion-risk` | TypeScript | Warning | High | Non-null assertion (`!`) on value whose semantic type contains null or undefined. |
|
|
150
|
+
| `typescript/unchecked-index-access` | TypeScript | Warning | Medium | Dynamic property or index access dereferenced without presence check in loose config. |
|
|
151
|
+
| `network/fetch-status-unchecked` | Network | Warning | High | Consuming `fetch()` response body without checking `response.ok` or `response.status`. |
|
|
152
|
+
| `browser/event-listener-cleanup` | Browser | Error | High | `addEventListener` registered in lifecycle scope without matching `removeEventListener`. |
|
|
153
|
+
| `browser/timer-cleanup` | Browser | Error | High | `setInterval` registered in lifecycle scope without corresponding `clearInterval`. |
|
|
154
|
+
| `browser/observer-cleanup` | Browser | Error | High | DOM Observer (`ResizeObserver`, etc.) created in lifecycle scope without `.disconnect()`. |
|
|
155
|
+
| `react/async-effect-callback` | React | Error | High | Async function passed directly as `useEffect` callback argument. |
|
|
156
|
+
| `react/derived-state-effect` | React | Warning | High | `useEffect` used exclusively to derive local state from render inputs. |
|
|
157
|
+
| `react/missing-effect-cleanup` | React | Warning | High | Subscriptions or event targets instantiated in `useEffect` without returned cleanup. |
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Programmatic API
|
|
162
|
+
|
|
163
|
+
SourceVerity exposes a TypeScript programmatic API for build tool and custom CI integrations:
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
import { scanRepository } from "sourceverity";
|
|
167
|
+
|
|
168
|
+
const result = await scanRepository({
|
|
169
|
+
targetDir: process.cwd(),
|
|
170
|
+
minConfidence: "high",
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
console.log(`Found ${result.findings.length} findings across ${result.summary.filesAnalyzed} files.`);
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Requirements & Engines
|
|
179
|
+
|
|
180
|
+
- Node.js >= 20.12.0
|
|
181
|
+
- Supports npm, pnpm, Yarn, and Bun workspaces
|
|
182
|
+
- Analyzes TypeScript (using project's local TypeScript installation) and JavaScript
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## License
|
|
187
|
+
|
|
188
|
+
MIT © 2026 SourceVerity Contributors
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { runCli } from "../dist/cli/main.js";
|
|
4
|
+
|
|
5
|
+
try {
|
|
6
|
+
const code = await runCli(process.argv.slice(2));
|
|
7
|
+
process.exitCode = code;
|
|
8
|
+
} catch (error) {
|
|
9
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
10
|
+
process.stderr.write(`sourceverity: fatal error: ${message}\n`);
|
|
11
|
+
process.exitCode = 3;
|
|
12
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type * as tsType from "typescript";
|
|
2
|
+
export interface GuardCheckResult {
|
|
3
|
+
readonly isGuarded: boolean;
|
|
4
|
+
readonly evidence?: string | undefined;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Checks if a non-null assertion operand is guarded against null/undefined or out-of-bounds access.
|
|
8
|
+
*/
|
|
9
|
+
export declare function isGuardedNonNullAssertion(node: tsType.NonNullExpression, ts: typeof tsType, checker?: tsType.TypeChecker | undefined): GuardCheckResult;
|
|
10
|
+
//# sourceMappingURL=controlFlow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controlFlow.d.ts","sourceRoot":"","sources":["../../src/analysis/controlFlow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,MAAM,YAAY,CAAC;AAG1C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC;AAmQD;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,CAAC,iBAAiB,EAC9B,EAAE,EAAE,OAAO,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,CAAC,WAAW,GAAG,SAAS,GACvC,gBAAgB,CAsGlB"}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { unwrapExpression } from "./values.js";
|
|
2
|
+
/**
|
|
3
|
+
* Checks if a statement definitely exits control flow (return, throw, break, continue).
|
|
4
|
+
*/
|
|
5
|
+
function statementExitsControlFlow(stmt, ts) {
|
|
6
|
+
if (ts.isReturnStatement(stmt) ||
|
|
7
|
+
ts.isThrowStatement(stmt) ||
|
|
8
|
+
ts.isBreakStatement(stmt) ||
|
|
9
|
+
ts.isContinueStatement(stmt)) {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
if (ts.isBlock(stmt)) {
|
|
13
|
+
const stmts = stmt.statements;
|
|
14
|
+
if (stmts.length === 0)
|
|
15
|
+
return false;
|
|
16
|
+
const last = stmts[stmts.length - 1];
|
|
17
|
+
return last !== undefined && statementExitsControlFlow(last, ts);
|
|
18
|
+
}
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
function normalizeIndexExpression(expr, ts, checker) {
|
|
22
|
+
const unwrapped = unwrapExpression(expr, ts);
|
|
23
|
+
if (ts.isIdentifier(unwrapped)) {
|
|
24
|
+
const sym = checker?.getSymbolAtLocation(unwrapped);
|
|
25
|
+
return { baseText: unwrapped.text, baseSymbol: sym, offset: 0 };
|
|
26
|
+
}
|
|
27
|
+
if (ts.isBinaryExpression(unwrapped)) {
|
|
28
|
+
const left = unwrapExpression(unwrapped.left, ts);
|
|
29
|
+
const right = unwrapExpression(unwrapped.right, ts);
|
|
30
|
+
if (ts.isIdentifier(left) && ts.isNumericLiteral(right)) {
|
|
31
|
+
const num = Number(right.text);
|
|
32
|
+
if (!Number.isNaN(num)) {
|
|
33
|
+
const sym = checker?.getSymbolAtLocation(left);
|
|
34
|
+
if (unwrapped.operatorToken.kind === ts.SyntaxKind.PlusToken) {
|
|
35
|
+
return { baseText: left.text, baseSymbol: sym, offset: num };
|
|
36
|
+
}
|
|
37
|
+
if (unwrapped.operatorToken.kind === ts.SyntaxKind.MinusToken) {
|
|
38
|
+
return { baseText: left.text, baseSymbol: sym, offset: -num };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
function normalizeArrayTarget(expr, ts, checker) {
|
|
46
|
+
const unwrapped = unwrapExpression(expr, ts);
|
|
47
|
+
if (ts.isIdentifier(unwrapped)) {
|
|
48
|
+
const sym = checker?.getSymbolAtLocation(unwrapped);
|
|
49
|
+
return { text: unwrapped.text, symbol: sym };
|
|
50
|
+
}
|
|
51
|
+
if (ts.isPropertyAccessExpression(unwrapped)) {
|
|
52
|
+
const sym = checker?.getSymbolAtLocation(unwrapped);
|
|
53
|
+
return { text: unwrapped.getText(), symbol: sym };
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Checks if a binary condition expression guards an index lower bound (e.g. index === -1 or index < 0).
|
|
59
|
+
*/
|
|
60
|
+
function isLowerBoundNegativeGuard(cond, indexInfo, ts) {
|
|
61
|
+
const unwrapped = unwrapExpression(cond, ts);
|
|
62
|
+
if (!ts.isBinaryExpression(unwrapped))
|
|
63
|
+
return false;
|
|
64
|
+
const left = unwrapExpression(unwrapped.left, ts);
|
|
65
|
+
const right = unwrapExpression(unwrapped.right, ts);
|
|
66
|
+
const op = unwrapped.operatorToken.kind;
|
|
67
|
+
// index === -1 or -1 === index
|
|
68
|
+
if (op === ts.SyntaxKind.EqualsEqualsToken || op === ts.SyntaxKind.EqualsEqualsEqualsToken) {
|
|
69
|
+
if (ts.isIdentifier(left) && left.text === indexInfo.baseText) {
|
|
70
|
+
if (ts.isPrefixUnaryExpression(right) && right.operator === ts.SyntaxKind.MinusToken && ts.isNumericLiteral(right.operand) && right.operand.text === "1") {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (ts.isIdentifier(right) && right.text === indexInfo.baseText) {
|
|
75
|
+
if (ts.isPrefixUnaryExpression(left) && left.operator === ts.SyntaxKind.MinusToken && ts.isNumericLiteral(left.operand) && left.operand.text === "1") {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// index < 0
|
|
81
|
+
if (op === ts.SyntaxKind.LessThanToken) {
|
|
82
|
+
if (ts.isIdentifier(left) && left.text === indexInfo.baseText && ts.isNumericLiteral(right) && right.text === "0") {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// 0 > index
|
|
87
|
+
if (op === ts.SyntaxKind.GreaterThanToken) {
|
|
88
|
+
if (ts.isNumericLiteral(left) && left.text === "0" && ts.isIdentifier(right) && right.text === indexInfo.baseText) {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Checks if an expression represents `array.length` or `array.length - K`.
|
|
96
|
+
*/
|
|
97
|
+
function parseArrayLengthOffset(expr, arrayInfo, ts) {
|
|
98
|
+
const unwrapped = unwrapExpression(expr, ts);
|
|
99
|
+
// array.length
|
|
100
|
+
if (ts.isPropertyAccessExpression(unwrapped) && unwrapped.name.text === "length") {
|
|
101
|
+
const obj = unwrapExpression(unwrapped.expression, ts);
|
|
102
|
+
if (ts.isIdentifier(obj) && obj.text === arrayInfo.text) {
|
|
103
|
+
return 0;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// array.length - K
|
|
107
|
+
if (ts.isBinaryExpression(unwrapped) && unwrapped.operatorToken.kind === ts.SyntaxKind.MinusToken) {
|
|
108
|
+
const left = unwrapExpression(unwrapped.left, ts);
|
|
109
|
+
const right = unwrapExpression(unwrapped.right, ts);
|
|
110
|
+
if (ts.isPropertyAccessExpression(left) && left.name.text === "length") {
|
|
111
|
+
const obj = unwrapExpression(left.expression, ts);
|
|
112
|
+
if (ts.isIdentifier(obj) && obj.text === arrayInfo.text && ts.isNumericLiteral(right)) {
|
|
113
|
+
const k = Number(right.text);
|
|
114
|
+
if (!Number.isNaN(k))
|
|
115
|
+
return k;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Checks if a binary condition expression guards an upper bound against array.length.
|
|
123
|
+
* e.g. `index >= array.length` or `index >= array.length - 1` or `index > array.length - 1`.
|
|
124
|
+
*/
|
|
125
|
+
function isUpperBoundLengthGuard(cond, indexInfo, arrayInfo, ts) {
|
|
126
|
+
const unwrapped = unwrapExpression(cond, ts);
|
|
127
|
+
if (!ts.isBinaryExpression(unwrapped))
|
|
128
|
+
return { isGuard: false, maxAllowedOffset: 0 };
|
|
129
|
+
const left = unwrapExpression(unwrapped.left, ts);
|
|
130
|
+
const right = unwrapExpression(unwrapped.right, ts);
|
|
131
|
+
const op = unwrapped.operatorToken.kind;
|
|
132
|
+
// Pattern: `index >= [length expression]`
|
|
133
|
+
if (op === ts.SyntaxKind.GreaterThanEqualsToken && ts.isIdentifier(left) && left.text === indexInfo.baseText) {
|
|
134
|
+
const lengthMinus = parseArrayLengthOffset(right, arrayInfo, ts);
|
|
135
|
+
if (lengthMinus !== undefined) {
|
|
136
|
+
// index >= array.length - lengthMinus (exit)
|
|
137
|
+
// after exit: index < array.length - lengthMinus
|
|
138
|
+
// => index + offset < array.length is safe if offset <= lengthMinus - (lengthMinus === 0 ? 0 : 0) -> offset < lengthMinus + 1 => offset <= lengthMinus
|
|
139
|
+
// Specifically: if lengthMinus === 1 (index >= array.length - 1), then index < array.length - 1, so index + 1 < array.length (offset 1 is safe).
|
|
140
|
+
// If lengthMinus === 0 (index >= array.length), then index < array.length (offset 0 is safe).
|
|
141
|
+
return { isGuard: true, maxAllowedOffset: lengthMinus };
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Pattern: `index > [length expression]`
|
|
145
|
+
if (op === ts.SyntaxKind.GreaterThanToken && ts.isIdentifier(left) && left.text === indexInfo.baseText) {
|
|
146
|
+
const lengthMinus = parseArrayLengthOffset(right, arrayInfo, ts);
|
|
147
|
+
if (lengthMinus !== undefined) {
|
|
148
|
+
// index > array.length - 1 (exit) => index <= array.length - 1 => index < array.length (offset 0 safe)
|
|
149
|
+
return { isGuard: true, maxAllowedOffset: lengthMinus - 1 };
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return { isGuard: false, maxAllowedOffset: 0 };
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Checks if an exit condition contains both a lower-bound check and an upper-bound check.
|
|
156
|
+
*/
|
|
157
|
+
function isCompleteBoundsExitGuard(cond, indexInfo, arrayInfo, ts) {
|
|
158
|
+
// Collect all OR disjuncts: A || B || C
|
|
159
|
+
const disjuncts = [];
|
|
160
|
+
function collectOrs(e) {
|
|
161
|
+
const u = unwrapExpression(e, ts);
|
|
162
|
+
if (ts.isBinaryExpression(u) && u.operatorToken.kind === ts.SyntaxKind.BarBarToken) {
|
|
163
|
+
collectOrs(u.left);
|
|
164
|
+
collectOrs(u.right);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
disjuncts.push(u);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
collectOrs(cond);
|
|
171
|
+
let hasLower = false;
|
|
172
|
+
let maxUpperOffset = -1;
|
|
173
|
+
for (const d of disjuncts) {
|
|
174
|
+
if (isLowerBoundNegativeGuard(d, indexInfo, ts)) {
|
|
175
|
+
hasLower = true;
|
|
176
|
+
}
|
|
177
|
+
const upper = isUpperBoundLengthGuard(d, indexInfo, arrayInfo, ts);
|
|
178
|
+
if (upper.isGuard) {
|
|
179
|
+
maxUpperOffset = Math.max(maxUpperOffset, upper.maxAllowedOffset);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (hasLower && maxUpperOffset >= indexInfo.offset) {
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Checks if a non-null assertion operand is guarded against null/undefined or out-of-bounds access.
|
|
189
|
+
*/
|
|
190
|
+
export function isGuardedNonNullAssertion(node, ts, checker) {
|
|
191
|
+
const operand = unwrapExpression(node.expression, ts);
|
|
192
|
+
// Case 1: Indexed access non-null assertion: `array[index]!`
|
|
193
|
+
if (ts.isElementAccessExpression(operand)) {
|
|
194
|
+
const arrayInfo = normalizeArrayTarget(operand.expression, ts, checker);
|
|
195
|
+
const indexInfo = normalizeIndexExpression(operand.argumentExpression, ts, checker);
|
|
196
|
+
if (arrayInfo && indexInfo) {
|
|
197
|
+
// Find enclosing block / function containing the statement of this node
|
|
198
|
+
let stmt = node;
|
|
199
|
+
while (stmt.parent && !ts.isBlock(stmt.parent) && !ts.isSourceFile(stmt.parent)) {
|
|
200
|
+
stmt = stmt.parent;
|
|
201
|
+
}
|
|
202
|
+
if (stmt.parent && (ts.isBlock(stmt.parent) || ts.isSourceFile(stmt.parent))) {
|
|
203
|
+
const statements = ts.isBlock(stmt.parent) ? stmt.parent.statements : stmt.parent.statements;
|
|
204
|
+
const targetIndex = statements.indexOf(stmt);
|
|
205
|
+
if (targetIndex > 0) {
|
|
206
|
+
// Look at prior sibling statements
|
|
207
|
+
for (let i = 0; i < targetIndex; i++) {
|
|
208
|
+
const prior = statements[i];
|
|
209
|
+
if (!prior)
|
|
210
|
+
continue;
|
|
211
|
+
// Look for early-exit if guard: if (index === -1 || index >= array.length - 1) return null;
|
|
212
|
+
if (ts.isIfStatement(prior)) {
|
|
213
|
+
if (statementExitsControlFlow(prior.thenStatement, ts)) {
|
|
214
|
+
if (isCompleteBoundsExitGuard(prior.expression, indexInfo, arrayInfo, ts)) {
|
|
215
|
+
return {
|
|
216
|
+
isGuarded: true,
|
|
217
|
+
evidence: `Dominating guard '${prior.expression.getText()}' proves index '${indexInfo.baseText}${indexInfo.offset ? ` + ${indexInfo.offset}` : ""}' is strictly in-bounds for '${arrayInfo.text}'.`,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// Case 2: Direct variable / identifier non-null assertion: `target!`
|
|
228
|
+
if (ts.isIdentifier(operand)) {
|
|
229
|
+
const targetName = operand.text;
|
|
230
|
+
let stmt = node;
|
|
231
|
+
while (stmt.parent && !ts.isBlock(stmt.parent) && !ts.isSourceFile(stmt.parent)) {
|
|
232
|
+
stmt = stmt.parent;
|
|
233
|
+
}
|
|
234
|
+
if (stmt.parent && (ts.isBlock(stmt.parent) || ts.isSourceFile(stmt.parent))) {
|
|
235
|
+
const statements = ts.isBlock(stmt.parent) ? stmt.parent.statements : stmt.parent.statements;
|
|
236
|
+
const targetIndex = statements.indexOf(stmt);
|
|
237
|
+
if (targetIndex > 0) {
|
|
238
|
+
for (let i = 0; i < targetIndex; i++) {
|
|
239
|
+
const prior = statements[i];
|
|
240
|
+
if (!prior)
|
|
241
|
+
continue;
|
|
242
|
+
if (ts.isIfStatement(prior) && statementExitsControlFlow(prior.thenStatement, ts)) {
|
|
243
|
+
const cond = unwrapExpression(prior.expression, ts);
|
|
244
|
+
// if (!target) return;
|
|
245
|
+
if (ts.isPrefixUnaryExpression(cond) && cond.operator === ts.SyntaxKind.ExclamationToken) {
|
|
246
|
+
const inner = unwrapExpression(cond.operand, ts);
|
|
247
|
+
if (ts.isIdentifier(inner) && inner.text === targetName) {
|
|
248
|
+
return {
|
|
249
|
+
isGuarded: true,
|
|
250
|
+
evidence: `Dominating guard '!${targetName}' proves operand is non-null.`,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// if (target === null || target === undefined || target == null) return;
|
|
255
|
+
if (ts.isBinaryExpression(cond)) {
|
|
256
|
+
const left = unwrapExpression(cond.left, ts);
|
|
257
|
+
const right = unwrapExpression(cond.right, ts);
|
|
258
|
+
if ((ts.isIdentifier(left) && left.text === targetName) ||
|
|
259
|
+
(ts.isIdentifier(right) && right.text === targetName)) {
|
|
260
|
+
const other = ts.isIdentifier(left) && left.text === targetName ? right : left;
|
|
261
|
+
if (other.kind === ts.SyntaxKind.NullKeyword ||
|
|
262
|
+
other.kind === ts.SyntaxKind.UndefinedKeyword ||
|
|
263
|
+
(ts.isIdentifier(other) && other.text === "undefined")) {
|
|
264
|
+
return {
|
|
265
|
+
isGuarded: true,
|
|
266
|
+
evidence: `Dominating null check proves '${targetName}' is non-null.`,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return { isGuarded: false };
|
|
277
|
+
}
|
|
278
|
+
//# sourceMappingURL=controlFlow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controlFlow.js","sourceRoot":"","sources":["../../src/analysis/controlFlow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type * as tsType from "typescript";
|
|
2
|
+
export interface FrameworkHandlingResult {
|
|
3
|
+
readonly isHandled: boolean;
|
|
4
|
+
readonly isKnownRejecting?: boolean | undefined;
|
|
5
|
+
readonly reason?: string | undefined;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Evaluates whether a CallExpression represents a verified, handled framework API call.
|
|
9
|
+
*/
|
|
10
|
+
export declare function evaluateFrameworkPromiseCall(callExpr: tsType.CallExpression, ts: typeof tsType, checker?: tsType.TypeChecker | undefined): FrameworkHandlingResult;
|
|
11
|
+
//# sourceMappingURL=frameworks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frameworks.d.ts","sourceRoot":"","sources":["../../src/analysis/frameworks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,MAAM,YAAY,CAAC;AAG1C,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC;AAyDD;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,MAAM,CAAC,cAAc,EAC/B,EAAE,EAAE,OAAO,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,CAAC,WAAW,GAAG,SAAS,GACvC,uBAAuB,CA4JzB"}
|