@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,429 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Import Order Engine
|
|
3
|
-
* Detects:
|
|
4
|
-
* - Inconsistent import ordering
|
|
5
|
-
* - Mixed import styles (require vs import)
|
|
6
|
-
* - Circular import potential
|
|
7
|
-
* - Unused imports (basic detection)
|
|
8
|
-
* - Side-effect imports
|
|
9
|
-
* - Type-only imports that should use 'import type'
|
|
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
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Import categories for ordering
|
|
19
|
-
*/
|
|
20
|
-
const IMPORT_CATEGORIES = {
|
|
21
|
-
BUILTIN: 1, // node:fs, fs, path, etc.
|
|
22
|
-
EXTERNAL: 2, // react, lodash, @org/pkg
|
|
23
|
-
INTERNAL: 3, // @/, ~/, #/
|
|
24
|
-
PARENT: 4, // ../
|
|
25
|
-
SIBLING: 5, // ./
|
|
26
|
-
INDEX: 6, // ./index, .
|
|
27
|
-
STYLE: 7, // .css, .scss, .less
|
|
28
|
-
TYPE: 8, // import type
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Node.js built-in modules
|
|
33
|
-
*/
|
|
34
|
-
const BUILTIN_MODULES = new Set([
|
|
35
|
-
"assert", "buffer", "child_process", "cluster", "console", "constants",
|
|
36
|
-
"crypto", "dgram", "dns", "domain", "events", "fs", "http", "https",
|
|
37
|
-
"module", "net", "os", "path", "punycode", "querystring", "readline",
|
|
38
|
-
"repl", "stream", "string_decoder", "sys", "timers", "tls", "tty",
|
|
39
|
-
"url", "util", "vm", "zlib", "process",
|
|
40
|
-
]);
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Determine import category
|
|
44
|
-
*/
|
|
45
|
-
function getImportCategory(source, isTypeOnly = false) {
|
|
46
|
-
if (isTypeOnly) return IMPORT_CATEGORIES.TYPE;
|
|
47
|
-
|
|
48
|
-
// Style imports
|
|
49
|
-
if (/\.(css|scss|sass|less|styl)$/.test(source)) {
|
|
50
|
-
return IMPORT_CATEGORIES.STYLE;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Node built-in
|
|
54
|
-
if (source.startsWith("node:") || BUILTIN_MODULES.has(source)) {
|
|
55
|
-
return IMPORT_CATEGORIES.BUILTIN;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Internal aliases
|
|
59
|
-
if (source.startsWith("@/") || source.startsWith("~/") || source.startsWith("#/")) {
|
|
60
|
-
return IMPORT_CATEGORIES.INTERNAL;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Relative imports
|
|
64
|
-
if (source.startsWith("../")) {
|
|
65
|
-
return IMPORT_CATEGORIES.PARENT;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (source === "." || source === "./index" || source.startsWith("./index.")) {
|
|
69
|
-
return IMPORT_CATEGORIES.INDEX;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (source.startsWith("./")) {
|
|
73
|
-
return IMPORT_CATEGORIES.SIBLING;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// External packages
|
|
77
|
-
return IMPORT_CATEGORIES.EXTERNAL;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Get category name for display
|
|
82
|
-
*/
|
|
83
|
-
function getCategoryName(category) {
|
|
84
|
-
const names = {
|
|
85
|
-
[IMPORT_CATEGORIES.BUILTIN]: "built-in",
|
|
86
|
-
[IMPORT_CATEGORIES.EXTERNAL]: "external",
|
|
87
|
-
[IMPORT_CATEGORIES.INTERNAL]: "internal alias",
|
|
88
|
-
[IMPORT_CATEGORIES.PARENT]: "parent",
|
|
89
|
-
[IMPORT_CATEGORIES.SIBLING]: "sibling",
|
|
90
|
-
[IMPORT_CATEGORIES.INDEX]: "index",
|
|
91
|
-
[IMPORT_CATEGORIES.STYLE]: "style",
|
|
92
|
-
[IMPORT_CATEGORIES.TYPE]: "type",
|
|
93
|
-
};
|
|
94
|
-
return names[category] || "unknown";
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function snippetForLine(lines, line) {
|
|
98
|
-
return lines[line - 1] ? lines[line - 1].trim() : "";
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Analyze import order and patterns
|
|
103
|
-
*/
|
|
104
|
-
function analyzeImportOrder(code, filePath) {
|
|
105
|
-
const findings = [];
|
|
106
|
-
|
|
107
|
-
if (shouldExcludeFile(filePath)) return findings;
|
|
108
|
-
if (isTestContext(code, filePath)) return findings;
|
|
109
|
-
if (hasIgnoreDirective(code, "import-order")) return findings;
|
|
110
|
-
|
|
111
|
-
const ast = getAST(code, filePath);
|
|
112
|
-
if (!ast) return findings;
|
|
113
|
-
|
|
114
|
-
const lines = code.split("\n");
|
|
115
|
-
|
|
116
|
-
// Collect all imports
|
|
117
|
-
const imports = [];
|
|
118
|
-
const requires = [];
|
|
119
|
-
const importedIdentifiers = new Set();
|
|
120
|
-
const usedIdentifiers = new Set();
|
|
121
|
-
let lastImportLine = 0;
|
|
122
|
-
let hasCodeBetweenImports = false;
|
|
123
|
-
|
|
124
|
-
traverse(ast, {
|
|
125
|
-
ImportDeclaration(path) {
|
|
126
|
-
const node = path.node;
|
|
127
|
-
const loc = node.loc?.start;
|
|
128
|
-
if (!loc) return;
|
|
129
|
-
|
|
130
|
-
const source = node.source.value;
|
|
131
|
-
const isTypeOnly = node.importKind === "type";
|
|
132
|
-
const category = getImportCategory(source, isTypeOnly);
|
|
133
|
-
|
|
134
|
-
// Track imported identifiers
|
|
135
|
-
for (const specifier of node.specifiers) {
|
|
136
|
-
if (t.isImportSpecifier(specifier) || t.isImportDefaultSpecifier(specifier)) {
|
|
137
|
-
importedIdentifiers.add(specifier.local.name);
|
|
138
|
-
} else if (t.isImportNamespaceSpecifier(specifier)) {
|
|
139
|
-
importedIdentifiers.add(specifier.local.name);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Check for code between imports
|
|
144
|
-
if (lastImportLine > 0 && loc.line > lastImportLine + 1) {
|
|
145
|
-
// Check if there's actual code between (not just blank lines or comments)
|
|
146
|
-
const linesBetween = lines.slice(lastImportLine, loc.line - 1);
|
|
147
|
-
const hasCode = linesBetween.some(l => {
|
|
148
|
-
const trimmed = l.trim();
|
|
149
|
-
return trimmed && !trimmed.startsWith("//") && !trimmed.startsWith("/*");
|
|
150
|
-
});
|
|
151
|
-
if (hasCode) {
|
|
152
|
-
hasCodeBetweenImports = true;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
lastImportLine = loc.line;
|
|
156
|
-
|
|
157
|
-
imports.push({
|
|
158
|
-
source,
|
|
159
|
-
category,
|
|
160
|
-
line: loc.line,
|
|
161
|
-
isTypeOnly,
|
|
162
|
-
isSideEffect: node.specifiers.length === 0,
|
|
163
|
-
node,
|
|
164
|
-
});
|
|
165
|
-
},
|
|
166
|
-
|
|
167
|
-
// Track require() calls
|
|
168
|
-
CallExpression(path) {
|
|
169
|
-
const node = path.node;
|
|
170
|
-
|
|
171
|
-
if (t.isIdentifier(node.callee, { name: "require" }) &&
|
|
172
|
-
node.arguments.length > 0 &&
|
|
173
|
-
t.isStringLiteral(node.arguments[0])) {
|
|
174
|
-
|
|
175
|
-
const loc = node.loc?.start;
|
|
176
|
-
if (!loc) return;
|
|
177
|
-
|
|
178
|
-
requires.push({
|
|
179
|
-
source: node.arguments[0].value,
|
|
180
|
-
line: loc.line,
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
},
|
|
184
|
-
|
|
185
|
-
// Track used identifiers
|
|
186
|
-
Identifier(path) {
|
|
187
|
-
// Skip if it's a declaration
|
|
188
|
-
if (path.isBindingIdentifier()) return;
|
|
189
|
-
|
|
190
|
-
// Skip property names
|
|
191
|
-
if (path.parentPath.isMemberExpression() &&
|
|
192
|
-
path.key === "property" &&
|
|
193
|
-
!path.parentPath.node.computed) {
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// Skip import specifiers
|
|
198
|
-
if (path.parentPath.isImportSpecifier() ||
|
|
199
|
-
path.parentPath.isImportDefaultSpecifier() ||
|
|
200
|
-
path.parentPath.isImportNamespaceSpecifier()) {
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
usedIdentifiers.add(path.node.name);
|
|
205
|
-
},
|
|
206
|
-
|
|
207
|
-
// Track JSX usage
|
|
208
|
-
JSXIdentifier(path) {
|
|
209
|
-
if (path.parentPath.isJSXOpeningElement() || path.parentPath.isJSXClosingElement()) {
|
|
210
|
-
usedIdentifiers.add(path.node.name);
|
|
211
|
-
}
|
|
212
|
-
},
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
// Check import order
|
|
216
|
-
let lastCategory = 0;
|
|
217
|
-
let lastSource = "";
|
|
218
|
-
let orderViolations = [];
|
|
219
|
-
|
|
220
|
-
for (let i = 0; i < imports.length; i++) {
|
|
221
|
-
const imp = imports[i];
|
|
222
|
-
|
|
223
|
-
// Check category order
|
|
224
|
-
if (imp.category < lastCategory) {
|
|
225
|
-
orderViolations.push({
|
|
226
|
-
line: imp.line,
|
|
227
|
-
source: imp.source,
|
|
228
|
-
expectedBefore: getCategoryName(lastCategory),
|
|
229
|
-
actualCategory: getCategoryName(imp.category),
|
|
230
|
-
});
|
|
231
|
-
} else if (imp.category === lastCategory) {
|
|
232
|
-
// Within same category, check alphabetical order (optional)
|
|
233
|
-
// Skip this for now as it's too strict
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
lastCategory = imp.category;
|
|
237
|
-
lastSource = imp.source;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Report order violations (grouped)
|
|
241
|
-
if (orderViolations.length > 0) {
|
|
242
|
-
const firstViolation = orderViolations[0];
|
|
243
|
-
findings.push({
|
|
244
|
-
type: "import_order",
|
|
245
|
-
severity: "INFO",
|
|
246
|
-
category: "ImportOrder",
|
|
247
|
-
file: filePath,
|
|
248
|
-
line: firstViolation.line,
|
|
249
|
-
column: 0,
|
|
250
|
-
title: `Import order inconsistent (${orderViolations.length} issues)`,
|
|
251
|
-
message: `'${firstViolation.source}' (${firstViolation.actualCategory}) should come before ${firstViolation.expectedBefore} imports.`,
|
|
252
|
-
codeSnippet: snippetForLine(lines, firstViolation.line),
|
|
253
|
-
confidence: "low",
|
|
254
|
-
fixHint: "Order imports: built-in → external → internal → parent → sibling → index → styles",
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// Check for mixed import/require
|
|
259
|
-
if (imports.length > 0 && requires.length > 0) {
|
|
260
|
-
const firstRequire = requires[0];
|
|
261
|
-
findings.push({
|
|
262
|
-
type: "mixed_imports",
|
|
263
|
-
severity: "INFO",
|
|
264
|
-
category: "ImportOrder",
|
|
265
|
-
file: filePath,
|
|
266
|
-
line: firstRequire.line,
|
|
267
|
-
column: 0,
|
|
268
|
-
title: "Mixed import and require statements",
|
|
269
|
-
message: `File uses both ESM imports (${imports.length}) and CommonJS require (${requires.length}). Consider using consistent module syntax.`,
|
|
270
|
-
codeSnippet: snippetForLine(lines, firstRequire.line),
|
|
271
|
-
confidence: "low",
|
|
272
|
-
fixHint: "Convert to ESM: import x from 'y' instead of const x = require('y')",
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// Check for code between imports
|
|
277
|
-
if (hasCodeBetweenImports) {
|
|
278
|
-
findings.push({
|
|
279
|
-
type: "code_between_imports",
|
|
280
|
-
severity: "INFO",
|
|
281
|
-
category: "ImportOrder",
|
|
282
|
-
file: filePath,
|
|
283
|
-
line: 1,
|
|
284
|
-
column: 0,
|
|
285
|
-
title: "Code between import statements",
|
|
286
|
-
message: "There is code between import statements. Keep all imports at the top of the file.",
|
|
287
|
-
codeSnippet: "",
|
|
288
|
-
confidence: "med",
|
|
289
|
-
fixHint: "Move all imports to the top of the file, before any other code",
|
|
290
|
-
});
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
// Check for side-effect imports (warn if not intentional)
|
|
294
|
-
const sideEffectImports = imports.filter(i => i.isSideEffect);
|
|
295
|
-
for (const imp of sideEffectImports) {
|
|
296
|
-
// Skip known side-effect imports
|
|
297
|
-
if (/\.(css|scss|sass|less)$/.test(imp.source)) continue;
|
|
298
|
-
if (imp.source.includes("polyfill")) continue;
|
|
299
|
-
if (imp.source.includes("register")) continue;
|
|
300
|
-
|
|
301
|
-
findings.push({
|
|
302
|
-
type: "side_effect_import",
|
|
303
|
-
severity: "INFO",
|
|
304
|
-
category: "ImportOrder",
|
|
305
|
-
file: filePath,
|
|
306
|
-
line: imp.line,
|
|
307
|
-
column: 0,
|
|
308
|
-
title: `Side-effect import: ${imp.source}`,
|
|
309
|
-
message: "Import doesn't import any values. If intentional, add a comment.",
|
|
310
|
-
codeSnippet: snippetForLine(lines, imp.line),
|
|
311
|
-
confidence: "low",
|
|
312
|
-
fixHint: "Add // side-effect import comment or import specific values",
|
|
313
|
-
});
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
// Check for potentially unused imports
|
|
317
|
-
const unusedImports = [];
|
|
318
|
-
for (const identifier of importedIdentifiers) {
|
|
319
|
-
if (!usedIdentifiers.has(identifier)) {
|
|
320
|
-
// Skip common false positives
|
|
321
|
-
if (identifier === "React") continue; // JSX transform
|
|
322
|
-
if (identifier.startsWith("_")) continue; // Intentionally unused
|
|
323
|
-
|
|
324
|
-
unusedImports.push(identifier);
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
if (unusedImports.length > 0) {
|
|
329
|
-
// Find the line for the first unused import
|
|
330
|
-
let unusedLine = 1;
|
|
331
|
-
for (const imp of imports) {
|
|
332
|
-
for (const spec of imp.node.specifiers) {
|
|
333
|
-
if (unusedImports.includes(spec.local.name)) {
|
|
334
|
-
unusedLine = imp.line;
|
|
335
|
-
break;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
findings.push({
|
|
341
|
-
type: "unused_import",
|
|
342
|
-
severity: "INFO",
|
|
343
|
-
category: "ImportOrder",
|
|
344
|
-
file: filePath,
|
|
345
|
-
line: unusedLine,
|
|
346
|
-
column: 0,
|
|
347
|
-
title: `Potentially unused imports (${unusedImports.length})`,
|
|
348
|
-
message: `Imports may be unused: ${unusedImports.slice(0, 5).join(", ")}${unusedImports.length > 5 ? "..." : ""}`,
|
|
349
|
-
codeSnippet: snippetForLine(lines, unusedLine),
|
|
350
|
-
confidence: "low",
|
|
351
|
-
fixHint: "Remove unused imports or prefix with underscore if intentional",
|
|
352
|
-
});
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
// Check for imports that should use 'import type'
|
|
356
|
-
traverse(ast, {
|
|
357
|
-
ImportDeclaration(path) {
|
|
358
|
-
const node = path.node;
|
|
359
|
-
if (node.importKind === "type") return; // Already type import
|
|
360
|
-
|
|
361
|
-
const loc = node.loc?.start;
|
|
362
|
-
if (!loc) return;
|
|
363
|
-
|
|
364
|
-
// Check if all specifiers are only used as types
|
|
365
|
-
let allTypeOnly = true;
|
|
366
|
-
|
|
367
|
-
for (const specifier of node.specifiers) {
|
|
368
|
-
if (!t.isImportSpecifier(specifier)) {
|
|
369
|
-
allTypeOnly = false;
|
|
370
|
-
break;
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
const name = specifier.local.name;
|
|
374
|
-
|
|
375
|
-
// Check if used as value anywhere
|
|
376
|
-
let usedAsValue = false;
|
|
377
|
-
traverse(ast, {
|
|
378
|
-
Identifier(innerPath) {
|
|
379
|
-
if (innerPath.node.name !== name) return;
|
|
380
|
-
if (innerPath.parentPath.isImportSpecifier()) return;
|
|
381
|
-
|
|
382
|
-
// Check if in type annotation
|
|
383
|
-
if (innerPath.findParent(p =>
|
|
384
|
-
p.isTSTypeAnnotation() ||
|
|
385
|
-
p.isTSTypeReference() ||
|
|
386
|
-
p.isTSInterfaceDeclaration() ||
|
|
387
|
-
p.isTSTypeAliasDeclaration()
|
|
388
|
-
)) {
|
|
389
|
-
return; // Type usage, OK
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
usedAsValue = true;
|
|
393
|
-
},
|
|
394
|
-
}, path.scope, path);
|
|
395
|
-
|
|
396
|
-
if (usedAsValue) {
|
|
397
|
-
allTypeOnly = false;
|
|
398
|
-
break;
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
if (allTypeOnly && node.specifiers.length > 0) {
|
|
403
|
-
findings.push({
|
|
404
|
-
type: "should_be_type_import",
|
|
405
|
-
severity: "INFO",
|
|
406
|
-
category: "ImportOrder",
|
|
407
|
-
file: filePath,
|
|
408
|
-
line: loc.line,
|
|
409
|
-
column: 0,
|
|
410
|
-
title: "Import could use 'import type'",
|
|
411
|
-
message: "All imports from this module are only used as types.",
|
|
412
|
-
codeSnippet: snippetForLine(lines, loc.line),
|
|
413
|
-
confidence: "low",
|
|
414
|
-
fixHint: "Change to: import type { ... } from '...'",
|
|
415
|
-
});
|
|
416
|
-
}
|
|
417
|
-
},
|
|
418
|
-
});
|
|
419
|
-
|
|
420
|
-
return findings;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
module.exports = {
|
|
424
|
-
analyzeImportOrder,
|
|
425
|
-
getImportCategory,
|
|
426
|
-
getCategoryName,
|
|
427
|
-
IMPORT_CATEGORIES,
|
|
428
|
-
BUILTIN_MODULES,
|
|
429
|
-
};
|