@vibecheckai/cli 3.5.0 → 3.5.2
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/bin/registry.js +214 -237
- package/bin/runners/cli-utils.js +33 -2
- package/bin/runners/context/analyzer.js +52 -1
- package/bin/runners/context/generators/cursor.js +2 -49
- package/bin/runners/context/git-context.js +3 -1
- package/bin/runners/context/team-conventions.js +33 -7
- package/bin/runners/lib/analysis-core.js +25 -5
- package/bin/runners/lib/analyzers.js +431 -481
- package/bin/runners/lib/default-config.js +127 -0
- package/bin/runners/lib/doctor/modules/security.js +3 -1
- package/bin/runners/lib/engine/ast-cache.js +210 -0
- package/bin/runners/lib/engine/auth-extractor.js +211 -0
- package/bin/runners/lib/engine/billing-extractor.js +112 -0
- package/bin/runners/lib/engine/enforcement-extractor.js +100 -0
- package/bin/runners/lib/engine/env-extractor.js +207 -0
- package/bin/runners/lib/engine/express-extractor.js +208 -0
- package/bin/runners/lib/engine/extractors.js +849 -0
- package/bin/runners/lib/engine/index.js +207 -0
- package/bin/runners/lib/engine/repo-index.js +514 -0
- package/bin/runners/lib/engine/types.js +124 -0
- package/bin/runners/lib/engines/accessibility-engine.js +18 -218
- package/bin/runners/lib/engines/api-consistency-engine.js +30 -335
- package/bin/runners/lib/engines/cross-file-analysis-engine.js +27 -292
- package/bin/runners/lib/engines/empty-catch-engine.js +17 -127
- package/bin/runners/lib/engines/mock-data-engine.js +10 -53
- package/bin/runners/lib/engines/performance-issues-engine.js +36 -176
- package/bin/runners/lib/engines/security-vulnerabilities-engine.js +54 -382
- package/bin/runners/lib/engines/type-aware-engine.js +39 -263
- package/bin/runners/lib/engines/vibecheck-engines/index.js +13 -122
- package/bin/runners/lib/engines/vibecheck-engines/lib/ast-cache.js +164 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/code-quality-engine.js +291 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/console-logs-engine.js +83 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/dead-code-engine.js +198 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/deprecated-api-engine.js +275 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/empty-catch-engine.js +167 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/file-filter.js +217 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +73 -373
- package/bin/runners/lib/engines/vibecheck-engines/lib/mock-data-engine.js +140 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/parallel-processor.js +164 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/performance-issues-engine.js +234 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/type-aware-engine.js +217 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/unsafe-regex-engine.js +78 -0
- package/bin/runners/lib/entitlements-v2.js +73 -97
- package/bin/runners/lib/error-handler.js +44 -3
- package/bin/runners/lib/error-messages.js +289 -0
- package/bin/runners/lib/evidence-pack.js +7 -1
- package/bin/runners/lib/finding-id.js +69 -0
- package/bin/runners/lib/finding-sorter.js +89 -0
- package/bin/runners/lib/html-proof-report.js +700 -350
- package/bin/runners/lib/missions/plan.js +6 -46
- package/bin/runners/lib/missions/templates.js +0 -232
- package/bin/runners/lib/next-action.js +560 -0
- package/bin/runners/lib/prerequisites.js +149 -0
- package/bin/runners/lib/route-detection.js +137 -68
- package/bin/runners/lib/scan-output.js +91 -76
- package/bin/runners/lib/scan-runner.js +135 -0
- package/bin/runners/lib/schemas/ajv-validator.js +464 -0
- package/bin/runners/lib/schemas/error-envelope.schema.json +105 -0
- package/bin/runners/lib/schemas/finding-v3.schema.json +151 -0
- package/bin/runners/lib/schemas/report-artifact.schema.json +120 -0
- package/bin/runners/lib/schemas/run-request.schema.json +108 -0
- package/bin/runners/lib/schemas/validator.js +27 -0
- package/bin/runners/lib/schemas/verdict.schema.json +140 -0
- package/bin/runners/lib/ship-output-enterprise.js +23 -23
- package/bin/runners/lib/ship-output.js +75 -31
- package/bin/runners/lib/terminal-ui.js +6 -113
- package/bin/runners/lib/truth.js +351 -10
- package/bin/runners/lib/unified-cli-output.js +430 -603
- package/bin/runners/lib/unified-output.js +13 -9
- package/bin/runners/runAIAgent.js +10 -5
- package/bin/runners/runAgent.js +0 -3
- package/bin/runners/runAllowlist.js +389 -0
- package/bin/runners/runApprove.js +0 -33
- package/bin/runners/runAuth.js +73 -45
- package/bin/runners/runCheckpoint.js +51 -11
- package/bin/runners/runClassify.js +85 -21
- package/bin/runners/runContext.js +0 -3
- package/bin/runners/runDoctor.js +41 -28
- package/bin/runners/runEvidencePack.js +362 -0
- package/bin/runners/runFirewall.js +0 -3
- package/bin/runners/runFirewallHook.js +0 -3
- package/bin/runners/runFix.js +66 -76
- package/bin/runners/runGuard.js +18 -411
- package/bin/runners/runInit.js +113 -30
- package/bin/runners/runLabs.js +424 -0
- package/bin/runners/runMcp.js +19 -25
- package/bin/runners/runPolish.js +64 -240
- package/bin/runners/runPromptFirewall.js +12 -5
- package/bin/runners/runProve.js +57 -22
- package/bin/runners/runQuickstart.js +531 -0
- package/bin/runners/runReality.js +59 -68
- package/bin/runners/runReport.js +38 -33
- package/bin/runners/runRuntime.js +8 -5
- package/bin/runners/runScan.js +1413 -190
- package/bin/runners/runShip.js +113 -719
- package/bin/runners/runTruth.js +0 -3
- package/bin/runners/runValidate.js +13 -9
- package/bin/runners/runWatch.js +23 -14
- package/bin/scan.js +6 -1
- package/bin/vibecheck.js +204 -185
- package/mcp-server/deprecation-middleware.js +282 -0
- package/mcp-server/handlers/index.ts +15 -0
- package/mcp-server/handlers/tool-handler.ts +554 -0
- package/mcp-server/index-v1.js +698 -0
- package/mcp-server/index.js +210 -238
- package/mcp-server/lib/cache-wrapper.cjs +383 -0
- package/mcp-server/lib/error-envelope.js +138 -0
- package/mcp-server/lib/executor.ts +499 -0
- package/mcp-server/lib/index.ts +19 -0
- package/mcp-server/lib/rate-limiter.js +166 -0
- package/mcp-server/lib/sandbox.test.ts +519 -0
- package/mcp-server/lib/sandbox.ts +395 -0
- package/mcp-server/lib/types.ts +267 -0
- package/mcp-server/package.json +12 -3
- package/mcp-server/registry/tool-registry.js +794 -0
- package/mcp-server/registry/tools.json +605 -0
- package/mcp-server/registry.test.ts +334 -0
- package/mcp-server/tests/tier-gating.test.js +297 -0
- package/mcp-server/tier-auth.js +378 -45
- package/mcp-server/tools-v3.js +353 -442
- package/mcp-server/tsconfig.json +37 -0
- package/mcp-server/vibecheck-2.0-tools.js +14 -1
- package/package.json +1 -1
- package/bin/runners/lib/agent-firewall/learning/learning-engine.js +0 -849
- package/bin/runners/lib/audit-logger.js +0 -532
- package/bin/runners/lib/authority/authorities/architecture.js +0 -364
- package/bin/runners/lib/authority/authorities/compliance.js +0 -341
- package/bin/runners/lib/authority/authorities/human.js +0 -343
- package/bin/runners/lib/authority/authorities/quality.js +0 -420
- package/bin/runners/lib/authority/authorities/security.js +0 -228
- package/bin/runners/lib/authority/index.js +0 -293
- package/bin/runners/lib/bundle/bundle-intelligence.js +0 -846
- package/bin/runners/lib/cli-charts.js +0 -368
- package/bin/runners/lib/cli-config-display.js +0 -405
- package/bin/runners/lib/cli-demo.js +0 -275
- package/bin/runners/lib/cli-errors.js +0 -438
- package/bin/runners/lib/cli-help-formatter.js +0 -439
- package/bin/runners/lib/cli-interactive-menu.js +0 -509
- package/bin/runners/lib/cli-prompts.js +0 -441
- package/bin/runners/lib/cli-scan-cards.js +0 -362
- package/bin/runners/lib/compliance-reporter.js +0 -710
- package/bin/runners/lib/conductor/index.js +0 -671
- package/bin/runners/lib/easy/README.md +0 -123
- package/bin/runners/lib/easy/index.js +0 -140
- package/bin/runners/lib/easy/interactive-wizard.js +0 -788
- package/bin/runners/lib/easy/one-click-firewall.js +0 -564
- package/bin/runners/lib/easy/zero-config-reality.js +0 -714
- package/bin/runners/lib/engines/async-patterns-engine.js +0 -444
- package/bin/runners/lib/engines/bundle-size-engine.js +0 -433
- package/bin/runners/lib/engines/confidence-scoring.js +0 -276
- package/bin/runners/lib/engines/context-detection.js +0 -264
- package/bin/runners/lib/engines/database-patterns-engine.js +0 -429
- package/bin/runners/lib/engines/duplicate-code-engine.js +0 -354
- package/bin/runners/lib/engines/env-variables-engine.js +0 -458
- package/bin/runners/lib/engines/error-handling-engine.js +0 -437
- package/bin/runners/lib/engines/false-positive-prevention.js +0 -630
- package/bin/runners/lib/engines/framework-adapters/index.js +0 -607
- package/bin/runners/lib/engines/framework-detection.js +0 -508
- package/bin/runners/lib/engines/import-order-engine.js +0 -429
- package/bin/runners/lib/engines/naming-conventions-engine.js +0 -544
- package/bin/runners/lib/engines/noise-reduction-engine.js +0 -452
- package/bin/runners/lib/engines/orchestrator.js +0 -334
- package/bin/runners/lib/engines/react-patterns-engine.js +0 -457
- package/bin/runners/lib/engines/vibecheck-engines/lib/ai-hallucination-engine.js +0 -806
- package/bin/runners/lib/engines/vibecheck-engines/lib/smart-fix-engine.js +0 -577
- package/bin/runners/lib/engines/vibecheck-engines/lib/vibe-score-engine.js +0 -543
- package/bin/runners/lib/engines/vibecheck-engines.js +0 -514
- package/bin/runners/lib/enhanced-features/index.js +0 -305
- package/bin/runners/lib/enhanced-output.js +0 -631
- package/bin/runners/lib/enterprise.js +0 -300
- package/bin/runners/lib/firewall/command-validator.js +0 -351
- package/bin/runners/lib/firewall/config.js +0 -341
- package/bin/runners/lib/firewall/content-validator.js +0 -519
- package/bin/runners/lib/firewall/index.js +0 -101
- package/bin/runners/lib/firewall/path-validator.js +0 -256
- package/bin/runners/lib/intelligence/cross-repo-intelligence.js +0 -817
- package/bin/runners/lib/mcp-utils.js +0 -425
- package/bin/runners/lib/output/index.js +0 -1022
- package/bin/runners/lib/policy-engine.js +0 -652
- package/bin/runners/lib/polish/autofix/accessibility-fixes.js +0 -333
- package/bin/runners/lib/polish/autofix/async-handlers.js +0 -273
- package/bin/runners/lib/polish/autofix/dead-code.js +0 -280
- package/bin/runners/lib/polish/autofix/imports-optimizer.js +0 -344
- package/bin/runners/lib/polish/autofix/index.js +0 -200
- package/bin/runners/lib/polish/autofix/remove-consoles.js +0 -209
- package/bin/runners/lib/polish/autofix/strengthen-types.js +0 -245
- package/bin/runners/lib/polish/backend-checks.js +0 -148
- package/bin/runners/lib/polish/documentation-checks.js +0 -111
- package/bin/runners/lib/polish/frontend-checks.js +0 -168
- package/bin/runners/lib/polish/index.js +0 -71
- package/bin/runners/lib/polish/infrastructure-checks.js +0 -131
- package/bin/runners/lib/polish/library-detection.js +0 -175
- package/bin/runners/lib/polish/performance-checks.js +0 -100
- package/bin/runners/lib/polish/security-checks.js +0 -148
- package/bin/runners/lib/polish/utils.js +0 -203
- package/bin/runners/lib/prompt-builder.js +0 -540
- package/bin/runners/lib/proof-certificate.js +0 -634
- package/bin/runners/lib/reality/accessibility-audit.js +0 -946
- package/bin/runners/lib/reality/api-contract-validator.js +0 -1012
- package/bin/runners/lib/reality/chaos-engineering.js +0 -1084
- package/bin/runners/lib/reality/performance-tracker.js +0 -1077
- package/bin/runners/lib/reality/scenario-generator.js +0 -1404
- package/bin/runners/lib/reality/visual-regression.js +0 -852
- package/bin/runners/lib/reality-profiler.js +0 -717
- package/bin/runners/lib/replay/flight-recorder-viewer.js +0 -1160
- package/bin/runners/lib/review/ai-code-review.js +0 -832
- package/bin/runners/lib/rules/custom-rule-engine.js +0 -985
- package/bin/runners/lib/sbom-generator.js +0 -641
- package/bin/runners/lib/scan-output-enhanced.js +0 -512
- package/bin/runners/lib/security/owasp-scanner.js +0 -939
- package/bin/runners/lib/validators/contract-validator.js +0 -283
- package/bin/runners/lib/validators/dead-export-detector.js +0 -279
- package/bin/runners/lib/validators/dep-audit.js +0 -245
- package/bin/runners/lib/validators/env-validator.js +0 -319
- package/bin/runners/lib/validators/index.js +0 -120
- package/bin/runners/lib/validators/license-checker.js +0 -252
- package/bin/runners/lib/validators/route-validator.js +0 -290
- package/bin/runners/runAuthority.js +0 -528
- package/bin/runners/runConductor.js +0 -772
- package/bin/runners/runContainer.js +0 -366
- package/bin/runners/runEasy.js +0 -410
- package/bin/runners/runIaC.js +0 -372
- package/bin/runners/runVibe.js +0 -791
- package/mcp-server/tools.js +0 -495
|
@@ -1,437 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Error Handling Engine
|
|
3
|
-
* Detects:
|
|
4
|
-
* - Missing error handling
|
|
5
|
-
* - Swallowed errors (empty catch)
|
|
6
|
-
* - Generic error messages
|
|
7
|
-
* - Error re-throwing without context
|
|
8
|
-
* - Missing error boundaries (React)
|
|
9
|
-
* - Inconsistent error responses (API)
|
|
10
|
-
* - Missing validation error handling
|
|
11
|
-
* - Untyped error catches
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
const { getAST } = require("./ast-cache");
|
|
15
|
-
const traverse = require("@babel/traverse").default;
|
|
16
|
-
const t = require("@babel/types");
|
|
17
|
-
const { shouldExcludeFile, isTestContext, hasIgnoreDirective } = require("./file-filter");
|
|
18
|
-
|
|
19
|
-
function snippetForLine(lines, line) {
|
|
20
|
-
return lines[line - 1] ? lines[line - 1].trim() : "";
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Good error handling patterns
|
|
25
|
-
*/
|
|
26
|
-
const GOOD_ERROR_PATTERNS = {
|
|
27
|
-
logging: [
|
|
28
|
-
/console\.error/,
|
|
29
|
-
/logger\.error/,
|
|
30
|
-
/log\.error/,
|
|
31
|
-
/Sentry\.captureException/,
|
|
32
|
-
/captureException/,
|
|
33
|
-
/reportError/,
|
|
34
|
-
/trackError/,
|
|
35
|
-
/Bugsnag/,
|
|
36
|
-
/Rollbar/,
|
|
37
|
-
],
|
|
38
|
-
rethrowing: [
|
|
39
|
-
/throw\s+/,
|
|
40
|
-
/throw\s+new\s+/,
|
|
41
|
-
],
|
|
42
|
-
returning: [
|
|
43
|
-
/return\s+.*error/i,
|
|
44
|
-
/return\s+.*Error/,
|
|
45
|
-
/return\s+{.*error/i,
|
|
46
|
-
],
|
|
47
|
-
handling: [
|
|
48
|
-
/if\s*\(/,
|
|
49
|
-
/switch\s*\(/,
|
|
50
|
-
/instanceof/,
|
|
51
|
-
],
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Generic error messages that should be more specific
|
|
56
|
-
*/
|
|
57
|
-
const GENERIC_ERROR_MESSAGES = [
|
|
58
|
-
/['"]something went wrong['"]/i,
|
|
59
|
-
/['"]an error occurred['"]/i,
|
|
60
|
-
/['"]error['"]\s*$/i,
|
|
61
|
-
/['"]unknown error['"]/i,
|
|
62
|
-
/['"]oops['"]/i,
|
|
63
|
-
/['"]failed['"]\s*$/i,
|
|
64
|
-
];
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Check if catch block has meaningful handling
|
|
68
|
-
*/
|
|
69
|
-
function hasMeaningfulHandling(catchBlock, code) {
|
|
70
|
-
if (!catchBlock || !t.isBlockStatement(catchBlock)) return false;
|
|
71
|
-
|
|
72
|
-
// Empty catch block
|
|
73
|
-
if (catchBlock.body.length === 0) return false;
|
|
74
|
-
|
|
75
|
-
const blockCode = code.substring(catchBlock.start, catchBlock.end);
|
|
76
|
-
|
|
77
|
-
// Check for good patterns
|
|
78
|
-
for (const patterns of Object.values(GOOD_ERROR_PATTERNS)) {
|
|
79
|
-
if (patterns.some(p => p.test(blockCode))) {
|
|
80
|
-
return true;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Check if has any statements (not just comments)
|
|
85
|
-
const hasStatements = catchBlock.body.some(stmt => !t.isEmptyStatement(stmt));
|
|
86
|
-
|
|
87
|
-
return hasStatements;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Check if error message is generic
|
|
92
|
-
*/
|
|
93
|
-
function isGenericErrorMessage(message) {
|
|
94
|
-
return GENERIC_ERROR_MESSAGES.some(p => p.test(message));
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Analyze error handling patterns
|
|
99
|
-
*/
|
|
100
|
-
function analyzeErrorHandling(code, filePath) {
|
|
101
|
-
const findings = [];
|
|
102
|
-
|
|
103
|
-
if (shouldExcludeFile(filePath)) return findings;
|
|
104
|
-
if (isTestContext(code, filePath)) return findings;
|
|
105
|
-
if (hasIgnoreDirective(code, "error-handling")) return findings;
|
|
106
|
-
|
|
107
|
-
const ast = getAST(code, filePath);
|
|
108
|
-
if (!ast) return findings;
|
|
109
|
-
|
|
110
|
-
const lines = code.split("\n");
|
|
111
|
-
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
112
|
-
const isAPIRoute = normalizedPath.includes("/api/") || normalizedPath.includes("/routes/");
|
|
113
|
-
|
|
114
|
-
// Track error response patterns
|
|
115
|
-
const errorResponsePatterns = new Set();
|
|
116
|
-
|
|
117
|
-
traverse(ast, {
|
|
118
|
-
// Analyze catch blocks
|
|
119
|
-
CatchClause(path) {
|
|
120
|
-
const node = path.node;
|
|
121
|
-
const loc = node.loc?.start;
|
|
122
|
-
if (!loc) return;
|
|
123
|
-
|
|
124
|
-
const catchBody = node.body;
|
|
125
|
-
const param = node.param;
|
|
126
|
-
|
|
127
|
-
// Check for empty catch
|
|
128
|
-
if (!hasMeaningfulHandling(catchBody, code)) {
|
|
129
|
-
// Check for intentional comment
|
|
130
|
-
const blockCode = code.substring(catchBody.start, catchBody.end);
|
|
131
|
-
const hasIntentionalComment = /intentional|expected|ignore|safe|ok/i.test(blockCode);
|
|
132
|
-
|
|
133
|
-
if (!hasIntentionalComment) {
|
|
134
|
-
findings.push({
|
|
135
|
-
type: "empty_catch",
|
|
136
|
-
severity: "WARN",
|
|
137
|
-
category: "ErrorHandling",
|
|
138
|
-
file: filePath,
|
|
139
|
-
line: loc.line,
|
|
140
|
-
column: loc.column,
|
|
141
|
-
title: "Empty or minimal catch block",
|
|
142
|
-
message: "Errors are being swallowed without logging or handling.",
|
|
143
|
-
codeSnippet: snippetForLine(lines, loc.line),
|
|
144
|
-
confidence: "high",
|
|
145
|
-
fixHint: "Log the error or re-throw with context",
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Check for untyped catch parameter (TypeScript)
|
|
151
|
-
if (param && t.isIdentifier(param) && filePath.endsWith(".ts")) {
|
|
152
|
-
// In TypeScript, catch param is 'unknown' by default in strict mode
|
|
153
|
-
// but many codebases use 'any' or no annotation
|
|
154
|
-
const hasTypeAnnotation = param.typeAnnotation;
|
|
155
|
-
|
|
156
|
-
if (!hasTypeAnnotation) {
|
|
157
|
-
findings.push({
|
|
158
|
-
type: "untyped_catch",
|
|
159
|
-
severity: "INFO",
|
|
160
|
-
category: "ErrorHandling",
|
|
161
|
-
file: filePath,
|
|
162
|
-
line: loc.line,
|
|
163
|
-
column: loc.column,
|
|
164
|
-
title: "Catch parameter not typed",
|
|
165
|
-
message: "Consider typing catch parameter as 'unknown' and checking type before use.",
|
|
166
|
-
codeSnippet: snippetForLine(lines, loc.line),
|
|
167
|
-
confidence: "low",
|
|
168
|
-
fixHint: "catch (error: unknown) { if (error instanceof Error) { ... } }",
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Check for console.log instead of console.error
|
|
174
|
-
traverse(catchBody, {
|
|
175
|
-
CallExpression(innerPath) {
|
|
176
|
-
const callee = innerPath.node.callee;
|
|
177
|
-
if (t.isMemberExpression(callee) &&
|
|
178
|
-
t.isIdentifier(callee.object, { name: "console" }) &&
|
|
179
|
-
t.isIdentifier(callee.property, { name: "log" })) {
|
|
180
|
-
|
|
181
|
-
const innerLoc = innerPath.node.loc?.start;
|
|
182
|
-
if (innerLoc) {
|
|
183
|
-
findings.push({
|
|
184
|
-
type: "console_log_in_catch",
|
|
185
|
-
severity: "INFO",
|
|
186
|
-
category: "ErrorHandling",
|
|
187
|
-
file: filePath,
|
|
188
|
-
line: innerLoc.line,
|
|
189
|
-
column: innerLoc.column,
|
|
190
|
-
title: "console.log in catch block",
|
|
191
|
-
message: "Use console.error for error logging to distinguish from regular logs.",
|
|
192
|
-
codeSnippet: snippetForLine(lines, innerLoc.line),
|
|
193
|
-
confidence: "med",
|
|
194
|
-
fixHint: "Change to console.error(error)",
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
},
|
|
199
|
-
noScope: true,
|
|
200
|
-
}, path.scope);
|
|
201
|
-
|
|
202
|
-
// Check for error being thrown without additional context
|
|
203
|
-
traverse(catchBody, {
|
|
204
|
-
ThrowStatement(innerPath) {
|
|
205
|
-
const argument = innerPath.node.argument;
|
|
206
|
-
|
|
207
|
-
// Just rethrowing the same error
|
|
208
|
-
if (t.isIdentifier(argument) && param && t.isIdentifier(param) &&
|
|
209
|
-
argument.name === param.name) {
|
|
210
|
-
|
|
211
|
-
const innerLoc = innerPath.node.loc?.start;
|
|
212
|
-
if (innerLoc) {
|
|
213
|
-
findings.push({
|
|
214
|
-
type: "rethrow_without_context",
|
|
215
|
-
severity: "INFO",
|
|
216
|
-
category: "ErrorHandling",
|
|
217
|
-
file: filePath,
|
|
218
|
-
line: innerLoc.line,
|
|
219
|
-
column: innerLoc.column,
|
|
220
|
-
title: "Error rethrown without context",
|
|
221
|
-
message: "Consider wrapping with additional context for better debugging.",
|
|
222
|
-
codeSnippet: snippetForLine(lines, innerLoc.line),
|
|
223
|
-
confidence: "low",
|
|
224
|
-
fixHint: "throw new Error(`Context: ${error.message}`, { cause: error })",
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
},
|
|
229
|
-
noScope: true,
|
|
230
|
-
}, path.scope);
|
|
231
|
-
},
|
|
232
|
-
|
|
233
|
-
// Check for try without catch or finally
|
|
234
|
-
TryStatement(path) {
|
|
235
|
-
const node = path.node;
|
|
236
|
-
const loc = node.loc?.start;
|
|
237
|
-
if (!loc) return;
|
|
238
|
-
|
|
239
|
-
if (!node.handler && !node.finalizer) {
|
|
240
|
-
findings.push({
|
|
241
|
-
type: "try_without_catch",
|
|
242
|
-
severity: "WARN",
|
|
243
|
-
category: "ErrorHandling",
|
|
244
|
-
file: filePath,
|
|
245
|
-
line: loc.line,
|
|
246
|
-
column: loc.column,
|
|
247
|
-
title: "try without catch or finally",
|
|
248
|
-
message: "try statement has no error handling.",
|
|
249
|
-
codeSnippet: snippetForLine(lines, loc.line),
|
|
250
|
-
confidence: "high",
|
|
251
|
-
fixHint: "Add catch block to handle errors",
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
},
|
|
255
|
-
|
|
256
|
-
// Check for generic error messages
|
|
257
|
-
NewExpression(path) {
|
|
258
|
-
const node = path.node;
|
|
259
|
-
const loc = node.loc?.start;
|
|
260
|
-
if (!loc) return;
|
|
261
|
-
|
|
262
|
-
if (t.isIdentifier(node.callee, { name: "Error" }) ||
|
|
263
|
-
(t.isIdentifier(node.callee) && node.callee.name.endsWith("Error"))) {
|
|
264
|
-
|
|
265
|
-
const args = node.arguments;
|
|
266
|
-
if (args.length > 0 && t.isStringLiteral(args[0])) {
|
|
267
|
-
const message = args[0].value;
|
|
268
|
-
|
|
269
|
-
if (isGenericErrorMessage(message)) {
|
|
270
|
-
findings.push({
|
|
271
|
-
type: "generic_error_message",
|
|
272
|
-
severity: "INFO",
|
|
273
|
-
category: "ErrorHandling",
|
|
274
|
-
file: filePath,
|
|
275
|
-
line: loc.line,
|
|
276
|
-
column: loc.column,
|
|
277
|
-
title: "Generic error message",
|
|
278
|
-
message: `Error message "${message}" is not descriptive. Include specific context.`,
|
|
279
|
-
codeSnippet: snippetForLine(lines, loc.line),
|
|
280
|
-
confidence: "med",
|
|
281
|
-
fixHint: "Include what failed and why: 'Failed to fetch user: invalid ID'",
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
},
|
|
287
|
-
|
|
288
|
-
// Check API error responses for consistency
|
|
289
|
-
CallExpression(path) {
|
|
290
|
-
const node = path.node;
|
|
291
|
-
const callee = node.callee;
|
|
292
|
-
const loc = node.loc?.start;
|
|
293
|
-
if (!loc) return;
|
|
294
|
-
|
|
295
|
-
// Check for NextResponse.json() or res.json() error patterns
|
|
296
|
-
if (isAPIRoute) {
|
|
297
|
-
let isErrorResponse = false;
|
|
298
|
-
let responseShape = null;
|
|
299
|
-
|
|
300
|
-
// NextResponse.json({ error: ... }, { status: 4xx })
|
|
301
|
-
if (t.isMemberExpression(callee) &&
|
|
302
|
-
t.isIdentifier(callee.object, { name: "NextResponse" }) &&
|
|
303
|
-
t.isIdentifier(callee.property, { name: "json" })) {
|
|
304
|
-
|
|
305
|
-
if (node.arguments.length >= 2) {
|
|
306
|
-
const options = node.arguments[1];
|
|
307
|
-
if (t.isObjectExpression(options)) {
|
|
308
|
-
const statusProp = options.properties.find(p =>
|
|
309
|
-
t.isObjectProperty(p) &&
|
|
310
|
-
t.isIdentifier(p.key, { name: "status" }) &&
|
|
311
|
-
t.isNumericLiteral(p.value)
|
|
312
|
-
);
|
|
313
|
-
|
|
314
|
-
if (statusProp && statusProp.value.value >= 400) {
|
|
315
|
-
isErrorResponse = true;
|
|
316
|
-
|
|
317
|
-
// Get response shape
|
|
318
|
-
const body = node.arguments[0];
|
|
319
|
-
if (t.isObjectExpression(body)) {
|
|
320
|
-
responseShape = body.properties
|
|
321
|
-
.filter(p => t.isObjectProperty(p) && t.isIdentifier(p.key))
|
|
322
|
-
.map(p => p.key.name)
|
|
323
|
-
.sort()
|
|
324
|
-
.join(",");
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// res.status(4xx).json({ error: ... })
|
|
332
|
-
if (t.isMemberExpression(callee) &&
|
|
333
|
-
t.isIdentifier(callee.property, { name: "json" }) &&
|
|
334
|
-
t.isCallExpression(callee.object)) {
|
|
335
|
-
|
|
336
|
-
const statusCall = callee.object;
|
|
337
|
-
if (t.isMemberExpression(statusCall.callee) &&
|
|
338
|
-
t.isIdentifier(statusCall.callee.property, { name: "status" }) &&
|
|
339
|
-
statusCall.arguments.length > 0 &&
|
|
340
|
-
t.isNumericLiteral(statusCall.arguments[0]) &&
|
|
341
|
-
statusCall.arguments[0].value >= 400) {
|
|
342
|
-
|
|
343
|
-
isErrorResponse = true;
|
|
344
|
-
|
|
345
|
-
// Get response shape
|
|
346
|
-
const body = node.arguments[0];
|
|
347
|
-
if (t.isObjectExpression(body)) {
|
|
348
|
-
responseShape = body.properties
|
|
349
|
-
.filter(p => t.isObjectProperty(p) && t.isIdentifier(p.key))
|
|
350
|
-
.map(p => p.key.name)
|
|
351
|
-
.sort()
|
|
352
|
-
.join(",");
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
if (isErrorResponse && responseShape) {
|
|
358
|
-
errorResponsePatterns.add(responseShape);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
},
|
|
362
|
-
|
|
363
|
-
// Check for missing .catch() on promises
|
|
364
|
-
MemberExpression(path) {
|
|
365
|
-
const node = path.node;
|
|
366
|
-
const loc = node.loc?.start;
|
|
367
|
-
if (!loc) return;
|
|
368
|
-
|
|
369
|
-
// Check for .then() without .catch()
|
|
370
|
-
if (t.isIdentifier(node.property, { name: "then" })) {
|
|
371
|
-
const parent = path.parentPath;
|
|
372
|
-
|
|
373
|
-
if (parent.isCallExpression() && parent.node.callee === node) {
|
|
374
|
-
// Check if there's a .catch() after
|
|
375
|
-
const grandparent = parent.parentPath;
|
|
376
|
-
|
|
377
|
-
if (!grandparent.isMemberExpression() ||
|
|
378
|
-
!t.isIdentifier(grandparent.node.property, { name: "catch" })) {
|
|
379
|
-
|
|
380
|
-
// Check if the .then() callback handles errors
|
|
381
|
-
const thenArgs = parent.node.arguments;
|
|
382
|
-
const hasErrorHandler = thenArgs.length >= 2; // Second arg is error handler
|
|
383
|
-
|
|
384
|
-
if (!hasErrorHandler) {
|
|
385
|
-
// Check if result is returned or awaited (will propagate)
|
|
386
|
-
const returnParent = parent.findParent(p => p.isReturnStatement());
|
|
387
|
-
const awaitParent = parent.findParent(p => p.isAwaitExpression());
|
|
388
|
-
|
|
389
|
-
if (!returnParent && !awaitParent) {
|
|
390
|
-
findings.push({
|
|
391
|
-
type: "then_without_catch",
|
|
392
|
-
severity: "INFO",
|
|
393
|
-
category: "ErrorHandling",
|
|
394
|
-
file: filePath,
|
|
395
|
-
line: loc.line,
|
|
396
|
-
column: loc.column,
|
|
397
|
-
title: ".then() without .catch()",
|
|
398
|
-
message: "Promise may have unhandled rejections.",
|
|
399
|
-
codeSnippet: snippetForLine(lines, loc.line),
|
|
400
|
-
confidence: "low",
|
|
401
|
-
fixHint: "Add .catch() or use async/await with try/catch",
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
},
|
|
409
|
-
});
|
|
410
|
-
|
|
411
|
-
// Check for inconsistent error response patterns
|
|
412
|
-
if (isAPIRoute && errorResponsePatterns.size > 1) {
|
|
413
|
-
findings.push({
|
|
414
|
-
type: "inconsistent_error_response",
|
|
415
|
-
severity: "INFO",
|
|
416
|
-
category: "ErrorHandling",
|
|
417
|
-
file: filePath,
|
|
418
|
-
line: 1,
|
|
419
|
-
column: 0,
|
|
420
|
-
title: "Inconsistent error response shapes",
|
|
421
|
-
message: `Found ${errorResponsePatterns.size} different error response shapes. Standardize error format.`,
|
|
422
|
-
codeSnippet: "",
|
|
423
|
-
confidence: "low",
|
|
424
|
-
fixHint: "Use consistent shape: { error: { message, code, details? } }",
|
|
425
|
-
});
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
return findings;
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
module.exports = {
|
|
432
|
-
analyzeErrorHandling,
|
|
433
|
-
hasMeaningfulHandling,
|
|
434
|
-
isGenericErrorMessage,
|
|
435
|
-
GOOD_ERROR_PATTERNS,
|
|
436
|
-
GENERIC_ERROR_MESSAGES,
|
|
437
|
-
};
|