@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.
Files changed (224) hide show
  1. package/bin/registry.js +214 -237
  2. package/bin/runners/cli-utils.js +33 -2
  3. package/bin/runners/context/analyzer.js +52 -1
  4. package/bin/runners/context/generators/cursor.js +2 -49
  5. package/bin/runners/context/git-context.js +3 -1
  6. package/bin/runners/context/team-conventions.js +33 -7
  7. package/bin/runners/lib/analysis-core.js +25 -5
  8. package/bin/runners/lib/analyzers.js +431 -481
  9. package/bin/runners/lib/default-config.js +127 -0
  10. package/bin/runners/lib/doctor/modules/security.js +3 -1
  11. package/bin/runners/lib/engine/ast-cache.js +210 -0
  12. package/bin/runners/lib/engine/auth-extractor.js +211 -0
  13. package/bin/runners/lib/engine/billing-extractor.js +112 -0
  14. package/bin/runners/lib/engine/enforcement-extractor.js +100 -0
  15. package/bin/runners/lib/engine/env-extractor.js +207 -0
  16. package/bin/runners/lib/engine/express-extractor.js +208 -0
  17. package/bin/runners/lib/engine/extractors.js +849 -0
  18. package/bin/runners/lib/engine/index.js +207 -0
  19. package/bin/runners/lib/engine/repo-index.js +514 -0
  20. package/bin/runners/lib/engine/types.js +124 -0
  21. package/bin/runners/lib/engines/accessibility-engine.js +18 -218
  22. package/bin/runners/lib/engines/api-consistency-engine.js +30 -335
  23. package/bin/runners/lib/engines/cross-file-analysis-engine.js +27 -292
  24. package/bin/runners/lib/engines/empty-catch-engine.js +17 -127
  25. package/bin/runners/lib/engines/mock-data-engine.js +10 -53
  26. package/bin/runners/lib/engines/performance-issues-engine.js +36 -176
  27. package/bin/runners/lib/engines/security-vulnerabilities-engine.js +54 -382
  28. package/bin/runners/lib/engines/type-aware-engine.js +39 -263
  29. package/bin/runners/lib/engines/vibecheck-engines/index.js +13 -122
  30. package/bin/runners/lib/engines/vibecheck-engines/lib/ast-cache.js +164 -0
  31. package/bin/runners/lib/engines/vibecheck-engines/lib/code-quality-engine.js +291 -0
  32. package/bin/runners/lib/engines/vibecheck-engines/lib/console-logs-engine.js +83 -0
  33. package/bin/runners/lib/engines/vibecheck-engines/lib/dead-code-engine.js +198 -0
  34. package/bin/runners/lib/engines/vibecheck-engines/lib/deprecated-api-engine.js +275 -0
  35. package/bin/runners/lib/engines/vibecheck-engines/lib/empty-catch-engine.js +167 -0
  36. package/bin/runners/lib/engines/vibecheck-engines/lib/file-filter.js +217 -0
  37. package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +73 -373
  38. package/bin/runners/lib/engines/vibecheck-engines/lib/mock-data-engine.js +140 -0
  39. package/bin/runners/lib/engines/vibecheck-engines/lib/parallel-processor.js +164 -0
  40. package/bin/runners/lib/engines/vibecheck-engines/lib/performance-issues-engine.js +234 -0
  41. package/bin/runners/lib/engines/vibecheck-engines/lib/type-aware-engine.js +217 -0
  42. package/bin/runners/lib/engines/vibecheck-engines/lib/unsafe-regex-engine.js +78 -0
  43. package/bin/runners/lib/entitlements-v2.js +73 -97
  44. package/bin/runners/lib/error-handler.js +44 -3
  45. package/bin/runners/lib/error-messages.js +289 -0
  46. package/bin/runners/lib/evidence-pack.js +7 -1
  47. package/bin/runners/lib/finding-id.js +69 -0
  48. package/bin/runners/lib/finding-sorter.js +89 -0
  49. package/bin/runners/lib/html-proof-report.js +700 -350
  50. package/bin/runners/lib/missions/plan.js +6 -46
  51. package/bin/runners/lib/missions/templates.js +0 -232
  52. package/bin/runners/lib/next-action.js +560 -0
  53. package/bin/runners/lib/prerequisites.js +149 -0
  54. package/bin/runners/lib/route-detection.js +137 -68
  55. package/bin/runners/lib/scan-output.js +91 -76
  56. package/bin/runners/lib/scan-runner.js +135 -0
  57. package/bin/runners/lib/schemas/ajv-validator.js +464 -0
  58. package/bin/runners/lib/schemas/error-envelope.schema.json +105 -0
  59. package/bin/runners/lib/schemas/finding-v3.schema.json +151 -0
  60. package/bin/runners/lib/schemas/report-artifact.schema.json +120 -0
  61. package/bin/runners/lib/schemas/run-request.schema.json +108 -0
  62. package/bin/runners/lib/schemas/validator.js +27 -0
  63. package/bin/runners/lib/schemas/verdict.schema.json +140 -0
  64. package/bin/runners/lib/ship-output-enterprise.js +23 -23
  65. package/bin/runners/lib/ship-output.js +75 -31
  66. package/bin/runners/lib/terminal-ui.js +6 -113
  67. package/bin/runners/lib/truth.js +351 -10
  68. package/bin/runners/lib/unified-cli-output.js +430 -603
  69. package/bin/runners/lib/unified-output.js +13 -9
  70. package/bin/runners/runAIAgent.js +10 -5
  71. package/bin/runners/runAgent.js +0 -3
  72. package/bin/runners/runAllowlist.js +389 -0
  73. package/bin/runners/runApprove.js +0 -33
  74. package/bin/runners/runAuth.js +73 -45
  75. package/bin/runners/runCheckpoint.js +51 -11
  76. package/bin/runners/runClassify.js +85 -21
  77. package/bin/runners/runContext.js +0 -3
  78. package/bin/runners/runDoctor.js +41 -28
  79. package/bin/runners/runEvidencePack.js +362 -0
  80. package/bin/runners/runFirewall.js +0 -3
  81. package/bin/runners/runFirewallHook.js +0 -3
  82. package/bin/runners/runFix.js +66 -76
  83. package/bin/runners/runGuard.js +18 -411
  84. package/bin/runners/runInit.js +113 -30
  85. package/bin/runners/runLabs.js +424 -0
  86. package/bin/runners/runMcp.js +19 -25
  87. package/bin/runners/runPolish.js +64 -240
  88. package/bin/runners/runPromptFirewall.js +12 -5
  89. package/bin/runners/runProve.js +57 -22
  90. package/bin/runners/runQuickstart.js +531 -0
  91. package/bin/runners/runReality.js +59 -68
  92. package/bin/runners/runReport.js +38 -33
  93. package/bin/runners/runRuntime.js +8 -5
  94. package/bin/runners/runScan.js +1413 -190
  95. package/bin/runners/runShip.js +113 -719
  96. package/bin/runners/runTruth.js +0 -3
  97. package/bin/runners/runValidate.js +13 -9
  98. package/bin/runners/runWatch.js +23 -14
  99. package/bin/scan.js +6 -1
  100. package/bin/vibecheck.js +204 -185
  101. package/mcp-server/deprecation-middleware.js +282 -0
  102. package/mcp-server/handlers/index.ts +15 -0
  103. package/mcp-server/handlers/tool-handler.ts +554 -0
  104. package/mcp-server/index-v1.js +698 -0
  105. package/mcp-server/index.js +210 -238
  106. package/mcp-server/lib/cache-wrapper.cjs +383 -0
  107. package/mcp-server/lib/error-envelope.js +138 -0
  108. package/mcp-server/lib/executor.ts +499 -0
  109. package/mcp-server/lib/index.ts +19 -0
  110. package/mcp-server/lib/rate-limiter.js +166 -0
  111. package/mcp-server/lib/sandbox.test.ts +519 -0
  112. package/mcp-server/lib/sandbox.ts +395 -0
  113. package/mcp-server/lib/types.ts +267 -0
  114. package/mcp-server/package.json +12 -3
  115. package/mcp-server/registry/tool-registry.js +794 -0
  116. package/mcp-server/registry/tools.json +605 -0
  117. package/mcp-server/registry.test.ts +334 -0
  118. package/mcp-server/tests/tier-gating.test.js +297 -0
  119. package/mcp-server/tier-auth.js +378 -45
  120. package/mcp-server/tools-v3.js +353 -442
  121. package/mcp-server/tsconfig.json +37 -0
  122. package/mcp-server/vibecheck-2.0-tools.js +14 -1
  123. package/package.json +1 -1
  124. package/bin/runners/lib/agent-firewall/learning/learning-engine.js +0 -849
  125. package/bin/runners/lib/audit-logger.js +0 -532
  126. package/bin/runners/lib/authority/authorities/architecture.js +0 -364
  127. package/bin/runners/lib/authority/authorities/compliance.js +0 -341
  128. package/bin/runners/lib/authority/authorities/human.js +0 -343
  129. package/bin/runners/lib/authority/authorities/quality.js +0 -420
  130. package/bin/runners/lib/authority/authorities/security.js +0 -228
  131. package/bin/runners/lib/authority/index.js +0 -293
  132. package/bin/runners/lib/bundle/bundle-intelligence.js +0 -846
  133. package/bin/runners/lib/cli-charts.js +0 -368
  134. package/bin/runners/lib/cli-config-display.js +0 -405
  135. package/bin/runners/lib/cli-demo.js +0 -275
  136. package/bin/runners/lib/cli-errors.js +0 -438
  137. package/bin/runners/lib/cli-help-formatter.js +0 -439
  138. package/bin/runners/lib/cli-interactive-menu.js +0 -509
  139. package/bin/runners/lib/cli-prompts.js +0 -441
  140. package/bin/runners/lib/cli-scan-cards.js +0 -362
  141. package/bin/runners/lib/compliance-reporter.js +0 -710
  142. package/bin/runners/lib/conductor/index.js +0 -671
  143. package/bin/runners/lib/easy/README.md +0 -123
  144. package/bin/runners/lib/easy/index.js +0 -140
  145. package/bin/runners/lib/easy/interactive-wizard.js +0 -788
  146. package/bin/runners/lib/easy/one-click-firewall.js +0 -564
  147. package/bin/runners/lib/easy/zero-config-reality.js +0 -714
  148. package/bin/runners/lib/engines/async-patterns-engine.js +0 -444
  149. package/bin/runners/lib/engines/bundle-size-engine.js +0 -433
  150. package/bin/runners/lib/engines/confidence-scoring.js +0 -276
  151. package/bin/runners/lib/engines/context-detection.js +0 -264
  152. package/bin/runners/lib/engines/database-patterns-engine.js +0 -429
  153. package/bin/runners/lib/engines/duplicate-code-engine.js +0 -354
  154. package/bin/runners/lib/engines/env-variables-engine.js +0 -458
  155. package/bin/runners/lib/engines/error-handling-engine.js +0 -437
  156. package/bin/runners/lib/engines/false-positive-prevention.js +0 -630
  157. package/bin/runners/lib/engines/framework-adapters/index.js +0 -607
  158. package/bin/runners/lib/engines/framework-detection.js +0 -508
  159. package/bin/runners/lib/engines/import-order-engine.js +0 -429
  160. package/bin/runners/lib/engines/naming-conventions-engine.js +0 -544
  161. package/bin/runners/lib/engines/noise-reduction-engine.js +0 -452
  162. package/bin/runners/lib/engines/orchestrator.js +0 -334
  163. package/bin/runners/lib/engines/react-patterns-engine.js +0 -457
  164. package/bin/runners/lib/engines/vibecheck-engines/lib/ai-hallucination-engine.js +0 -806
  165. package/bin/runners/lib/engines/vibecheck-engines/lib/smart-fix-engine.js +0 -577
  166. package/bin/runners/lib/engines/vibecheck-engines/lib/vibe-score-engine.js +0 -543
  167. package/bin/runners/lib/engines/vibecheck-engines.js +0 -514
  168. package/bin/runners/lib/enhanced-features/index.js +0 -305
  169. package/bin/runners/lib/enhanced-output.js +0 -631
  170. package/bin/runners/lib/enterprise.js +0 -300
  171. package/bin/runners/lib/firewall/command-validator.js +0 -351
  172. package/bin/runners/lib/firewall/config.js +0 -341
  173. package/bin/runners/lib/firewall/content-validator.js +0 -519
  174. package/bin/runners/lib/firewall/index.js +0 -101
  175. package/bin/runners/lib/firewall/path-validator.js +0 -256
  176. package/bin/runners/lib/intelligence/cross-repo-intelligence.js +0 -817
  177. package/bin/runners/lib/mcp-utils.js +0 -425
  178. package/bin/runners/lib/output/index.js +0 -1022
  179. package/bin/runners/lib/policy-engine.js +0 -652
  180. package/bin/runners/lib/polish/autofix/accessibility-fixes.js +0 -333
  181. package/bin/runners/lib/polish/autofix/async-handlers.js +0 -273
  182. package/bin/runners/lib/polish/autofix/dead-code.js +0 -280
  183. package/bin/runners/lib/polish/autofix/imports-optimizer.js +0 -344
  184. package/bin/runners/lib/polish/autofix/index.js +0 -200
  185. package/bin/runners/lib/polish/autofix/remove-consoles.js +0 -209
  186. package/bin/runners/lib/polish/autofix/strengthen-types.js +0 -245
  187. package/bin/runners/lib/polish/backend-checks.js +0 -148
  188. package/bin/runners/lib/polish/documentation-checks.js +0 -111
  189. package/bin/runners/lib/polish/frontend-checks.js +0 -168
  190. package/bin/runners/lib/polish/index.js +0 -71
  191. package/bin/runners/lib/polish/infrastructure-checks.js +0 -131
  192. package/bin/runners/lib/polish/library-detection.js +0 -175
  193. package/bin/runners/lib/polish/performance-checks.js +0 -100
  194. package/bin/runners/lib/polish/security-checks.js +0 -148
  195. package/bin/runners/lib/polish/utils.js +0 -203
  196. package/bin/runners/lib/prompt-builder.js +0 -540
  197. package/bin/runners/lib/proof-certificate.js +0 -634
  198. package/bin/runners/lib/reality/accessibility-audit.js +0 -946
  199. package/bin/runners/lib/reality/api-contract-validator.js +0 -1012
  200. package/bin/runners/lib/reality/chaos-engineering.js +0 -1084
  201. package/bin/runners/lib/reality/performance-tracker.js +0 -1077
  202. package/bin/runners/lib/reality/scenario-generator.js +0 -1404
  203. package/bin/runners/lib/reality/visual-regression.js +0 -852
  204. package/bin/runners/lib/reality-profiler.js +0 -717
  205. package/bin/runners/lib/replay/flight-recorder-viewer.js +0 -1160
  206. package/bin/runners/lib/review/ai-code-review.js +0 -832
  207. package/bin/runners/lib/rules/custom-rule-engine.js +0 -985
  208. package/bin/runners/lib/sbom-generator.js +0 -641
  209. package/bin/runners/lib/scan-output-enhanced.js +0 -512
  210. package/bin/runners/lib/security/owasp-scanner.js +0 -939
  211. package/bin/runners/lib/validators/contract-validator.js +0 -283
  212. package/bin/runners/lib/validators/dead-export-detector.js +0 -279
  213. package/bin/runners/lib/validators/dep-audit.js +0 -245
  214. package/bin/runners/lib/validators/env-validator.js +0 -319
  215. package/bin/runners/lib/validators/index.js +0 -120
  216. package/bin/runners/lib/validators/license-checker.js +0 -252
  217. package/bin/runners/lib/validators/route-validator.js +0 -290
  218. package/bin/runners/runAuthority.js +0 -528
  219. package/bin/runners/runConductor.js +0 -772
  220. package/bin/runners/runContainer.js +0 -366
  221. package/bin/runners/runEasy.js +0 -410
  222. package/bin/runners/runIaC.js +0 -372
  223. package/bin/runners/runVibe.js +0 -791
  224. package/mcp-server/tools.js +0 -495
