@empline/preflight 1.1.47 → 1.1.49
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/dist/bin/init.d.ts +18 -0
- package/dist/bin/init.d.ts.map +1 -0
- package/dist/bin/init.js +369 -0
- package/dist/bin/init.js.map +1 -0
- package/dist/bin/preflight.js +201 -0
- package/dist/bin/preflight.js.map +1 -1
- package/dist/bin/preinstall.js +7 -0
- package/dist/bin/preinstall.js.map +1 -1
- package/dist/checks/react/vercel-react-best-practices.d.ts +38 -0
- package/dist/checks/react/vercel-react-best-practices.d.ts.map +1 -0
- package/dist/checks/react/vercel-react-best-practices.js +547 -0
- package/dist/checks/react/vercel-react-best-practices.js.map +1 -0
- package/dist/checks/system/preflight-actionable-output.d.ts +18 -0
- package/dist/checks/system/preflight-actionable-output.d.ts.map +1 -0
- package/dist/checks/system/preflight-actionable-output.js +216 -0
- package/dist/checks/system/preflight-actionable-output.js.map +1 -0
- package/dist/checks/ui/responsive-text-truncation.d.ts.map +1 -1
- package/dist/checks/ui/responsive-text-truncation.js +16 -8
- package/dist/checks/ui/responsive-text-truncation.js.map +1 -1
- package/dist/checks/ui/web-design-guidelines.d.ts +37 -0
- package/dist/checks/ui/web-design-guidelines.d.ts.map +1 -0
- package/dist/checks/ui/web-design-guidelines.js +545 -0
- package/dist/checks/ui/web-design-guidelines.js.map +1 -0
- package/dist/lib/activation.d.ts +18 -0
- package/dist/lib/activation.d.ts.map +1 -0
- package/dist/lib/activation.js +283 -0
- package/dist/lib/activation.js.map +1 -0
- package/dist/lib/ai-commands.d.ts +72 -0
- package/dist/lib/ai-commands.d.ts.map +1 -0
- package/dist/lib/ai-commands.js +393 -0
- package/dist/lib/ai-commands.js.map +1 -0
- package/dist/runner.d.ts +20 -0
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +176 -54
- package/dist/runner.js.map +1 -1
- package/dist/shared/concurrency-config.d.ts +2 -0
- package/dist/shared/concurrency-config.d.ts.map +1 -1
- package/dist/shared/concurrency-config.js +12 -1
- package/dist/shared/concurrency-config.js.map +1 -1
- package/dist/utils/console-chars.d.ts +6 -6
- package/package.json +2 -1
- package/templates/domain-specific/trading-card-system/missing-page-layout.ts +377 -0
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* Preflight: Web Design Guidelines
|
|
5
|
+
*
|
|
6
|
+
* Validates UI code against Vercel's Web Interface Guidelines.
|
|
7
|
+
* Based on: https://github.com/vercel-labs/web-interface-guidelines
|
|
8
|
+
*
|
|
9
|
+
* Categories checked:
|
|
10
|
+
* - Accessibility (aria-labels, semantic HTML, keyboard support)
|
|
11
|
+
* - Forms (labels, autocomplete, input types)
|
|
12
|
+
* - Images (alt text, dimensions, lazy loading)
|
|
13
|
+
* - Animation (prefers-reduced-motion)
|
|
14
|
+
* - Performance (virtualization hints)
|
|
15
|
+
*/
|
|
16
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
19
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
20
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
21
|
+
}
|
|
22
|
+
Object.defineProperty(o, k2, desc);
|
|
23
|
+
}) : (function(o, m, k, k2) {
|
|
24
|
+
if (k2 === undefined) k2 = k;
|
|
25
|
+
o[k2] = m[k];
|
|
26
|
+
}));
|
|
27
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
28
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
29
|
+
}) : function(o, v) {
|
|
30
|
+
o["default"] = v;
|
|
31
|
+
});
|
|
32
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
33
|
+
var ownKeys = function(o) {
|
|
34
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
35
|
+
var ar = [];
|
|
36
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
37
|
+
return ar;
|
|
38
|
+
};
|
|
39
|
+
return ownKeys(o);
|
|
40
|
+
};
|
|
41
|
+
return function (mod) {
|
|
42
|
+
if (mod && mod.__esModule) return mod;
|
|
43
|
+
var result = {};
|
|
44
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
45
|
+
__setModuleDefault(result, mod);
|
|
46
|
+
return result;
|
|
47
|
+
};
|
|
48
|
+
})();
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.tags = exports.description = exports.blocking = exports.category = exports.name = exports.id = void 0;
|
|
51
|
+
exports.run = run;
|
|
52
|
+
const fs = __importStar(require("fs"));
|
|
53
|
+
const path = __importStar(require("path"));
|
|
54
|
+
const glob_1 = require("glob");
|
|
55
|
+
const console_chars_1 = require("../../utils/console-chars");
|
|
56
|
+
function createDivider(length, _style) {
|
|
57
|
+
return "═".repeat(length);
|
|
58
|
+
}
|
|
59
|
+
function writeFindings(findings) {
|
|
60
|
+
if (process.env.PREFLIGHT_JSON_OUTPUT) {
|
|
61
|
+
console.log(JSON.stringify(findings, null, 2));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Check metadata
|
|
65
|
+
exports.id = "ui/web-design-guidelines";
|
|
66
|
+
exports.name = "Web Design Guidelines";
|
|
67
|
+
exports.category = "ui";
|
|
68
|
+
exports.blocking = false;
|
|
69
|
+
exports.description = "Validates UI code against Vercel's Web Interface Guidelines";
|
|
70
|
+
exports.tags = ["accessibility", "a11y", "ui", "ux", "design", "wcag", "aria"];
|
|
71
|
+
// =============================================================================
|
|
72
|
+
// CONFIGURATION
|
|
73
|
+
// =============================================================================
|
|
74
|
+
const FILE_PATTERNS = [
|
|
75
|
+
"app/**/*.{tsx,jsx}",
|
|
76
|
+
"src/**/*.{tsx,jsx}",
|
|
77
|
+
"pages/**/*.{tsx,jsx}",
|
|
78
|
+
"components/**/*.{tsx,jsx}",
|
|
79
|
+
];
|
|
80
|
+
const EXCLUDE_PATTERNS = [
|
|
81
|
+
"node_modules/**",
|
|
82
|
+
"**/*.test.{ts,tsx}",
|
|
83
|
+
"**/*.spec.{ts,tsx}",
|
|
84
|
+
"**/*.stories.{tsx}",
|
|
85
|
+
"**/*.d.ts",
|
|
86
|
+
".next/**",
|
|
87
|
+
"dist/**",
|
|
88
|
+
];
|
|
89
|
+
// =============================================================================
|
|
90
|
+
// DETECTION FUNCTIONS
|
|
91
|
+
// =============================================================================
|
|
92
|
+
/**
|
|
93
|
+
* Accessibility: Icon-only buttons require aria-label
|
|
94
|
+
*/
|
|
95
|
+
function detectIconButtonsWithoutLabel(content, filePath) {
|
|
96
|
+
const findings = [];
|
|
97
|
+
const lines = content.split("\n");
|
|
98
|
+
for (let i = 0; i < lines.length; i++) {
|
|
99
|
+
const line = lines[i];
|
|
100
|
+
// Detect icon-only buttons (button containing only an icon component)
|
|
101
|
+
if (/<button[^>]*>/.test(line) || /<Button[^>]*>/.test(line)) {
|
|
102
|
+
// Check if it has aria-label
|
|
103
|
+
if (!line.includes("aria-label")) {
|
|
104
|
+
// Look for icon-only pattern in nearby lines
|
|
105
|
+
const context = lines.slice(i, Math.min(i + 3, lines.length)).join(" ");
|
|
106
|
+
if (/<(?:Icon|.*Icon|Svg)[^>]*\/?>/.test(context) && !context.includes("aria-label")) {
|
|
107
|
+
// Check if there's visible text content
|
|
108
|
+
if (!/<button[^>]*>[^<]*\w+[^<]*</.test(context.replace(/<[^>]+>/g, ""))) {
|
|
109
|
+
findings.push({
|
|
110
|
+
file: filePath,
|
|
111
|
+
line: i + 1,
|
|
112
|
+
rule: "a11y-icon-button-label",
|
|
113
|
+
category: "Accessibility",
|
|
114
|
+
message: "Icon-only button missing aria-label",
|
|
115
|
+
suggestion: 'Add aria-label="Description of action" to the button',
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return findings;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Accessibility: Form controls need labels
|
|
126
|
+
*/
|
|
127
|
+
function detectInputsWithoutLabels(content, filePath) {
|
|
128
|
+
const findings = [];
|
|
129
|
+
const lines = content.split("\n");
|
|
130
|
+
for (let i = 0; i < lines.length; i++) {
|
|
131
|
+
const line = lines[i];
|
|
132
|
+
// Detect input/select/textarea without associated label
|
|
133
|
+
if (/<(?:input|select|textarea|Input|Select|Textarea)[^>]*/.test(line)) {
|
|
134
|
+
// Check for aria-label or aria-labelledby or id (which might have label)
|
|
135
|
+
if (!line.includes("aria-label") &&
|
|
136
|
+
!line.includes("aria-labelledby") &&
|
|
137
|
+
!line.includes("type=\"hidden\"") &&
|
|
138
|
+
!line.includes("type=\"submit\"") &&
|
|
139
|
+
!line.includes("type=\"button\"")) {
|
|
140
|
+
// Check if there's an id that might be connected to a label
|
|
141
|
+
const idMatch = line.match(/id=["']([^"']+)["']/);
|
|
142
|
+
if (!idMatch) {
|
|
143
|
+
findings.push({
|
|
144
|
+
file: filePath,
|
|
145
|
+
line: i + 1,
|
|
146
|
+
rule: "a11y-input-label",
|
|
147
|
+
category: "Accessibility",
|
|
148
|
+
message: "Form control missing label association",
|
|
149
|
+
suggestion: 'Add aria-label="Description" or connect with <label htmlFor="id">',
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return findings;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Accessibility: Div onClick should be button
|
|
159
|
+
*/
|
|
160
|
+
function detectClickableDiv(content, filePath) {
|
|
161
|
+
const findings = [];
|
|
162
|
+
const lines = content.split("\n");
|
|
163
|
+
for (let i = 0; i < lines.length; i++) {
|
|
164
|
+
const line = lines[i];
|
|
165
|
+
// Detect <div onClick> pattern
|
|
166
|
+
if (/<div[^>]*onClick[^>]*>/.test(line)) {
|
|
167
|
+
// Check if it has role="button" (acceptable workaround)
|
|
168
|
+
if (!line.includes('role="button"') && !line.includes("role='button'")) {
|
|
169
|
+
findings.push({
|
|
170
|
+
file: filePath,
|
|
171
|
+
line: i + 1,
|
|
172
|
+
rule: "a11y-semantic-button",
|
|
173
|
+
category: "Accessibility",
|
|
174
|
+
message: "<div onClick> should be <button> for actions",
|
|
175
|
+
suggestion: 'Use <button> instead, or add role="button" and keyboard handlers',
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// Detect <span onClick> pattern
|
|
180
|
+
if (/<span[^>]*onClick[^>]*>/.test(line)) {
|
|
181
|
+
if (!line.includes('role="button"') && !line.includes("role='button'")) {
|
|
182
|
+
findings.push({
|
|
183
|
+
file: filePath,
|
|
184
|
+
line: i + 1,
|
|
185
|
+
rule: "a11y-semantic-button",
|
|
186
|
+
category: "Accessibility",
|
|
187
|
+
message: "<span onClick> should be <button> for actions",
|
|
188
|
+
suggestion: 'Use <button> instead, or add role="button" and keyboard handlers',
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return findings;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Accessibility: Images need alt text
|
|
197
|
+
*/
|
|
198
|
+
function detectImagesWithoutAlt(content, filePath) {
|
|
199
|
+
const findings = [];
|
|
200
|
+
const lines = content.split("\n");
|
|
201
|
+
for (let i = 0; i < lines.length; i++) {
|
|
202
|
+
const line = lines[i];
|
|
203
|
+
// Detect <img> or <Image> without alt
|
|
204
|
+
if (/<(?:img|Image)[^>]*/.test(line)) {
|
|
205
|
+
if (!line.includes("alt=") && !line.includes("alt={")) {
|
|
206
|
+
findings.push({
|
|
207
|
+
file: filePath,
|
|
208
|
+
line: i + 1,
|
|
209
|
+
rule: "a11y-image-alt",
|
|
210
|
+
category: "Accessibility",
|
|
211
|
+
message: "Image missing alt attribute",
|
|
212
|
+
suggestion: 'Add alt="Description" or alt="" for decorative images',
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return findings;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Images: Need explicit dimensions
|
|
221
|
+
*/
|
|
222
|
+
function detectImagesWithoutDimensions(content, filePath) {
|
|
223
|
+
const findings = [];
|
|
224
|
+
const lines = content.split("\n");
|
|
225
|
+
for (let i = 0; i < lines.length; i++) {
|
|
226
|
+
const line = lines[i];
|
|
227
|
+
// Detect <img> without width/height
|
|
228
|
+
if (/<img[^>]*/.test(line)) {
|
|
229
|
+
const hasWidth = /width=/.test(line);
|
|
230
|
+
const hasHeight = /height=/.test(line);
|
|
231
|
+
if (!hasWidth || !hasHeight) {
|
|
232
|
+
findings.push({
|
|
233
|
+
file: filePath,
|
|
234
|
+
line: i + 1,
|
|
235
|
+
rule: "perf-image-dimensions",
|
|
236
|
+
category: "Images",
|
|
237
|
+
message: "Image missing explicit width and height (causes layout shift)",
|
|
238
|
+
suggestion: "Add width and height attributes to prevent CLS",
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return findings;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Animation: Honor prefers-reduced-motion
|
|
247
|
+
*/
|
|
248
|
+
function detectAnimationsWithoutMotionPreference(content, filePath) {
|
|
249
|
+
const findings = [];
|
|
250
|
+
// Check if file uses animations
|
|
251
|
+
const hasAnimations = /animate-|animation:|@keyframes|transition:|framer-motion|motion\./i.test(content);
|
|
252
|
+
if (!hasAnimations)
|
|
253
|
+
return findings;
|
|
254
|
+
// Check if prefers-reduced-motion is respected
|
|
255
|
+
const hasMotionCheck = /prefers-reduced-motion|prefersReducedMotion|reducedMotion|useReducedMotion/.test(content);
|
|
256
|
+
if (!hasMotionCheck) {
|
|
257
|
+
// Find first animation reference
|
|
258
|
+
const lines = content.split("\n");
|
|
259
|
+
for (let i = 0; i < lines.length; i++) {
|
|
260
|
+
if (/animate-|animation:|@keyframes|transition:|framer-motion|motion\./.test(lines[i])) {
|
|
261
|
+
findings.push({
|
|
262
|
+
file: filePath,
|
|
263
|
+
line: i + 1,
|
|
264
|
+
rule: "a11y-reduced-motion",
|
|
265
|
+
category: "Animation",
|
|
266
|
+
message: "Animations should respect prefers-reduced-motion",
|
|
267
|
+
suggestion: "Add @media (prefers-reduced-motion: reduce) or use useReducedMotion hook",
|
|
268
|
+
});
|
|
269
|
+
break;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return findings;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Forms: Inputs should have autocomplete
|
|
277
|
+
*/
|
|
278
|
+
function detectInputsWithoutAutocomplete(content, filePath) {
|
|
279
|
+
const findings = [];
|
|
280
|
+
const lines = content.split("\n");
|
|
281
|
+
// Input types that benefit from autocomplete
|
|
282
|
+
const autocompleteTypes = ["email", "password", "tel", "text", "url"];
|
|
283
|
+
for (let i = 0; i < lines.length; i++) {
|
|
284
|
+
const line = lines[i];
|
|
285
|
+
// Detect relevant input types
|
|
286
|
+
for (const type of autocompleteTypes) {
|
|
287
|
+
if (new RegExp(`<(?:input|Input)[^>]*type=["']${type}["']`).test(line) ||
|
|
288
|
+
(type === "text" && /<(?:input|Input)[^>]*/.test(line) && !line.includes("type="))) {
|
|
289
|
+
if (!line.includes("autocomplete") && !line.includes("autoComplete")) {
|
|
290
|
+
// Skip if it's in a search context
|
|
291
|
+
if (!line.includes("search") && !line.includes("Search")) {
|
|
292
|
+
findings.push({
|
|
293
|
+
file: filePath,
|
|
294
|
+
line: i + 1,
|
|
295
|
+
rule: "form-autocomplete",
|
|
296
|
+
category: "Forms",
|
|
297
|
+
message: `Input (${type}) should have autocomplete attribute`,
|
|
298
|
+
suggestion: `Add autoComplete="${type === "email" ? "email" : type === "password" ? "current-password" : "on"}"`,
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return findings;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Forms: Blocking paste should be avoided
|
|
309
|
+
*/
|
|
310
|
+
function detectPastePrevention(content, filePath) {
|
|
311
|
+
const findings = [];
|
|
312
|
+
const lines = content.split("\n");
|
|
313
|
+
for (let i = 0; i < lines.length; i++) {
|
|
314
|
+
const line = lines[i];
|
|
315
|
+
if (/onPaste=.*preventDefault|onpaste.*return false/.test(line)) {
|
|
316
|
+
findings.push({
|
|
317
|
+
file: filePath,
|
|
318
|
+
line: i + 1,
|
|
319
|
+
rule: "form-allow-paste",
|
|
320
|
+
category: "Forms",
|
|
321
|
+
message: "Blocking paste is hostile to users (password managers, accessibility)",
|
|
322
|
+
suggestion: "Remove paste prevention - let users paste freely",
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return findings;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Typography: Use proper ellipsis character
|
|
330
|
+
*/
|
|
331
|
+
function detectWrongEllipsis(content, filePath) {
|
|
332
|
+
const findings = [];
|
|
333
|
+
const lines = content.split("\n");
|
|
334
|
+
for (let i = 0; i < lines.length; i++) {
|
|
335
|
+
const line = lines[i];
|
|
336
|
+
// Detect "..." in user-facing text (not in code/comments)
|
|
337
|
+
if (/["'`][^"'`]*\.\.\.[^"'`]*["'`]/.test(line) &&
|
|
338
|
+
!line.includes("...") && // Skip spread operator
|
|
339
|
+
!line.trim().startsWith("//") // Skip comments
|
|
340
|
+
) {
|
|
341
|
+
// Check if it's likely user-facing text
|
|
342
|
+
if (/placeholder|title|label|message|text|content/i.test(line)) {
|
|
343
|
+
findings.push({
|
|
344
|
+
file: filePath,
|
|
345
|
+
line: i + 1,
|
|
346
|
+
rule: "typo-ellipsis",
|
|
347
|
+
category: "Typography",
|
|
348
|
+
message: 'Use proper ellipsis character "…" instead of "..."',
|
|
349
|
+
suggestion: "Replace ... with … (U+2026)",
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return findings;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Performance: Large lists should be virtualized
|
|
358
|
+
*/
|
|
359
|
+
function detectUnvirtualizedLists(content, filePath) {
|
|
360
|
+
const findings = [];
|
|
361
|
+
const lines = content.split("\n");
|
|
362
|
+
// Check for .map() on large data hints
|
|
363
|
+
for (let i = 0; i < lines.length; i++) {
|
|
364
|
+
const line = lines[i];
|
|
365
|
+
// Detect patterns like items.map, data.map, etc. with potential size hints
|
|
366
|
+
if (/\b(?:items|data|list|rows|records|results|entries)\s*\.map\s*\(/.test(line)) {
|
|
367
|
+
// Check if file imports virtualization libraries
|
|
368
|
+
const hasVirtualization = /react-window|react-virtualized|@tanstack\/react-virtual|virtual/.test(content);
|
|
369
|
+
if (!hasVirtualization) {
|
|
370
|
+
// Look for size hints in the file
|
|
371
|
+
if (/length\s*[>>=]\s*(?:50|100|\d{3,})|\bpagination\b|loadMore/i.test(content)) {
|
|
372
|
+
findings.push({
|
|
373
|
+
file: filePath,
|
|
374
|
+
line: i + 1,
|
|
375
|
+
rule: "perf-virtualize-lists",
|
|
376
|
+
category: "Performance",
|
|
377
|
+
message: "Large lists (>50 items) should use virtualization",
|
|
378
|
+
suggestion: "Consider react-window or @tanstack/react-virtual for better performance",
|
|
379
|
+
});
|
|
380
|
+
break; // Only report once per file
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
return findings;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Focus: Never remove outline without replacement
|
|
389
|
+
*/
|
|
390
|
+
function detectOutlineRemoval(content, filePath) {
|
|
391
|
+
const findings = [];
|
|
392
|
+
const lines = content.split("\n");
|
|
393
|
+
for (let i = 0; i < lines.length; i++) {
|
|
394
|
+
const line = lines[i];
|
|
395
|
+
// Detect outline: none or outline: 0 without focus-visible replacement
|
|
396
|
+
if (/outline:\s*(?:none|0)/.test(line) || /outline-none/.test(line)) {
|
|
397
|
+
// Check if there's a focus replacement nearby
|
|
398
|
+
const context = lines.slice(Math.max(0, i - 3), Math.min(i + 3, lines.length)).join(" ");
|
|
399
|
+
if (!context.includes("focus-visible") &&
|
|
400
|
+
!context.includes("focus:ring") &&
|
|
401
|
+
!context.includes("focus:border")) {
|
|
402
|
+
findings.push({
|
|
403
|
+
file: filePath,
|
|
404
|
+
line: i + 1,
|
|
405
|
+
rule: "a11y-focus-visible",
|
|
406
|
+
category: "Focus States",
|
|
407
|
+
message: "Removing outline without focus replacement breaks keyboard navigation",
|
|
408
|
+
suggestion: "Add focus:ring-* or focus-visible styles instead",
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return findings;
|
|
414
|
+
}
|
|
415
|
+
// =============================================================================
|
|
416
|
+
// MAIN
|
|
417
|
+
// =============================================================================
|
|
418
|
+
async function run() {
|
|
419
|
+
const startTime = Date.now();
|
|
420
|
+
const allFindings = [];
|
|
421
|
+
console.log(`\n${console_chars_1.emoji.accessibility || "[A11Y]"} WEB DESIGN GUIDELINES`);
|
|
422
|
+
console.log(createDivider(65, "heavy"));
|
|
423
|
+
// Find all files
|
|
424
|
+
const allFiles = [];
|
|
425
|
+
for (const pattern of FILE_PATTERNS) {
|
|
426
|
+
const matches = await (0, glob_1.glob)(pattern, {
|
|
427
|
+
cwd: process.cwd(),
|
|
428
|
+
ignore: EXCLUDE_PATTERNS,
|
|
429
|
+
});
|
|
430
|
+
allFiles.push(...matches);
|
|
431
|
+
}
|
|
432
|
+
const uniqueFiles = [...new Set(allFiles)];
|
|
433
|
+
if (uniqueFiles.length === 0) {
|
|
434
|
+
console.log(`${console_chars_1.emoji.skip} No React/JSX files found`);
|
|
435
|
+
return {
|
|
436
|
+
passed: true,
|
|
437
|
+
findings: [],
|
|
438
|
+
duration: Date.now() - startTime,
|
|
439
|
+
metadata: { skipped: true },
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
console.log(`\n${console_chars_1.emoji.search || "[SEARCH]"} Scanning ${uniqueFiles.length} files...`);
|
|
443
|
+
// Analyze each file
|
|
444
|
+
for (const relativePath of uniqueFiles) {
|
|
445
|
+
const filePath = path.join(process.cwd(), relativePath);
|
|
446
|
+
if (!fs.existsSync(filePath))
|
|
447
|
+
continue;
|
|
448
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
449
|
+
// Run all detection functions
|
|
450
|
+
allFindings.push(...detectIconButtonsWithoutLabel(content, relativePath));
|
|
451
|
+
allFindings.push(...detectInputsWithoutLabels(content, relativePath));
|
|
452
|
+
allFindings.push(...detectClickableDiv(content, relativePath));
|
|
453
|
+
allFindings.push(...detectImagesWithoutAlt(content, relativePath));
|
|
454
|
+
allFindings.push(...detectImagesWithoutDimensions(content, relativePath));
|
|
455
|
+
allFindings.push(...detectAnimationsWithoutMotionPreference(content, relativePath));
|
|
456
|
+
allFindings.push(...detectInputsWithoutAutocomplete(content, relativePath));
|
|
457
|
+
allFindings.push(...detectPastePrevention(content, relativePath));
|
|
458
|
+
allFindings.push(...detectWrongEllipsis(content, relativePath));
|
|
459
|
+
allFindings.push(...detectUnvirtualizedLists(content, relativePath));
|
|
460
|
+
allFindings.push(...detectOutlineRemoval(content, relativePath));
|
|
461
|
+
}
|
|
462
|
+
// Group by category
|
|
463
|
+
const byCategory = allFindings.reduce((acc, f) => {
|
|
464
|
+
acc[f.category] = (acc[f.category] || 0) + 1;
|
|
465
|
+
return acc;
|
|
466
|
+
}, {});
|
|
467
|
+
// Convert to PreflightFinding format
|
|
468
|
+
const preflightFindings = allFindings.map((f) => ({
|
|
469
|
+
message: `[${f.rule}] ${f.message}`,
|
|
470
|
+
level: f.category === "Accessibility" ? "error" : "warning",
|
|
471
|
+
file: f.file,
|
|
472
|
+
line: f.line,
|
|
473
|
+
code: f.rule,
|
|
474
|
+
suggestion: f.suggestion,
|
|
475
|
+
}));
|
|
476
|
+
// Summary
|
|
477
|
+
console.log(`\n${console_chars_1.emoji.chart || "[CHART]"} Summary:`);
|
|
478
|
+
console.log(` Files scanned: ${uniqueFiles.length}`);
|
|
479
|
+
console.log(` Total issues: ${allFindings.length}`);
|
|
480
|
+
for (const [cat, count] of Object.entries(byCategory)) {
|
|
481
|
+
console.log(` ${cat}: ${count}`);
|
|
482
|
+
}
|
|
483
|
+
writeFindings(preflightFindings.map((f) => ({
|
|
484
|
+
message: f.message,
|
|
485
|
+
severity: f.level === "error" ? "error" : "warning",
|
|
486
|
+
file: f.file,
|
|
487
|
+
line: f.line,
|
|
488
|
+
code: f.code || exports.id,
|
|
489
|
+
suggestion: f.suggestion,
|
|
490
|
+
})));
|
|
491
|
+
const a11yIssues = allFindings.filter((f) => f.category === "Accessibility").length;
|
|
492
|
+
if (allFindings.length === 0) {
|
|
493
|
+
console.log(`\n${console_chars_1.emoji.success || "[OK]"} WEB DESIGN GUIDELINES PASSED`);
|
|
494
|
+
console.log(`\nNo accessibility or design issues detected.`);
|
|
495
|
+
}
|
|
496
|
+
else {
|
|
497
|
+
// Show findings by category
|
|
498
|
+
const categories = [...new Set(allFindings.map((f) => f.category))];
|
|
499
|
+
for (const category of categories) {
|
|
500
|
+
const catFindings = allFindings.filter((f) => f.category === category);
|
|
501
|
+
const icon = category === "Accessibility" ? console_chars_1.emoji.error : console_chars_1.emoji.warning;
|
|
502
|
+
console.log(`\n${icon} ${category} (${catFindings.length}):`);
|
|
503
|
+
for (const f of catFindings.slice(0, 5)) {
|
|
504
|
+
console.log(` ${f.file}:${f.line}`);
|
|
505
|
+
console.log(` ${f.message}`);
|
|
506
|
+
console.log(` Fix: ${f.suggestion}`);
|
|
507
|
+
}
|
|
508
|
+
if (catFindings.length > 5) {
|
|
509
|
+
console.log(` ... and ${catFindings.length - 5} more`);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
console.log(`\n${console_chars_1.emoji.info || "[INFO]"} Reference:`);
|
|
513
|
+
console.log(` https://github.com/vercel-labs/web-interface-guidelines`);
|
|
514
|
+
const status = a11yIssues > 0 ? "FAILED" : "PASSED WITH WARNINGS";
|
|
515
|
+
console.log(`\n${a11yIssues > 0 ? console_chars_1.emoji.error : console_chars_1.emoji.warning} WEB DESIGN GUIDELINES ${status}`);
|
|
516
|
+
}
|
|
517
|
+
return {
|
|
518
|
+
passed: a11yIssues === 0, // Fail on accessibility issues
|
|
519
|
+
findings: preflightFindings,
|
|
520
|
+
duration: Date.now() - startTime,
|
|
521
|
+
metadata: {
|
|
522
|
+
filesScanned: uniqueFiles.length,
|
|
523
|
+
totalIssues: allFindings.length,
|
|
524
|
+
byCategory,
|
|
525
|
+
rules: [
|
|
526
|
+
"a11y-icon-button-label",
|
|
527
|
+
"a11y-input-label",
|
|
528
|
+
"a11y-semantic-button",
|
|
529
|
+
"a11y-image-alt",
|
|
530
|
+
"a11y-reduced-motion",
|
|
531
|
+
"a11y-focus-visible",
|
|
532
|
+
"perf-image-dimensions",
|
|
533
|
+
"perf-virtualize-lists",
|
|
534
|
+
"form-autocomplete",
|
|
535
|
+
"form-allow-paste",
|
|
536
|
+
"typo-ellipsis",
|
|
537
|
+
],
|
|
538
|
+
},
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
// Standalone execution
|
|
542
|
+
if (require.main === module) {
|
|
543
|
+
run().then((result) => process.exit(result.passed ? 0 : 1));
|
|
544
|
+
}
|
|
545
|
+
//# sourceMappingURL=web-design-guidelines.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-design-guidelines.js","sourceRoot":"","sources":["../../../src/checks/ui/web-design-guidelines.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* License Activation Module
|
|
3
|
+
*
|
|
4
|
+
* Validates license with API and manages grace period.
|
|
5
|
+
* If activation fails beyond grace period, silently self-destructs.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Check activation status.
|
|
9
|
+
* Returns true if activation is valid, false otherwise.
|
|
10
|
+
* If activation is invalid and grace period expired, triggers self-destruct.
|
|
11
|
+
*/
|
|
12
|
+
export declare function checkActivation(): Promise<boolean>;
|
|
13
|
+
/**
|
|
14
|
+
* Initialize activation on first install.
|
|
15
|
+
* Called from preinstall hook.
|
|
16
|
+
*/
|
|
17
|
+
export declare function initializeActivation(): Promise<boolean>;
|
|
18
|
+
//# sourceMappingURL=activation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activation.d.ts","sourceRoot":"","sources":["../../src/lib/activation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAoMH;;;;GAIG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,CA0CxD;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC,CAgC7D"}
|