@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,544 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Naming Conventions Engine
|
|
3
|
-
* Detects:
|
|
4
|
-
* - Inconsistent naming styles (camelCase, PascalCase, snake_case)
|
|
5
|
-
* - Non-descriptive names (single letters, abbreviations)
|
|
6
|
-
* - Boolean naming (should start with is/has/can/should)
|
|
7
|
-
* - React component naming conventions
|
|
8
|
-
* - File naming consistency
|
|
9
|
-
* - Constants naming (UPPER_SNAKE_CASE)
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
const { getAST } = require("./ast-cache");
|
|
13
|
-
const traverse = require("@babel/traverse").default;
|
|
14
|
-
const t = require("@babel/types");
|
|
15
|
-
const { shouldExcludeFile, isTestContext, hasIgnoreDirective } = require("./file-filter");
|
|
16
|
-
const path = require("path");
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Naming patterns
|
|
20
|
-
*/
|
|
21
|
-
const PATTERNS = {
|
|
22
|
-
camelCase: /^[a-z][a-zA-Z0-9]*$/,
|
|
23
|
-
PascalCase: /^[A-Z][a-zA-Z0-9]*$/,
|
|
24
|
-
UPPER_SNAKE_CASE: /^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$/,
|
|
25
|
-
snake_case: /^[a-z][a-z0-9]*(_[a-z0-9]+)*$/,
|
|
26
|
-
kebab_case: /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/,
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Common acceptable short names
|
|
31
|
-
*/
|
|
32
|
-
const ACCEPTABLE_SHORT_NAMES = new Set([
|
|
33
|
-
// Loop variables
|
|
34
|
-
"i", "j", "k", "n", "x", "y", "z",
|
|
35
|
-
// Common abbreviations
|
|
36
|
-
"id", "db", "fs", "os", "io", "ui", "fn", "cb", "el", "ev", "re",
|
|
37
|
-
// Destructuring placeholders
|
|
38
|
-
"_",
|
|
39
|
-
// React refs
|
|
40
|
-
"ref",
|
|
41
|
-
// Error
|
|
42
|
-
"e", "err",
|
|
43
|
-
// Event
|
|
44
|
-
"evt",
|
|
45
|
-
// Props
|
|
46
|
-
"p",
|
|
47
|
-
// Context
|
|
48
|
-
"ctx", "c",
|
|
49
|
-
// Key/Value
|
|
50
|
-
"k", "v",
|
|
51
|
-
// Temp
|
|
52
|
-
"t",
|
|
53
|
-
// Result
|
|
54
|
-
"r",
|
|
55
|
-
]);
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Boolean prefixes
|
|
59
|
-
*/
|
|
60
|
-
const BOOLEAN_PREFIXES = ["is", "has", "can", "should", "will", "did", "was", "are", "does", "do"];
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Hook patterns
|
|
64
|
-
*/
|
|
65
|
-
const HOOK_PATTERN = /^use[A-Z]/;
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Check naming style
|
|
69
|
-
*/
|
|
70
|
-
function detectNamingStyle(name) {
|
|
71
|
-
if (PATTERNS.UPPER_SNAKE_CASE.test(name)) return "UPPER_SNAKE_CASE";
|
|
72
|
-
if (PATTERNS.PascalCase.test(name)) return "PascalCase";
|
|
73
|
-
if (PATTERNS.camelCase.test(name)) return "camelCase";
|
|
74
|
-
if (PATTERNS.snake_case.test(name)) return "snake_case";
|
|
75
|
-
return "mixed";
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Check if name looks like a boolean
|
|
80
|
-
*/
|
|
81
|
-
function looksLikeBoolean(name, isActuallyBoolean = false) {
|
|
82
|
-
// If it's actually a boolean type, check if it follows convention
|
|
83
|
-
if (isActuallyBoolean) {
|
|
84
|
-
return BOOLEAN_PREFIXES.some(prefix =>
|
|
85
|
-
name.startsWith(prefix) && name.length > prefix.length
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Check if name suggests boolean but might not follow convention
|
|
90
|
-
const booleanSuffixes = ["flag", "enabled", "disabled", "active", "visible", "hidden", "loading", "loaded"];
|
|
91
|
-
return booleanSuffixes.some(suffix => name.toLowerCase().endsWith(suffix));
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Check if it's a React component name
|
|
96
|
-
*/
|
|
97
|
-
function isComponentName(name) {
|
|
98
|
-
return PATTERNS.PascalCase.test(name);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Check if it's a hook name
|
|
103
|
-
*/
|
|
104
|
-
function isHookName(name) {
|
|
105
|
-
return HOOK_PATTERN.test(name);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Get expected naming style for context
|
|
110
|
-
*/
|
|
111
|
-
function getExpectedStyle(context) {
|
|
112
|
-
switch (context) {
|
|
113
|
-
case "component":
|
|
114
|
-
return "PascalCase";
|
|
115
|
-
case "hook":
|
|
116
|
-
return "camelCase starting with 'use'";
|
|
117
|
-
case "constant":
|
|
118
|
-
return "UPPER_SNAKE_CASE";
|
|
119
|
-
case "function":
|
|
120
|
-
case "variable":
|
|
121
|
-
case "parameter":
|
|
122
|
-
return "camelCase";
|
|
123
|
-
case "class":
|
|
124
|
-
case "type":
|
|
125
|
-
case "interface":
|
|
126
|
-
return "PascalCase";
|
|
127
|
-
default:
|
|
128
|
-
return "camelCase";
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function snippetForLine(lines, line) {
|
|
133
|
-
return lines[line - 1] ? lines[line - 1].trim() : "";
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Analyze naming conventions
|
|
138
|
-
*/
|
|
139
|
-
function analyzeNamingConventions(code, filePath) {
|
|
140
|
-
const findings = [];
|
|
141
|
-
|
|
142
|
-
if (shouldExcludeFile(filePath)) return findings;
|
|
143
|
-
if (isTestContext(code, filePath)) return findings;
|
|
144
|
-
if (hasIgnoreDirective(code, "naming-conventions")) return findings;
|
|
145
|
-
|
|
146
|
-
const ast = getAST(code, filePath);
|
|
147
|
-
if (!ast) return findings;
|
|
148
|
-
|
|
149
|
-
const lines = code.split("\n");
|
|
150
|
-
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
151
|
-
const fileName = path.basename(filePath);
|
|
152
|
-
const isReactFile = /\.(tsx|jsx)$/.test(filePath);
|
|
153
|
-
|
|
154
|
-
// Track naming styles used in the file for consistency checking
|
|
155
|
-
const functionStyles = new Map();
|
|
156
|
-
const variableStyles = new Map();
|
|
157
|
-
|
|
158
|
-
traverse(ast, {
|
|
159
|
-
// Check function declarations
|
|
160
|
-
FunctionDeclaration(pathNode) {
|
|
161
|
-
const node = pathNode.node;
|
|
162
|
-
const name = node.id?.name;
|
|
163
|
-
if (!name) return;
|
|
164
|
-
|
|
165
|
-
const loc = node.loc?.start;
|
|
166
|
-
if (!loc) return;
|
|
167
|
-
|
|
168
|
-
const style = detectNamingStyle(name);
|
|
169
|
-
functionStyles.set(name, style);
|
|
170
|
-
|
|
171
|
-
// React components should be PascalCase
|
|
172
|
-
if (isReactFile && returnsJSX(pathNode) && !isComponentName(name)) {
|
|
173
|
-
findings.push({
|
|
174
|
-
type: "naming_convention",
|
|
175
|
-
severity: "INFO",
|
|
176
|
-
category: "NamingConventions",
|
|
177
|
-
file: filePath,
|
|
178
|
-
line: loc.line,
|
|
179
|
-
column: loc.column,
|
|
180
|
-
title: `Component should be PascalCase: ${name}`,
|
|
181
|
-
message: `React component '${name}' should use PascalCase naming.`,
|
|
182
|
-
codeSnippet: snippetForLine(lines, loc.line),
|
|
183
|
-
confidence: "med",
|
|
184
|
-
fixHint: `Rename to ${toPascalCase(name)}`,
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// Hooks should start with 'use'
|
|
189
|
-
if (isReactFile && usesHooks(pathNode) && !isHookName(name) && !isComponentName(name)) {
|
|
190
|
-
findings.push({
|
|
191
|
-
type: "naming_convention",
|
|
192
|
-
severity: "INFO",
|
|
193
|
-
category: "NamingConventions",
|
|
194
|
-
file: filePath,
|
|
195
|
-
line: loc.line,
|
|
196
|
-
column: loc.column,
|
|
197
|
-
title: `Custom hook should start with 'use': ${name}`,
|
|
198
|
-
message: `Function '${name}' uses React hooks but doesn't follow hook naming convention.`,
|
|
199
|
-
codeSnippet: snippetForLine(lines, loc.line),
|
|
200
|
-
confidence: "low",
|
|
201
|
-
fixHint: `Rename to use${toPascalCase(name)}`,
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// Check for non-descriptive names
|
|
206
|
-
if (name.length <= 2 && !ACCEPTABLE_SHORT_NAMES.has(name)) {
|
|
207
|
-
findings.push({
|
|
208
|
-
type: "non_descriptive_name",
|
|
209
|
-
severity: "INFO",
|
|
210
|
-
category: "NamingConventions",
|
|
211
|
-
file: filePath,
|
|
212
|
-
line: loc.line,
|
|
213
|
-
column: loc.column,
|
|
214
|
-
title: `Non-descriptive function name: ${name}`,
|
|
215
|
-
message: `Function name '${name}' is too short. Use a more descriptive name.`,
|
|
216
|
-
codeSnippet: snippetForLine(lines, loc.line),
|
|
217
|
-
confidence: "low",
|
|
218
|
-
fixHint: "Use a descriptive name that explains the function's purpose",
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
},
|
|
222
|
-
|
|
223
|
-
// Check variable declarations
|
|
224
|
-
VariableDeclarator(pathNode) {
|
|
225
|
-
const node = pathNode.node;
|
|
226
|
-
if (!t.isIdentifier(node.id)) return;
|
|
227
|
-
|
|
228
|
-
const name = node.id.name;
|
|
229
|
-
const loc = node.loc?.start || pathNode.parentPath.node.loc?.start;
|
|
230
|
-
if (!loc) return;
|
|
231
|
-
|
|
232
|
-
const style = detectNamingStyle(name);
|
|
233
|
-
const kind = pathNode.parentPath.node.kind; // const, let, var
|
|
234
|
-
|
|
235
|
-
// Check for constants that should be UPPER_SNAKE_CASE
|
|
236
|
-
if (kind === "const" && t.isLiteral(node.init) && !t.isTemplateLiteral(node.init)) {
|
|
237
|
-
// Module-level constants
|
|
238
|
-
const isModuleLevel = pathNode.parentPath.parentPath.isProgram();
|
|
239
|
-
|
|
240
|
-
if (isModuleLevel && style !== "UPPER_SNAKE_CASE" && name.length > 3) {
|
|
241
|
-
// Skip if it's clearly not a constant (function, object, etc.)
|
|
242
|
-
if (t.isStringLiteral(node.init) || t.isNumericLiteral(node.init)) {
|
|
243
|
-
findings.push({
|
|
244
|
-
type: "constant_naming",
|
|
245
|
-
severity: "INFO",
|
|
246
|
-
category: "NamingConventions",
|
|
247
|
-
file: filePath,
|
|
248
|
-
line: loc.line,
|
|
249
|
-
column: loc.column,
|
|
250
|
-
title: `Constant should be UPPER_SNAKE_CASE: ${name}`,
|
|
251
|
-
message: `Module-level constant '${name}' should use UPPER_SNAKE_CASE.`,
|
|
252
|
-
codeSnippet: snippetForLine(lines, loc.line),
|
|
253
|
-
confidence: "low",
|
|
254
|
-
fixHint: `Rename to ${toUpperSnakeCase(name)}`,
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// Check for arrow function components
|
|
261
|
-
if (isReactFile &&
|
|
262
|
-
(t.isArrowFunctionExpression(node.init) || t.isFunctionExpression(node.init)) &&
|
|
263
|
-
returnsJSXFromInit(node.init, pathNode)) {
|
|
264
|
-
|
|
265
|
-
if (!isComponentName(name)) {
|
|
266
|
-
findings.push({
|
|
267
|
-
type: "naming_convention",
|
|
268
|
-
severity: "INFO",
|
|
269
|
-
category: "NamingConventions",
|
|
270
|
-
file: filePath,
|
|
271
|
-
line: loc.line,
|
|
272
|
-
column: loc.column,
|
|
273
|
-
title: `Component should be PascalCase: ${name}`,
|
|
274
|
-
message: `React component '${name}' should use PascalCase naming.`,
|
|
275
|
-
codeSnippet: snippetForLine(lines, loc.line),
|
|
276
|
-
confidence: "med",
|
|
277
|
-
fixHint: `Rename to ${toPascalCase(name)}`,
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// Check for boolean variables
|
|
283
|
-
if (node.init && (t.isBooleanLiteral(node.init) || isComparisonExpression(node.init))) {
|
|
284
|
-
if (!looksLikeBoolean(name, true)) {
|
|
285
|
-
findings.push({
|
|
286
|
-
type: "boolean_naming",
|
|
287
|
-
severity: "INFO",
|
|
288
|
-
category: "NamingConventions",
|
|
289
|
-
file: filePath,
|
|
290
|
-
line: loc.line,
|
|
291
|
-
column: loc.column,
|
|
292
|
-
title: `Boolean should use is/has/can prefix: ${name}`,
|
|
293
|
-
message: `Boolean variable '${name}' should start with is, has, can, should, etc.`,
|
|
294
|
-
codeSnippet: snippetForLine(lines, loc.line),
|
|
295
|
-
confidence: "low",
|
|
296
|
-
fixHint: `Rename to is${toPascalCase(name)} or has${toPascalCase(name)}`,
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
},
|
|
301
|
-
|
|
302
|
-
// Check class names
|
|
303
|
-
ClassDeclaration(pathNode) {
|
|
304
|
-
const node = pathNode.node;
|
|
305
|
-
const name = node.id?.name;
|
|
306
|
-
if (!name) return;
|
|
307
|
-
|
|
308
|
-
const loc = node.loc?.start;
|
|
309
|
-
if (!loc) return;
|
|
310
|
-
|
|
311
|
-
if (!PATTERNS.PascalCase.test(name)) {
|
|
312
|
-
findings.push({
|
|
313
|
-
type: "naming_convention",
|
|
314
|
-
severity: "WARN",
|
|
315
|
-
category: "NamingConventions",
|
|
316
|
-
file: filePath,
|
|
317
|
-
line: loc.line,
|
|
318
|
-
column: loc.column,
|
|
319
|
-
title: `Class should be PascalCase: ${name}`,
|
|
320
|
-
message: `Class name '${name}' should use PascalCase.`,
|
|
321
|
-
codeSnippet: snippetForLine(lines, loc.line),
|
|
322
|
-
confidence: "high",
|
|
323
|
-
fixHint: `Rename to ${toPascalCase(name)}`,
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
},
|
|
327
|
-
|
|
328
|
-
// Check TypeScript interfaces and types
|
|
329
|
-
TSInterfaceDeclaration(pathNode) {
|
|
330
|
-
const node = pathNode.node;
|
|
331
|
-
const name = node.id?.name;
|
|
332
|
-
if (!name) return;
|
|
333
|
-
|
|
334
|
-
const loc = node.loc?.start;
|
|
335
|
-
if (!loc) return;
|
|
336
|
-
|
|
337
|
-
if (!PATTERNS.PascalCase.test(name)) {
|
|
338
|
-
findings.push({
|
|
339
|
-
type: "naming_convention",
|
|
340
|
-
severity: "WARN",
|
|
341
|
-
category: "NamingConventions",
|
|
342
|
-
file: filePath,
|
|
343
|
-
line: loc.line,
|
|
344
|
-
column: loc.column,
|
|
345
|
-
title: `Interface should be PascalCase: ${name}`,
|
|
346
|
-
message: `Interface name '${name}' should use PascalCase.`,
|
|
347
|
-
codeSnippet: snippetForLine(lines, loc.line),
|
|
348
|
-
confidence: "high",
|
|
349
|
-
fixHint: `Rename to ${toPascalCase(name)}`,
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
},
|
|
353
|
-
|
|
354
|
-
TSTypeAliasDeclaration(pathNode) {
|
|
355
|
-
const node = pathNode.node;
|
|
356
|
-
const name = node.id?.name;
|
|
357
|
-
if (!name) return;
|
|
358
|
-
|
|
359
|
-
const loc = node.loc?.start;
|
|
360
|
-
if (!loc) return;
|
|
361
|
-
|
|
362
|
-
if (!PATTERNS.PascalCase.test(name)) {
|
|
363
|
-
findings.push({
|
|
364
|
-
type: "naming_convention",
|
|
365
|
-
severity: "WARN",
|
|
366
|
-
category: "NamingConventions",
|
|
367
|
-
file: filePath,
|
|
368
|
-
line: loc.line,
|
|
369
|
-
column: loc.column,
|
|
370
|
-
title: `Type should be PascalCase: ${name}`,
|
|
371
|
-
message: `Type alias '${name}' should use PascalCase.`,
|
|
372
|
-
codeSnippet: snippetForLine(lines, loc.line),
|
|
373
|
-
confidence: "high",
|
|
374
|
-
fixHint: `Rename to ${toPascalCase(name)}`,
|
|
375
|
-
});
|
|
376
|
-
}
|
|
377
|
-
},
|
|
378
|
-
|
|
379
|
-
// Check enum names (TypeScript)
|
|
380
|
-
TSEnumDeclaration(pathNode) {
|
|
381
|
-
const node = pathNode.node;
|
|
382
|
-
const name = node.id?.name;
|
|
383
|
-
if (!name) return;
|
|
384
|
-
|
|
385
|
-
const loc = node.loc?.start;
|
|
386
|
-
if (!loc) return;
|
|
387
|
-
|
|
388
|
-
if (!PATTERNS.PascalCase.test(name)) {
|
|
389
|
-
findings.push({
|
|
390
|
-
type: "naming_convention",
|
|
391
|
-
severity: "WARN",
|
|
392
|
-
category: "NamingConventions",
|
|
393
|
-
file: filePath,
|
|
394
|
-
line: loc.line,
|
|
395
|
-
column: loc.column,
|
|
396
|
-
title: `Enum should be PascalCase: ${name}`,
|
|
397
|
-
message: `Enum name '${name}' should use PascalCase.`,
|
|
398
|
-
codeSnippet: snippetForLine(lines, loc.line),
|
|
399
|
-
confidence: "high",
|
|
400
|
-
fixHint: `Rename to ${toPascalCase(name)}`,
|
|
401
|
-
});
|
|
402
|
-
}
|
|
403
|
-
},
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
// Check file naming
|
|
407
|
-
if (isReactFile) {
|
|
408
|
-
// Component files should be PascalCase
|
|
409
|
-
const baseName = path.basename(fileName, path.extname(fileName));
|
|
410
|
-
|
|
411
|
-
if (baseName !== "index" &&
|
|
412
|
-
!PATTERNS.PascalCase.test(baseName) &&
|
|
413
|
-
!baseName.startsWith("[") && // Skip dynamic routes
|
|
414
|
-
!baseName.includes(".")) { // Skip files like page.tsx, layout.tsx
|
|
415
|
-
|
|
416
|
-
findings.push({
|
|
417
|
-
type: "file_naming",
|
|
418
|
-
severity: "INFO",
|
|
419
|
-
category: "NamingConventions",
|
|
420
|
-
file: filePath,
|
|
421
|
-
line: 1,
|
|
422
|
-
column: 0,
|
|
423
|
-
title: `React file should be PascalCase: ${fileName}`,
|
|
424
|
-
message: `React component file '${fileName}' should use PascalCase naming.`,
|
|
425
|
-
codeSnippet: "",
|
|
426
|
-
confidence: "low",
|
|
427
|
-
fixHint: `Rename to ${toPascalCase(baseName)}${path.extname(fileName)}`,
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
return findings;
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
/**
|
|
436
|
-
* Check if function returns JSX
|
|
437
|
-
*/
|
|
438
|
-
function returnsJSX(pathNode) {
|
|
439
|
-
let hasJSX = false;
|
|
440
|
-
|
|
441
|
-
pathNode.traverse({
|
|
442
|
-
JSXElement() {
|
|
443
|
-
hasJSX = true;
|
|
444
|
-
},
|
|
445
|
-
JSXFragment() {
|
|
446
|
-
hasJSX = true;
|
|
447
|
-
},
|
|
448
|
-
});
|
|
449
|
-
|
|
450
|
-
return hasJSX;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
/**
|
|
454
|
-
* Check if init expression returns JSX
|
|
455
|
-
*/
|
|
456
|
-
function returnsJSXFromInit(init, pathNode) {
|
|
457
|
-
if (!init.body) return false;
|
|
458
|
-
|
|
459
|
-
// Check if body is JSX directly (arrow function without block)
|
|
460
|
-
if (t.isJSXElement(init.body) || t.isJSXFragment(init.body)) {
|
|
461
|
-
return true;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
// Check block body for return statement with JSX
|
|
465
|
-
let hasJSX = false;
|
|
466
|
-
if (t.isBlockStatement(init.body)) {
|
|
467
|
-
traverse(init.body, {
|
|
468
|
-
ReturnStatement(innerPath) {
|
|
469
|
-
if (t.isJSXElement(innerPath.node.argument) ||
|
|
470
|
-
t.isJSXFragment(innerPath.node.argument)) {
|
|
471
|
-
hasJSX = true;
|
|
472
|
-
}
|
|
473
|
-
},
|
|
474
|
-
noScope: true,
|
|
475
|
-
}, pathNode.scope);
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
return hasJSX;
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
/**
|
|
482
|
-
* Check if function uses React hooks
|
|
483
|
-
*/
|
|
484
|
-
function usesHooks(pathNode) {
|
|
485
|
-
let usesHook = false;
|
|
486
|
-
|
|
487
|
-
pathNode.traverse({
|
|
488
|
-
CallExpression(innerPath) {
|
|
489
|
-
const callee = innerPath.node.callee;
|
|
490
|
-
if (t.isIdentifier(callee) && HOOK_PATTERN.test(callee.name)) {
|
|
491
|
-
usesHook = true;
|
|
492
|
-
}
|
|
493
|
-
},
|
|
494
|
-
});
|
|
495
|
-
|
|
496
|
-
return usesHook;
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
/**
|
|
500
|
-
* Check if expression is a comparison
|
|
501
|
-
*/
|
|
502
|
-
function isComparisonExpression(node) {
|
|
503
|
-
if (t.isBinaryExpression(node)) {
|
|
504
|
-
return ["===", "!==", "==", "!=", ">", "<", ">=", "<="].includes(node.operator);
|
|
505
|
-
}
|
|
506
|
-
if (t.isLogicalExpression(node)) {
|
|
507
|
-
return true;
|
|
508
|
-
}
|
|
509
|
-
if (t.isUnaryExpression(node) && node.operator === "!") {
|
|
510
|
-
return true;
|
|
511
|
-
}
|
|
512
|
-
return false;
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
/**
|
|
516
|
-
* Convert to PascalCase
|
|
517
|
-
*/
|
|
518
|
-
function toPascalCase(str) {
|
|
519
|
-
return str
|
|
520
|
-
.replace(/[-_](.)/g, (_, c) => c.toUpperCase())
|
|
521
|
-
.replace(/^(.)/, (_, c) => c.toUpperCase());
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
/**
|
|
525
|
-
* Convert to UPPER_SNAKE_CASE
|
|
526
|
-
*/
|
|
527
|
-
function toUpperSnakeCase(str) {
|
|
528
|
-
return str
|
|
529
|
-
.replace(/([a-z])([A-Z])/g, "$1_$2")
|
|
530
|
-
.replace(/[-\s]/g, "_")
|
|
531
|
-
.toUpperCase();
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
module.exports = {
|
|
535
|
-
analyzeNamingConventions,
|
|
536
|
-
detectNamingStyle,
|
|
537
|
-
looksLikeBoolean,
|
|
538
|
-
isComponentName,
|
|
539
|
-
isHookName,
|
|
540
|
-
toPascalCase,
|
|
541
|
-
toUpperSnakeCase,
|
|
542
|
-
PATTERNS,
|
|
543
|
-
BOOLEAN_PREFIXES,
|
|
544
|
-
};
|