@@ -0,0 +1,124 @@
1
+ // bin/runners/lib/engine/types.js
2
+ // JSDoc type definitions for the engine
3
+
4
+ /**
5
+ * @typedef {Object} FileRecord
6
+ * @property {string} abs - Absolute path
7
+ * @property {string} rel - Relative path from repo root (forward slashes)
8
+ * @property {number} size - File size in bytes
9
+ * @property {number} mtime - Last modified time (ms since epoch)
10
+ * @property {string} hash - Content hash (sha256)
11
+ * @property {string} [ext] - File extension (e.g., ".ts", ".js")
12
+ */
13
+
14
+ /**
15
+ * @typedef {Object} RepoSignals
16
+ * @property {boolean} hasPackageJson
17
+ * @property {boolean} hasRequirementsTxt
18
+ * @property {boolean} hasPyprojectToml
19
+ * @property {boolean} hasGoMod
20
+ * @property {boolean} hasGemfile
21
+ * @property {boolean} hasNextApp - has app/ directory
22
+ * @property {boolean} hasNextPages - has pages/ directory
23
+ * @property {boolean} hasOpenAPI
24
+ * @property {boolean} hasGraphQL
25
+ * @property {Set<string>} detectedFrameworks
26
+ */
27
+
28
+ /**
29
+ * @typedef {Object} RepoIndexResult
30
+ * @property {FileRecord[]} files - All indexed files
31
+ * @property {RepoSignals} signals - Detected signals
32
+ * @property {Map<string, string>} contentCache - abs -> content
33
+ * @property {Map<string, Set<string>>} tokenIndex - token -> Set<abs>
34
+ * @property {Object} stats
35
+ * @property {number} stats.totalFiles
36
+ * @property {number} stats.totalSize
37
+ * @property {number} stats.indexTimeMs
38
+ */
39
+
40
+ /**
41
+ * @typedef {Object} Evidence
42
+ * @property {string} id - Unique evidence ID (ev_xxxx)
43
+ * @property {string} file - Relative file path
44
+ * @property {string} lines - Line range (e.g., "10-15")
45
+ * @property {string} snippetHash - SHA256 of snippet
46
+ * @property {string} reason - Why this is evidence
47
+ */
48
+
49
+ /**
50
+ * @typedef {Object} RouteFact
51
+ * @property {string} method - HTTP method (GET, POST, *, etc.)
52
+ * @property {string} path - Canonicalized route path
53
+ * @property {string} handler - Relative file path
54
+ * @property {string} framework - Source framework
55
+ * @property {"high"|"med"|"low"} confidence
56
+ * @property {Evidence[]} evidence
57
+ * @property {string[]} [hooks] - Fastify hooks if present
58
+ */
59
+
60
+ /**
61
+ * @typedef {Object} ClientRefFact
62
+ * @property {string} method - HTTP method or "*"
63
+ * @property {string} path - Canonicalized path
64
+ * @property {string} source - Relative file path
65
+ * @property {"high"|"med"|"low"} confidence
66
+ * @property {string} kind - fetch, axios_member, axios_config, useSWR, useQuery
67
+ * @property {Evidence[]} evidence
68
+ */
69
+
70
+ /**
71
+ * @typedef {Object} EnvFact
72
+ * @property {string} name - Environment variable name
73
+ * @property {string[]} files - Files where it's referenced
74
+ * @property {boolean} hasDefault - Whether a default value exists
75
+ * @property {string} [defaultValue] - Default value if any
76
+ */
77
+
78
+ /**
79
+ * @typedef {Object} Gap
80
+ * @property {string} kind - Gap type (e.g., "fastify_plugin_unresolved")
81
+ * @property {string} [file] - Related file
82
+ * @property {string} [spec] - Module specifier
83
+ * @property {string} [name] - Identifier name
84
+ * @property {string} [note] - Additional notes
85
+ * @property {string} [error] - Error message if from catch
86
+ */
87
+
88
+ /**
89
+ * @typedef {Object} AdapterResult
90
+ * @property {RouteFact[]} routes
91
+ * @property {ClientRefFact[]} clientRefs
92
+ * @property {Gap[]} gaps
93
+ * @property {Object} stats
94
+ * @property {number} stats.filesScanned
95
+ * @property {number} stats.parseErrors
96
+ * @property {number} [quality] - 0-1 extraction quality score
97
+ */
98
+
99
+ /**
100
+ * @typedef {Object} Finding
101
+ * @property {string} id - Stable finding ID
102
+ * @property {string} title
103
+ * @property {string} description
104
+ * @property {"info"|"warn"|"block"} severity
105
+ * @property {"high"|"med"|"low"} confidence
106
+ * @property {Evidence[]} evidence
107
+ * @property {Gap[]} [gaps]
108
+ * @property {string} [suggestedFix]
109
+ * @property {string} [category]
110
+ */
111
+
112
+ /**
113
+ * @typedef {Object} ScanResult
114
+ * @property {Finding[]} findings
115
+ * @property {Object} truthpack
116
+ * @property {Object} stats
117
+ * @property {number} stats.scanTimeMs
118
+ * @property {number} stats.filesIndexed
119
+ * @property {number} stats.routesFound
120
+ * @property {number} stats.clientRefsFound
121
+ * @property {number} stats.gapsFound
122
+ */
123
+
124
+ module.exports = {};
@@ -1,115 +1,12 @@
1
1
  /**
2
2
  * Accessibility Analysis Engine
3
3
  * Detects accessibility issues in React/JSX code
4
- * Enhanced with smarter detection:
5
- * - Distinguishes decorative vs informative images (empty alt="" is valid)
6
- * - Checks for visible text content in buttons/links
7
- * - Detects Next.js Image component and accessible patterns
8
- * - Supports aria-hidden for decorative elements
9
4
  */
