@vertaaux/cli 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/README.md +345 -0
  2. package/dist/auth/ci-token.d.ts +49 -0
  3. package/dist/auth/ci-token.d.ts.map +1 -0
  4. package/dist/auth/ci-token.js +83 -0
  5. package/dist/auth/device-flow.d.ts +66 -0
  6. package/dist/auth/device-flow.d.ts.map +1 -0
  7. package/dist/auth/device-flow.js +156 -0
  8. package/dist/auth/token-store.d.ts +53 -0
  9. package/dist/auth/token-store.d.ts.map +1 -0
  10. package/dist/auth/token-store.js +78 -0
  11. package/dist/baseline/diff.d.ts +57 -0
  12. package/dist/baseline/diff.d.ts.map +1 -0
  13. package/dist/baseline/diff.js +152 -0
  14. package/dist/baseline/hash.d.ts +54 -0
  15. package/dist/baseline/hash.d.ts.map +1 -0
  16. package/dist/baseline/hash.js +66 -0
  17. package/dist/baseline/manager.d.ts +89 -0
  18. package/dist/baseline/manager.d.ts.map +1 -0
  19. package/dist/baseline/manager.js +157 -0
  20. package/dist/cache/index.d.ts +8 -0
  21. package/dist/cache/index.d.ts.map +1 -0
  22. package/dist/cache/index.js +7 -0
  23. package/dist/cache/route-cache.d.ts +119 -0
  24. package/dist/cache/route-cache.d.ts.map +1 -0
  25. package/dist/cache/route-cache.js +213 -0
  26. package/dist/ci/changed-routes.d.ts +95 -0
  27. package/dist/ci/changed-routes.d.ts.map +1 -0
  28. package/dist/ci/changed-routes.js +304 -0
  29. package/dist/ci/github-api.d.ts +68 -0
  30. package/dist/ci/github-api.d.ts.map +1 -0
  31. package/dist/ci/github-api.js +138 -0
  32. package/dist/ci/gitlab-api.d.ts +75 -0
  33. package/dist/ci/gitlab-api.d.ts.map +1 -0
  34. package/dist/ci/gitlab-api.js +180 -0
  35. package/dist/ci/index.d.ts +6 -0
  36. package/dist/ci/index.d.ts.map +1 -0
  37. package/dist/ci/index.js +4 -0
  38. package/dist/commands/audit.d.ts +58 -0
  39. package/dist/commands/audit.d.ts.map +1 -0
  40. package/dist/commands/audit.js +862 -0
  41. package/dist/commands/baseline.d.ts +22 -0
  42. package/dist/commands/baseline.d.ts.map +1 -0
  43. package/dist/commands/baseline.js +210 -0
  44. package/dist/commands/comment.d.ts +14 -0
  45. package/dist/commands/comment.d.ts.map +1 -0
  46. package/dist/commands/comment.js +363 -0
  47. package/dist/commands/diff.d.ts +24 -0
  48. package/dist/commands/diff.d.ts.map +1 -0
  49. package/dist/commands/diff.js +196 -0
  50. package/dist/commands/doctor.d.ts +58 -0
  51. package/dist/commands/doctor.d.ts.map +1 -0
  52. package/dist/commands/doctor.js +338 -0
  53. package/dist/commands/download.d.ts +12 -0
  54. package/dist/commands/download.d.ts.map +1 -0
  55. package/dist/commands/download.js +183 -0
  56. package/dist/commands/explain.d.ts +62 -0
  57. package/dist/commands/explain.d.ts.map +1 -0
  58. package/dist/commands/explain.js +302 -0
  59. package/dist/commands/init.d.ts +12 -0
  60. package/dist/commands/init.d.ts.map +1 -0
  61. package/dist/commands/init.js +212 -0
  62. package/dist/commands/login.d.ts +14 -0
  63. package/dist/commands/login.d.ts.map +1 -0
  64. package/dist/commands/login.js +222 -0
  65. package/dist/commands/policy.d.ts +13 -0
  66. package/dist/commands/policy.d.ts.map +1 -0
  67. package/dist/commands/policy.js +347 -0
  68. package/dist/commands/upload.d.ts +12 -0
  69. package/dist/commands/upload.d.ts.map +1 -0
  70. package/dist/commands/upload.js +158 -0
  71. package/dist/config/defaults.d.ts +21 -0
  72. package/dist/config/defaults.d.ts.map +1 -0
  73. package/dist/config/defaults.js +49 -0
  74. package/dist/config/loader.d.ts +66 -0
  75. package/dist/config/loader.d.ts.map +1 -0
  76. package/dist/config/loader.js +167 -0
  77. package/dist/config/schema.d.ts +55 -0
  78. package/dist/config/schema.d.ts.map +1 -0
  79. package/dist/config/schema.js +6 -0
  80. package/dist/index.d.ts +9 -0
  81. package/dist/index.d.ts.map +1 -0
  82. package/dist/index.js +1090 -0
  83. package/dist/interactive/fix-wizard.d.ts +44 -0
  84. package/dist/interactive/fix-wizard.d.ts.map +1 -0
  85. package/dist/interactive/fix-wizard.js +286 -0
  86. package/dist/interactive/init-wizard.d.ts +32 -0
  87. package/dist/interactive/init-wizard.d.ts.map +1 -0
  88. package/dist/interactive/init-wizard.js +193 -0
  89. package/dist/interactive/prompts.d.ts +62 -0
  90. package/dist/interactive/prompts.d.ts.map +1 -0
  91. package/dist/interactive/prompts.js +78 -0
  92. package/dist/monorepo/detector.d.ts +70 -0
  93. package/dist/monorepo/detector.d.ts.map +1 -0
  94. package/dist/monorepo/detector.js +278 -0
  95. package/dist/monorepo/index.d.ts +9 -0
  96. package/dist/monorepo/index.d.ts.map +1 -0
  97. package/dist/monorepo/index.js +8 -0
  98. package/dist/monorepo/workspace.d.ts +142 -0
  99. package/dist/monorepo/workspace.d.ts.map +1 -0
  100. package/dist/monorepo/workspace.js +171 -0
  101. package/dist/output/envelope.d.ts +21 -0
  102. package/dist/output/envelope.d.ts.map +1 -0
  103. package/dist/output/envelope.js +27 -0
  104. package/dist/output/factory.d.ts +73 -0
  105. package/dist/output/factory.d.ts.map +1 -0
  106. package/dist/output/factory.js +60 -0
  107. package/dist/output/formats.d.ts +11 -0
  108. package/dist/output/formats.d.ts.map +1 -0
  109. package/dist/output/formats.js +41 -0
  110. package/dist/output/html.d.ts +45 -0
  111. package/dist/output/html.d.ts.map +1 -0
  112. package/dist/output/html.js +607 -0
  113. package/dist/output/human.d.ts +41 -0
  114. package/dist/output/human.d.ts.map +1 -0
  115. package/dist/output/human.js +274 -0
  116. package/dist/output/json.d.ts +42 -0
  117. package/dist/output/json.d.ts.map +1 -0
  118. package/dist/output/json.js +37 -0
  119. package/dist/output/junit.d.ts +56 -0
  120. package/dist/output/junit.d.ts.map +1 -0
  121. package/dist/output/junit.js +135 -0
  122. package/dist/output/markdown.d.ts +77 -0
  123. package/dist/output/markdown.d.ts.map +1 -0
  124. package/dist/output/markdown.js +411 -0
  125. package/dist/output/sarif.d.ts +160 -0
  126. package/dist/output/sarif.d.ts.map +1 -0
  127. package/dist/output/sarif.js +207 -0
  128. package/dist/policy/evaluator.d.ts +111 -0
  129. package/dist/policy/evaluator.d.ts.map +1 -0
  130. package/dist/policy/evaluator.js +362 -0
  131. package/dist/policy/index.d.ts +15 -0
  132. package/dist/policy/index.d.ts.map +1 -0
  133. package/dist/policy/index.js +11 -0
  134. package/dist/policy/loader.d.ts +97 -0
  135. package/dist/policy/loader.d.ts.map +1 -0
  136. package/dist/policy/loader.js +281 -0
  137. package/dist/policy/schema.d.ts +297 -0
  138. package/dist/policy/schema.d.ts.map +1 -0
  139. package/dist/policy/schema.js +230 -0
  140. package/dist/quality-gate/evaluator.d.ts +58 -0
  141. package/dist/quality-gate/evaluator.d.ts.map +1 -0
  142. package/dist/quality-gate/evaluator.js +274 -0
  143. package/dist/quality-gate/index.d.ts +10 -0
  144. package/dist/quality-gate/index.d.ts.map +1 -0
  145. package/dist/quality-gate/index.js +7 -0
  146. package/dist/quality-gate/types.d.ts +103 -0
  147. package/dist/quality-gate/types.d.ts.map +1 -0
  148. package/dist/quality-gate/types.js +23 -0
  149. package/dist/templates/azure-devops.d.ts +25 -0
  150. package/dist/templates/azure-devops.d.ts.map +1 -0
  151. package/dist/templates/azure-devops.js +109 -0
  152. package/dist/templates/circleci.d.ts +28 -0
  153. package/dist/templates/circleci.d.ts.map +1 -0
  154. package/dist/templates/circleci.js +86 -0
  155. package/dist/templates/github-actions.d.ts +81 -0
  156. package/dist/templates/github-actions.d.ts.map +1 -0
  157. package/dist/templates/github-actions.js +393 -0
  158. package/dist/templates/gitlab-ci.d.ts +26 -0
  159. package/dist/templates/gitlab-ci.d.ts.map +1 -0
  160. package/dist/templates/gitlab-ci.js +70 -0
  161. package/dist/templates/index.d.ts +72 -0
  162. package/dist/templates/index.d.ts.map +1 -0
  163. package/dist/templates/index.js +112 -0
  164. package/dist/templates/jenkins.d.ts +26 -0
  165. package/dist/templates/jenkins.d.ts.map +1 -0
  166. package/dist/templates/jenkins.js +110 -0
  167. package/dist/ui/banner.d.ts +31 -0
  168. package/dist/ui/banner.d.ts.map +1 -0
  169. package/dist/ui/banner.js +84 -0
  170. package/dist/ui/diagnostics.d.ts +39 -0
  171. package/dist/ui/diagnostics.d.ts.map +1 -0
  172. package/dist/ui/diagnostics.js +153 -0
  173. package/dist/ui/spinner.d.ts +61 -0
  174. package/dist/ui/spinner.d.ts.map +1 -0
  175. package/dist/ui/spinner.js +101 -0
  176. package/dist/ui/table.d.ts +63 -0
  177. package/dist/ui/table.d.ts.map +1 -0
  178. package/dist/ui/table.js +236 -0
  179. package/dist/utils/client.d.ts +82 -0
  180. package/dist/utils/client.d.ts.map +1 -0
  181. package/dist/utils/client.js +128 -0
  182. package/dist/utils/detect-env.d.ts +59 -0
  183. package/dist/utils/detect-env.d.ts.map +1 -0
  184. package/dist/utils/detect-env.js +115 -0
  185. package/dist/utils/exit-codes.d.ts +47 -0
  186. package/dist/utils/exit-codes.d.ts.map +1 -0
  187. package/dist/utils/exit-codes.js +61 -0
  188. package/dist/utils/logger.d.ts +87 -0
  189. package/dist/utils/logger.d.ts.map +1 -0
  190. package/dist/utils/logger.js +185 -0
  191. package/dist/utils/sanitize.d.ts +36 -0
  192. package/dist/utils/sanitize.d.ts.map +1 -0
  193. package/dist/utils/sanitize.js +64 -0
  194. package/dist/utils/validators.d.ts +41 -0
  195. package/dist/utils/validators.d.ts.map +1 -0
  196. package/dist/utils/validators.js +123 -0
  197. package/package.json +63 -0
  198. package/schemas/vertaaux.config.schema.json +103 -0