10
5
 
11
6
  const { getAST } = require("./ast-cache");
12
7
  const traverse = require("@babel/traverse").default;
13
8
  const t = require("@babel/types");
14
9
 
15
- /**
16
- * Get attribute value from JSX element
17
- */
18
- function getAttributeValue(attributes, name) {
19
- const attr = attributes.find(a =>
20
- t.isJSXAttribute(a) && a.name && a.name.name === name
21
- );
22
- if (!attr) return undefined;
23
-
24
- if (t.isStringLiteral(attr.value)) {
25
- return attr.value.value;
26
- }
27
- if (t.isJSXExpressionContainer(attr.value)) {
28
- const expr = attr.value.expression;
29
- if (t.isStringLiteral(expr)) return expr.value;
30
- if (t.isTemplateLiteral(expr) && expr.quasis.length === 1) {
31
- return expr.quasis[0].value.raw;
32
- }
33
- }
34
- return null; // Has attribute but value is dynamic
35
- }
36
-
37
- /**
38
- * Check if element has visible text content
39
- */
40
- function hasVisibleTextContent(element) {
41
- if (!element.children) return false;
42
-
43
- for (const child of element.children) {
44
- // Text node
45
- if (t.isJSXText(child) && child.value.trim()) {
46
- return true;
47
- }
48
- // Expression that might be text
49
- if (t.isJSXExpressionContainer(child)) {
50
- const expr = child.expression;
51
- if (t.isStringLiteral(expr) && expr.value.trim()) return true;
52
- if (t.isTemplateLiteral(expr)) return true;
53
- if (t.isIdentifier(expr)) return true; // Variable might be text
54
- }
55
- // Nested element - recursively check
56
- if (t.isJSXElement(child)) {
57
- if (hasVisibleTextContent(child)) return true;
58
- }
59
- }
60
- return false;
61
- }
62
-
63
- /**
64
- * Check if image is decorative (intentionally hidden from screen readers)
65
- */
66
- function isDecorativeImage(attributes) {
67
- // Check for aria-hidden="true"
68
- const ariaHidden = getAttributeValue(attributes, "aria-hidden");
69
- if (ariaHidden === "true") return true;
70
-
71
- // Check for role="presentation" or role="none"
72
- const role = getAttributeValue(attributes, "role");
73
- if (role === "presentation" || role === "none") return true;
74
-
75
- // Empty alt="" is valid for decorative images
76
- const alt = getAttributeValue(attributes, "alt");
77
- if (alt === "") return true;
78
-
79
- return false;
80
- }
81
-
82
- /**
83
- * Check if element is likely a decorative icon
84
- */
85
- function isLikelyIcon(attributes, tagName) {
86
- // Common icon patterns
87
- const className = getAttributeValue(attributes, "className") || "";
88
- const iconPatterns = [
89
- /icon/i,
90
- /fa-/i, // FontAwesome
91
- /bi-/i, // Bootstrap Icons
92
- /lucide/i, // Lucide icons
93
- /heroicon/i, // Heroicons
94
- /material/i, // Material icons
95
- /mdi-/i, // Material Design Icons
96
- ];
97
-
98
- if (iconPatterns.some(p => p.test(className))) return true;
99
-
100
- // SVG icons
101
- if (tagName === "svg") {
102
- const width = getAttributeValue(attributes, "width");
103
- const height = getAttributeValue(attributes, "height");
104
- // Small dimensions often indicate icons
105
- if ((width && parseInt(width) <= 32) || (height && parseInt(height) <= 32)) {
106
- return true;
107
- }
108
- }
109
-
110
- return false;
111
- }
112
-
113
10
  /**
114
11
  * Analyze accessibility issues
115
12
  */
@@ -127,40 +24,12 @@ function analyzeAccessibility(code, filePath) {
127
24
  JSXElement(path) {
128
25
  const node = path.node;
129
26
  const openingElement = node.openingElement;
27
+ const tagName = openingElement.name.name;
130
28
 
131
- // Handle both simple names and member expressions (e.g., Image, Next.Image)
132
- let tagName = null;
133
- if (t.isJSXIdentifier(openingElement.name)) {
134
- tagName = openingElement.name.name;
135
- } else if (t.isJSXMemberExpression(openingElement.name)) {
136
- tagName = openingElement.name.property.name;
137
- }
138
-
139
- if (!tagName) return;
140
-
141
- const attributes = openingElement.attributes || [];
142
-
143
- // Missing alt text on images (including Next.js Image component)
144
- if (tagName === "img" || tagName === "Image") {
145
- // Skip decorative images
146
- if (isDecorativeImage(attributes)) {
147
- return;
148
- }
149
-
150
- // Skip if likely an icon with aria-hidden parent
151
- if (isLikelyIcon(attributes, tagName)) {
152
- // Check if parent has aria-hidden
153
- const parent = path.findParent(p => t.isJSXElement(p.node));
154
- if (parent) {
155
- const parentAttrs = parent.node.openingElement.attributes || [];
156
- if (getAttributeValue(parentAttrs, "aria-hidden") === "true") {
157
- return;
158
- }
159
- }
160
- }
161
-
162
- const hasAlt = attributes.some(attr =>
163
- t.isJSXAttribute(attr) && attr.name && attr.name.name === "alt"
29
+ // Missing alt text on images
30
+ if (tagName === "img") {
31
+ const hasAlt = openingElement.attributes.some(attr =>
32
+ t.isJSXAttribute(attr) && attr.name.name === "alt"
164
33
  );
165
34
 
166
35
  if (!hasAlt) {
@@ -173,70 +42,32 @@ function analyzeAccessibility(code, filePath) {
173
42
  line,
174
43
  column: openingElement.loc.start.column,
175
44
  title: "Image missing alt text",
176
- message: "Images must have alt text. Use alt=\"\" for decorative images.",
45
+ message: "Images must have alt text for screen readers",
177
46
  codeSnippet: lines[line - 1]?.trim(),
178
47
  confidence: "high",
179
- fixHint: "Add alt=\"description\" for informative images or alt=\"\" for decorative ones",
180
48
  });
181
49
  }
182
50
  }
183
51
 
184
52
  // Interactive elements without accessible labels
185
- const interactiveElements = ["button", "a", "input", "select", "textarea", "Button", "Link"];
53
+ const interactiveElements = ["button", "a", "input", "select", "textarea"];
186
54
  if (interactiveElements.includes(tagName)) {
187
- const hasAriaLabel = attributes.some(attr =>
188
- t.isJSXAttribute(attr) && attr.name &&
55
+ const hasLabel = openingElement.attributes.some(attr =>
56
+ t.isJSXAttribute(attr) &&
189
57
  (attr.name.name === "aria-label" ||
190
58
  attr.name.name === "aria-labelledby" ||
191
59
  attr.name.name === "title")
192
60
  );
193
61
 
194
- // Check for visible text content (most common way to label buttons/links)
195
- const hasTextContent = hasVisibleTextContent(node);
196
-
197
62
  // Check for associated label element
198
63
  const hasAssociatedLabel = path.findParent(p => {
199
64
  if (t.isJSXElement(p.node)) {
200
- const parentName = t.isJSXIdentifier(p.node.openingElement.name)
201
- ? p.node.openingElement.name.name
202
- : null;
203
- return parentName === "label";
204
- }
205
- return false;
206
- });
207
-
208
- // Check for sr-only children (screen reader only text)
209
- const hasSrOnlyText = node.children && node.children.some(child => {
210
- if (t.isJSXElement(child)) {
211
- const childAttrs = child.openingElement.attributes || [];
212
- const className = getAttributeValue(childAttrs, "className") || "";
213
- return /sr-only|visually-hidden|screen-reader/i.test(className);
65
+ return p.node.openingElement.name.name === "label";
214
66
  }
215
67
  return false;
216
68
  });
217
69
 
218
- // Skip for links and buttons that have visible text or are in link/button components
219
- if (tagName === "a" || tagName === "Link" || tagName === "button" || tagName === "Button") {
220
- if (hasTextContent || hasAriaLabel || hasSrOnlyText) {
221
- // Has accessible name, skip
222
- } else {
223
- const line = openingElement.loc.start.line;
224
- findings.push({
225
- type: "missing_accessible_label",
226
- severity: "WARN",
227
- category: "Accessibility",
228
- file: filePath,
229
- line,
230
- column: openingElement.loc.start.column,
231
- title: `${tagName} element missing accessible name`,
232
- message: `Add visible text, aria-label, or sr-only text for screen readers`,
233
- codeSnippet: lines[line - 1]?.trim(),
234
- confidence: "med",
235
- fixHint: "Add visible text content or aria-label for accessibility",
236
- });
237
- }
238
- } else if (!hasAriaLabel && !hasAssociatedLabel) {
239
- // Form inputs need labels
70
+ if (!hasLabel && !hasAssociatedLabel && tagName !== "a") {
240
71
  const line = openingElement.loc.start.line;
241
72
  findings.push({
242
73
  type: "missing_accessible_label",
@@ -249,7 +80,6 @@ function analyzeAccessibility(code, filePath) {
249
80
  message: `Add aria-label, aria-labelledby, or wrap in <label>`,
250
81
  codeSnippet: lines[line - 1]?.trim(),
251
82
  confidence: "med",
252
- fixHint: "Add aria-label or associate with a <label> element using htmlFor",
253
83
  });
254
84
  }
255
85
  }
@@ -292,27 +122,16 @@ function analyzeAccessibility(code, filePath) {
292
122
 
293
123
  // Missing keyboard handlers on interactive elements
294
124
  if (tagName === "div" || tagName === "span") {
295
- const hasOnClick = attributes.some(attr =>
296
- t.isJSXAttribute(attr) && attr.name &&
297
- attr.name.name === "onClick"
298
- );
299
-
300
- const hasKeyHandler = attributes.some(attr =>
301
- t.isJSXAttribute(attr) && attr.name &&
302
- (attr.name.name === "onKeyDown" ||
303
- attr.name.name === "onKeyUp" ||
304
- attr.name.name === "onKeyPress")
125
+ const hasOnClick = openingElement.attributes.some(attr =>
126
+ t.isJSXAttribute(attr) &&
127
+ (attr.name.name === "onClick" || attr.name.name === "onKeyDown")
305
128
  );
306
129
 
307
- const role = getAttributeValue(attributes, "role");
308
- const hasInteractiveRole = role && ["button", "link", "tab", "menuitem", "option"].includes(role);
309
-
310
- const hasTabIndex = attributes.some(attr =>
311
- t.isJSXAttribute(attr) && attr.name && attr.name.name === "tabIndex"
130
+ const hasRole = openingElement.attributes.some(attr =>
131
+ t.isJSXAttribute(attr) && attr.name.name === "role"
312
132
  );
313
133
 
314
- // Only flag if has onClick but missing both keyboard handler and proper role
315
- if (hasOnClick && !hasKeyHandler && !hasInteractiveRole) {
134
+ if (hasOnClick && !hasRole) {
316
135
  const line = openingElement.loc.start.line;
317
136
  findings.push({
318
137
  type: "missing_keyboard_handler",
@@ -322,28 +141,9 @@ function analyzeAccessibility(code, filePath) {
322
141
  line,
323
142
  column: openingElement.loc.start.column,
324
143
  title: "Interactive element missing keyboard support",
325
- message: "Elements with onClick should have role=\"button\" (or similar), tabIndex, and onKeyDown",
326
- codeSnippet: lines[line - 1]?.trim(),
327
- confidence: "med",
328
- fixHint: "Add role=\"button\" tabIndex={0} onKeyDown={(e) => e.key === 'Enter' && handleClick()}",
329
- });
330
- }
331
-
332
- // Also warn if has role but no tabIndex (not focusable)
333
- if (hasInteractiveRole && !hasTabIndex) {
334
- const line = openingElement.loc.start.line;
335
- findings.push({
336
- type: "missing_tabindex",
337
- severity: "WARN",
338
- category: "Accessibility",
339
- file: filePath,
340
- line,
341
- column: openingElement.loc.start.column,
342
- title: "Interactive element not focusable",
343
- message: `Element with role="${role}" should have tabIndex={0} to be keyboard focusable`,
144
+ message: "Elements with onClick should have onKeyDown and proper role",
344
145
  codeSnippet: lines[line - 1]?.trim(),
345
146
  confidence: "med",
346
- fixHint: "Add tabIndex={0} to make the element keyboard focusable",
347
147
  });
348
148
  }
349
149
  }