@@ -0,0 +1,607 @@
1
+ /**
2
+ * HTML output formatter for CLI.
3
+ *
4
+ * Generates standalone HTML reports with embedded CSS and JS.
5
+ * Reports are print-friendly and don't require external dependencies.
6
+ */
7
+ /**
8
+ * Normalize issues from various API response formats.
9
+ */
10
+ function normalizeIssues(issues) {
11
+ if (Array.isArray(issues))
12
+ return issues;
13
+ if (issues && typeof issues === "object") {
14
+ const values = Object.values(issues);
15
+ return values.flatMap((value) => Array.isArray(value) ? value : []);
16
+ }
17
+ return [];
18
+ }
19
+ /**
20
+ * Get overall score from scores object.
21
+ */
22
+ function getOverallScore(scores) {
23
+ if (!scores)
24
+ return null;
25
+ const direct = scores.overall ?? scores.ux ?? scores.total;
26
+ if (typeof direct === "number" && Number.isFinite(direct))
27
+ return direct;
28
+ const numeric = Object.values(scores)
29
+ .filter((v) => typeof v === "number" && Number.isFinite(v));
30
+ if (numeric.length === 0)
31
+ return null;
32
+ return Math.round(numeric.reduce((a, b) => a + b, 0) / numeric.length);
33
+ }
34
+ /**
35
+ * Escape HTML special characters.
36
+ */
37
+ function escapeHtml(text) {
38
+ return text
39
+ .replace(/&/g, "&")
40
+ .replace(/</g, "&lt;")
41
+ .replace(/>/g, "&gt;")
42
+ .replace(/"/g, "&quot;")
43
+ .replace(/'/g, "&#039;");
44
+ }
45
+ /**
46
+ * Get score color class based on value.
47
+ */
48
+ function getScoreColor(score) {
49
+ if (score >= 90)
50
+ return "score-good";
51
+ if (score >= 70)
52
+ return "score-warning";
53
+ return "score-bad";
54
+ }
55
+ /**
56
+ * Get severity color class.
57
+ */
58
+ function getSeverityClass(severity) {
59
+ const normalized = severity.toLowerCase();
60
+ if (normalized === "critical" || normalized === "error")
61
+ return "severity-critical";
62
+ if (normalized === "serious" || normalized === "warning")
63
+ return "severity-serious";
64
+ if (normalized === "minor" || normalized === "moderate")
65
+ return "severity-minor";
66
+ return "severity-info";
67
+ }
68
+ /**
69
+ * Get WCAG link from reference string.
70
+ */
71
+ function getWcagLink(reference) {
72
+ if (!reference)
73
+ return "";
74
+ // Extract WCAG criteria like "2.1.1" or "4.1.2"
75
+ const match = reference.match(/(\d+\.\d+\.\d+)/);
76
+ if (match) {
77
+ const criteria = match[1];
78
+ return `https://www.w3.org/WAI/WCAG21/Understanding/${criteria.replace(/\./g, "")}`;
79
+ }
80
+ // Return reference as-is if it looks like a URL
81
+ if (reference.startsWith("http")) {
82
+ return reference;
83
+ }
84
+ return "";
85
+ }
86
+ /**
87
+ * Generate the CSS styles for the report.
88
+ */
89
+ function generateStyles() {
90
+ return `
91
+ :root {
92
+ --color-bg: #0a0f14;
93
+ --color-surface: #121920;
94
+ --color-border: #1e2a36;
95
+ --color-text: #e8eaed;
96
+ --color-text-dim: #8a9299;
97
+ --color-brand: #78FFB4;
98
+ --color-good: #4ade80;
99
+ --color-warning: #fbbf24;
100
+ --color-bad: #f87171;
101
+ --color-info: #60a5fa;
102
+ --font-mono: 'SF Mono', Monaco, 'Cascadia Code', monospace;
103
+ }
104
+
105
+ * {
106
+ box-sizing: border-box;
107
+ margin: 0;
108
+ padding: 0;
109
+ }
110
+
111
+ body {
112
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
113
+ background: var(--color-bg);
114
+ color: var(--color-text);
115
+ line-height: 1.6;
116
+ padding: 2rem;
117
+ }
118
+
119
+ .container {
120
+ max-width: 1200px;
121
+ margin: 0 auto;
122
+ }
123
+
124
+ /* Header */
125
+ header {
126
+ border-bottom: 1px solid var(--color-border);
127
+ padding-bottom: 1.5rem;
128
+ margin-bottom: 2rem;
129
+ }
130
+
131
+ .brand {
132
+ display: flex;
133
+ align-items: center;
134
+ gap: 0.75rem;
135
+ margin-bottom: 1rem;
136
+ }
137
+
138
+ .brand-icon {
139
+ font-size: 2rem;
140
+ color: var(--color-brand);
141
+ }
142
+
143
+ .brand-name {
144
+ font-size: 1.5rem;
145
+ font-weight: 700;
146
+ color: var(--color-brand);
147
+ }
148
+
149
+ .audit-url {
150
+ font-family: var(--font-mono);
151
+ font-size: 0.9rem;
152
+ color: var(--color-text-dim);
153
+ word-break: break-all;
154
+ }
155
+
156
+ .audit-meta {
157
+ display: flex;
158
+ gap: 1.5rem;
159
+ margin-top: 0.75rem;
160
+ font-size: 0.875rem;
161
+ color: var(--color-text-dim);
162
+ }
163
+
164
+ /* Score Cards */
165
+ .scores {
166
+ display: grid;
167
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
168
+ gap: 1rem;
169
+ margin-bottom: 2rem;
170
+ }
171
+
172
+ .score-card {
173
+ background: var(--color-surface);
174
+ border: 1px solid var(--color-border);
175
+ border-radius: 0.5rem;
176
+ padding: 1.25rem;
177
+ text-align: center;
178
+ }
179
+
180
+ .score-card.score-overall {
181
+ grid-column: span 2;
182
+ border-color: var(--color-brand);
183
+ }
184
+
185
+ .score-value {
186
+ font-size: 2.5rem;
187
+ font-weight: 700;
188
+ line-height: 1.2;
189
+ }
190
+
191
+ .score-label {
192
+ font-size: 0.875rem;
193
+ color: var(--color-text-dim);
194
+ text-transform: uppercase;
195
+ letter-spacing: 0.05em;
196
+ }
197
+
198
+ .score-good .score-value { color: var(--color-good); }
199
+ .score-warning .score-value { color: var(--color-warning); }
200
+ .score-bad .score-value { color: var(--color-bad); }
201
+
202
+ /* Issues Section */
203
+ .issues-section {
204
+ margin-bottom: 2rem;
205
+ }
206
+
207
+ .section-header {
208
+ display: flex;
209
+ justify-content: space-between;
210
+ align-items: center;
211
+ margin-bottom: 1rem;
212
+ }
213
+
214
+ .section-title {
215
+ font-size: 1.25rem;
216
+ font-weight: 600;
217
+ }
218
+
219
+ .issue-count {
220
+ background: var(--color-surface);
221
+ padding: 0.25rem 0.75rem;
222
+ border-radius: 1rem;
223
+ font-size: 0.875rem;
224
+ color: var(--color-text-dim);
225
+ }
226
+
227
+ /* Issues Table */
228
+ .issues-table {
229
+ width: 100%;
230
+ border-collapse: collapse;
231
+ background: var(--color-surface);
232
+ border-radius: 0.5rem;
233
+ overflow: hidden;
234
+ }
235
+
236
+ .issues-table th,
237
+ .issues-table td {
238
+ padding: 0.75rem 1rem;
239
+ text-align: left;
240
+ border-bottom: 1px solid var(--color-border);
241
+ }
242
+
243
+ .issues-table th {
244
+ background: rgba(120, 255, 180, 0.05);
245
+ font-weight: 600;
246
+ font-size: 0.875rem;
247
+ text-transform: uppercase;
248
+ letter-spacing: 0.05em;
249
+ color: var(--color-text-dim);
250
+ }
251
+
252
+ .issues-table tr:last-child td {
253
+ border-bottom: none;
254
+ }
255
+
256
+ .issues-table tr:hover {
257
+ background: rgba(255, 255, 255, 0.02);
258
+ }
259
+
260
+ /* Severity Badges */
261
+ .severity-badge {
262
+ display: inline-block;
263
+ padding: 0.25rem 0.5rem;
264
+ border-radius: 0.25rem;
265
+ font-size: 0.75rem;
266
+ font-weight: 600;
267
+ text-transform: uppercase;
268
+ }
269
+
270
+ .severity-critical {
271
+ background: rgba(248, 113, 113, 0.15);
272
+ color: var(--color-bad);
273
+ }
274
+
275
+ .severity-serious {
276
+ background: rgba(251, 191, 36, 0.15);
277
+ color: var(--color-warning);
278
+ }
279
+
280
+ .severity-minor {
281
+ background: rgba(96, 165, 250, 0.15);
282
+ color: var(--color-info);
283
+ }
284
+
285
+ .severity-info {
286
+ background: rgba(138, 146, 153, 0.15);
287
+ color: var(--color-text-dim);
288
+ }
289
+
290
+ /* Issue Details */
291
+ .issue-id {
292
+ font-family: var(--font-mono);
293
+ font-size: 0.875rem;
294
+ color: var(--color-brand);
295
+ }
296
+
297
+ .issue-description {
298
+ max-width: 400px;
299
+ }
300
+
301
+ .issue-selector {
302
+ font-family: var(--font-mono);
303
+ font-size: 0.75rem;
304
+ color: var(--color-text-dim);
305
+ max-width: 200px;
306
+ overflow: hidden;
307
+ text-overflow: ellipsis;
308
+ white-space: nowrap;
309
+ }
310
+
311
+ .wcag-link {
312
+ color: var(--color-info);
313
+ text-decoration: none;
314
+ font-size: 0.875rem;
315
+ }
316
+
317
+ .wcag-link:hover {
318
+ text-decoration: underline;
319
+ }
320
+
321
+ /* Collapsible Details */
322
+ .issue-row {
323
+ cursor: pointer;
324
+ }
325
+
326
+ .issue-details {
327
+ display: none;
328
+ background: rgba(0, 0, 0, 0.2);
329
+ padding: 1rem;
330
+ border-bottom: 1px solid var(--color-border);
331
+ }
332
+
333
+ .issue-details.expanded {
334
+ display: block;
335
+ }
336
+
337
+ .detail-label {
338
+ font-size: 0.75rem;
339
+ text-transform: uppercase;
340
+ color: var(--color-text-dim);
341
+ margin-bottom: 0.25rem;
342
+ }
343
+
344
+ .detail-value {
345
+ margin-bottom: 1rem;
346
+ }
347
+
348
+ /* Footer */
349
+ footer {
350
+ border-top: 1px solid var(--color-border);
351
+ padding-top: 1.5rem;
352
+ margin-top: 2rem;
353
+ display: flex;
354
+ justify-content: space-between;
355
+ align-items: center;
356
+ font-size: 0.875rem;
357
+ color: var(--color-text-dim);
358
+ }
359
+
360
+ .footer-brand {
361
+ display: flex;
362
+ align-items: center;
363
+ gap: 0.5rem;
364
+ }
365
+
366
+ .footer-brand a {
367
+ color: var(--color-brand);
368
+ text-decoration: none;
369
+ }
370
+
371
+ /* Print Styles */
372
+ @media print {
373
+ body {
374
+ background: white;
375
+ color: #1a1a1a;
376
+ padding: 0;
377
+ }
378
+
379
+ .score-card {
380
+ background: #f5f5f5;
381
+ border-color: #ddd;
382
+ }
383
+
384
+ .score-good .score-value { color: #22c55e; }
385
+ .score-warning .score-value { color: #d97706; }
386
+ .score-bad .score-value { color: #dc2626; }
387
+
388
+ .issues-table {
389
+ background: white;
390
+ }
391
+
392
+ .issues-table th {
393
+ background: #f5f5f5;
394
+ }
395
+
396
+ .severity-critical { background: #fef2f2; color: #dc2626; }
397
+ .severity-serious { background: #fffbeb; color: #d97706; }
398
+ .severity-minor { background: #eff6ff; color: #2563eb; }
399
+
400
+ footer {
401
+ page-break-inside: avoid;
402
+ }
403
+ }
404
+ `;
405
+ }
406
+ /**
407
+ * Generate interactive JavaScript for the report.
408
+ */
409
+ function generateScript() {
410
+ return `
411
+ document.addEventListener('DOMContentLoaded', function() {
412
+ // Toggle issue details
413
+ document.querySelectorAll('.issue-row').forEach(function(row) {
414
+ row.addEventListener('click', function() {
415
+ const details = this.nextElementSibling;
416
+ if (details && details.classList.contains('issue-details')) {
417
+ details.classList.toggle('expanded');
418
+ }
419
+ });
420
+ });
421
+
422
+ // Sort table by column
423
+ document.querySelectorAll('.issues-table th[data-sortable]').forEach(function(th) {
424
+ th.style.cursor = 'pointer';
425
+ th.addEventListener('click', function() {
426
+ const table = this.closest('table');
427
+ const tbody = table.querySelector('tbody');
428
+ const rows = Array.from(tbody.querySelectorAll('tr.issue-row'));
429
+ const colIndex = Array.from(th.parentNode.children).indexOf(th);
430
+ const isAsc = th.getAttribute('data-sort') !== 'asc';
431
+
432
+ rows.sort(function(a, b) {
433
+ const aVal = a.children[colIndex].textContent.trim();
434
+ const bVal = b.children[colIndex].textContent.trim();
435
+ return isAsc ? aVal.localeCompare(bVal) : bVal.localeCompare(aVal);
436
+ });
437
+
438
+ th.setAttribute('data-sort', isAsc ? 'asc' : 'desc');
439
+
440
+ // Re-insert sorted rows (with their details)
441
+ rows.forEach(function(row) {
442
+ const details = row.nextElementSibling;
443
+ tbody.appendChild(row);
444
+ if (details && details.classList.contains('issue-details')) {
445
+ tbody.appendChild(details);
446
+ }
447
+ });
448
+ });
449
+ });
450
+ });
451
+ `;
452
+ }
453
+ /**
454
+ * Generate score cards HTML.
455
+ */
456
+ function generateScoreCards(scores) {
457
+ if (!scores)
458
+ return "";
459
+ const overall = getOverallScore(scores);
460
+ const cards = [];
461
+ // Overall score card
462
+ if (overall !== null) {
463
+ cards.push(`
464
+ <div class="score-card score-overall ${getScoreColor(overall)}">
465
+ <div class="score-value">${overall}</div>
466
+ <div class="score-label">Overall Score</div>
467
+ </div>
468
+ `);
469
+ }
470
+ // Category scores
471
+ for (const [key, value] of Object.entries(scores)) {
472
+ if (key === "overall" || typeof value !== "number")
473
+ continue;
474
+ const score = value;
475
+ cards.push(`
476
+ <div class="score-card ${getScoreColor(score)}">
477
+ <div class="score-value">${score}</div>
478
+ <div class="score-label">${escapeHtml(key)}</div>
479
+ </div>
480
+ `);
481
+ }
482
+ return `<div class="scores">${cards.join("")}</div>`;
483
+ }
484
+ /**
485
+ * Generate issues table HTML.
486
+ */
487
+ function generateIssuesTable(issues, interactive) {
488
+ if (issues.length === 0) {
489
+ return `<p style="color: var(--color-good);">No issues found!</p>`;
490
+ }
491
+ const rows = issues.map((issue) => {
492
+ const severity = issue.severity || "info";
493
+ const wcagLink = getWcagLink(issue.wcag_reference);
494
+ const recommendation = issue.recommendation || issue.recommended_fix || "";
495
+ const mainRow = `
496
+ <tr class="issue-row">
497
+ <td>
498
+ <span class="severity-badge ${getSeverityClass(severity)}">
499
+ ${escapeHtml(severity)}
500
+ </span>
501
+ </td>
502
+ <td class="issue-id">${escapeHtml(issue.id || "-")}</td>
503
+ <td class="issue-description">${escapeHtml(issue.description || issue.title || "-")}</td>
504
+ <td class="issue-selector" title="${escapeHtml(issue.selector || "")}">${escapeHtml(issue.selector || "-")}</td>
505
+ <td>
506
+ ${wcagLink ? `<a class="wcag-link" href="${wcagLink}" target="_blank">${escapeHtml(issue.wcag_reference || "")}</a>` : escapeHtml(issue.wcag_reference || "-")}
507
+ </td>
508
+ </tr>
509
+ `;
510
+ const detailsRow = interactive && recommendation ? `
511
+ <tr class="issue-details">
512
+ <td colspan="5">
513
+ <div class="detail-label">Recommendation</div>
514
+ <div class="detail-value">${escapeHtml(recommendation)}</div>
515
+ ${issue.selector ? `
516
+ <div class="detail-label">Selector</div>
517
+ <div class="detail-value" style="font-family: var(--font-mono); font-size: 0.875rem;">${escapeHtml(issue.selector)}</div>
518
+ ` : ""}
519
+ </td>
520
+ </tr>
521
+ ` : "";
522
+ return mainRow + detailsRow;
523
+ });
524
+ return `
525
+ <table class="issues-table">
526
+ <thead>
527
+ <tr>
528
+ <th data-sortable>Severity</th>
529
+ <th data-sortable>ID</th>
530
+ <th>Description</th>
531
+ <th>Selector</th>
532
+ <th>WCAG</th>
533
+ </tr>
534
+ </thead>
535
+ <tbody>
536
+ ${rows.join("")}
537
+ </tbody>
538
+ </table>
539
+ `;
540
+ }
541
+ /**
542
+ * Format audit result as standalone HTML report.
543
+ *
544
+ * @param result - Audit result object
545
+ * @param options - Formatting options
546
+ * @returns Complete HTML document string
547
+ */
548
+ export function formatAuditHtml(result, options = {}) {
549
+ const { title = "VertaaUX Audit Report", interactive = true } = options;
550
+ const issues = normalizeIssues(result.issues);
551
+ const timestamp = new Date().toISOString();
552
+ const auditDate = result.completed_at
553
+ ? new Date(result.completed_at).toLocaleDateString()
554
+ : new Date().toLocaleDateString();
555
+ // Count issues by severity
556
+ const severityCounts = {};
557
+ for (const issue of issues) {
558
+ const sev = issue.severity?.toLowerCase() || "info";
559
+ severityCounts[sev] = (severityCounts[sev] || 0) + 1;
560
+ }
561
+ return `<!DOCTYPE html>
562
+ <html lang="en">
563
+ <head>
564
+ <meta charset="UTF-8">
565
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
566
+ <title>${escapeHtml(title)}</title>
567
+ <style>${generateStyles()}</style>
568
+ </head>
569
+ <body>
570
+ <div class="container">
571
+ <header>
572
+ <div class="brand">
573
+ <span class="brand-icon">V</span>
574
+ <span class="brand-name">VertaaUX</span>
575
+ </div>
576
+ <div class="audit-url">${escapeHtml(result.url || "Unknown URL")}</div>
577
+ <div class="audit-meta">
578
+ <span>Mode: ${escapeHtml(result.mode || "basic")}</span>
579
+ <span>Date: ${auditDate}</span>
580
+ ${result.job_id ? `<span>Job: ${escapeHtml(result.job_id)}</span>` : ""}
581
+ </div>
582
+ </header>
583
+
584
+ ${generateScoreCards(result.scores)}
585
+
586
+ <section class="issues-section">
587
+ <div class="section-header">
588
+ <h2 class="section-title">Issues Found</h2>
589
+ <span class="issue-count">${issues.length} total</span>
590
+ </div>
591
+ ${generateIssuesTable(issues, interactive)}
592
+ </section>
593
+
594
+ <footer>
595
+ <div class="footer-brand">
596
+ Generated by <a href="https://vertaaux.ai">VertaaUX</a>
597
+ </div>
598
+ <div class="footer-timestamp">
599
+ ${timestamp}
600
+ </div>
601
+ </footer>
602
+ </div>
603
+
604
+ ${interactive ? `<script>${generateScript()}</script>` : ""}
605
+ </body>
606
+ </html>`;
607
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Human-readable output formatter for CLI.
3
+ *
4
+ * Outputs audit results as colorful, formatted text for terminal display.
5
+ * Uses chalk for colors and cli-table3 for table formatting.
6
+ */
7
+ import { type FormatTableOptions } from "../ui/table.js";
8
+ export interface AuditResult {
9
+ job_id?: string;
10
+ status?: string;
11
+ url?: string;
12
+ mode?: string;
13
+ progress?: number;
14
+ created_at?: string;
15
+ started_at?: string;
16
+ completed_at?: string;
17
+ scores?: Record<string, unknown>;
18
+ issues?: unknown;
19
+ error?: string;
20
+ }
21
+ export interface FormatHumanOptions {
22
+ /** How to group issues: severity (default), category, route */
23
+ groupBy?: "severity" | "category" | "route";
24
+ /** Whether to show detailed scores table */
25
+ showScores?: boolean;
26
+ /** Whether to show the summary at the end */
27
+ showSummary?: boolean;
28
+ /** Maximum issues to display per group */
29
+ maxIssuesPerGroup?: number;
30
+ /** Table formatting options */
31
+ tableOptions?: FormatTableOptions;
32
+ }
33
+ /**
34
+ * Format audit result as human-readable string.
35
+ *
36
+ * @param result - Audit result object
37
+ * @param options - Formatting options
38
+ * @returns Formatted string for terminal display
39
+ */
40
+ export declare function formatAuditHuman(result: AuditResult, options?: FormatHumanOptions): string;
41
+ //# sourceMappingURL=human.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"human.d.ts","sourceRoot":"","sources":["../../src/output/human.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAOL,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AAGxB,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,+DAA+D;IAC/D,OAAO,CAAC,EAAE,UAAU,GAAG,UAAU,GAAG,OAAO,CAAC;IAC5C,4CAA4C;IAC5C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,6CAA6C;IAC7C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,0CAA0C;IAC1C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,+BAA+B;IAC/B,YAAY,CAAC,EAAE,kBAAkB,CAAC;CACnC;AAmRD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,WAAW,EACnB,OAAO,GAAE,kBAAuB,GAC/B,MAAM,CAkDR"}