ai-ccesibility 0.1.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.
- package/EXAMPLES.md +595 -0
- package/LICENSE +21 -0
- package/README.md +233 -0
- package/USAGE.md +498 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +2177 -0
- package/dist/server.js.map +1 -0
- package/package.json +84 -0
package/EXAMPLES.md
ADDED
|
@@ -0,0 +1,595 @@
|
|
|
1
|
+
# Ejemplos de Uso - AI-ccesibility
|
|
2
|
+
|
|
3
|
+
Ejemplos concretos de inputs y outputs para cada herramienta MCP.
|
|
4
|
+
|
|
5
|
+
## Tabla de Contenidos
|
|
6
|
+
|
|
7
|
+
- [analyze-with-axe](#analyze-with-axe)
|
|
8
|
+
- [analyze-with-pa11y](#analyze-with-pa11y)
|
|
9
|
+
- [analyze-with-eslint](#analyze-with-eslint)
|
|
10
|
+
- [analyze-all](#analyze-all)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## analyze-with-axe
|
|
15
|
+
|
|
16
|
+
### Ejemplo 1: Análisis básico de URL
|
|
17
|
+
|
|
18
|
+
**Input:**
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"url": "https://example.com"
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Output:**
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"success": true,
|
|
29
|
+
"target": "https://example.com",
|
|
30
|
+
"issueCount": 5,
|
|
31
|
+
"issues": [
|
|
32
|
+
{
|
|
33
|
+
"id": "axe-core:image-alt:a3f8b9",
|
|
34
|
+
"ruleId": "image-alt",
|
|
35
|
+
"tool": "axe-core",
|
|
36
|
+
"severity": "critical",
|
|
37
|
+
"wcag": {
|
|
38
|
+
"criterion": "1.1.1",
|
|
39
|
+
"level": "A",
|
|
40
|
+
"principle": "perceivable"
|
|
41
|
+
},
|
|
42
|
+
"location": {
|
|
43
|
+
"selector": "img:nth-child(2)",
|
|
44
|
+
"snippet": "<img src=\"logo.png\">"
|
|
45
|
+
},
|
|
46
|
+
"message": "Images must have alternate text",
|
|
47
|
+
"humanContext": "**Contenido no textual (WCAG 1.1.1 - Nivel A)**\n\nTodo contenido no textual debe tener una alternativa de texto...",
|
|
48
|
+
"suggestedActions": [
|
|
49
|
+
"Añadir atributo alt descriptivo a imágenes",
|
|
50
|
+
"Usar aria-label para iconos decorativos con función",
|
|
51
|
+
"Marcar imágenes decorativas con alt=\"\" vacío"
|
|
52
|
+
],
|
|
53
|
+
"affectedUsers": ["screen-reader", "low-vision"],
|
|
54
|
+
"priority": "critical",
|
|
55
|
+
"remediationEffort": "low",
|
|
56
|
+
"confidence": 1
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
"summary": {
|
|
60
|
+
"total": 5,
|
|
61
|
+
"bySeverity": {
|
|
62
|
+
"critical": 1,
|
|
63
|
+
"serious": 2,
|
|
64
|
+
"moderate": 2,
|
|
65
|
+
"minor": 0
|
|
66
|
+
},
|
|
67
|
+
"byPrinciple": {
|
|
68
|
+
"perceivable": 3,
|
|
69
|
+
"operable": 2,
|
|
70
|
+
"understandable": 0,
|
|
71
|
+
"robust": 0
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"duration": 2340
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
### Ejemplo 2: Análisis de HTML raw
|
|
81
|
+
|
|
82
|
+
**Input:**
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"html": "<html><body><form><input type=\"text\" placeholder=\"Email\"><button>Submit</button></form></body></html>",
|
|
86
|
+
"options": {
|
|
87
|
+
"wcagLevel": "AA"
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**Output:**
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"success": true,
|
|
96
|
+
"target": "[html content]",
|
|
97
|
+
"issueCount": 2,
|
|
98
|
+
"issues": [
|
|
99
|
+
{
|
|
100
|
+
"id": "axe-core:label:f3a9b2",
|
|
101
|
+
"ruleId": "label",
|
|
102
|
+
"tool": "axe-core",
|
|
103
|
+
"severity": "serious",
|
|
104
|
+
"wcag": {
|
|
105
|
+
"criterion": "1.3.1",
|
|
106
|
+
"level": "A",
|
|
107
|
+
"principle": "perceivable"
|
|
108
|
+
},
|
|
109
|
+
"location": {
|
|
110
|
+
"selector": "input[type=\"text\"]",
|
|
111
|
+
"snippet": "<input type=\"text\" placeholder=\"Email\">"
|
|
112
|
+
},
|
|
113
|
+
"message": "Form elements must have labels",
|
|
114
|
+
"humanContext": "**Información y relaciones (WCAG 1.3.1 - Nivel A)**...",
|
|
115
|
+
"suggestedActions": [
|
|
116
|
+
"Asociar labels con inputs correctamente",
|
|
117
|
+
"Usar aria-label si label visible no es posible"
|
|
118
|
+
],
|
|
119
|
+
"affectedUsers": ["screen-reader", "cognitive"],
|
|
120
|
+
"priority": "high",
|
|
121
|
+
"remediationEffort": "low"
|
|
122
|
+
}
|
|
123
|
+
],
|
|
124
|
+
"duration": 180
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
### Ejemplo 3: Con opciones avanzadas
|
|
131
|
+
|
|
132
|
+
**Input:**
|
|
133
|
+
```json
|
|
134
|
+
{
|
|
135
|
+
"url": "https://spa-app.com",
|
|
136
|
+
"options": {
|
|
137
|
+
"wcagLevel": "AA",
|
|
138
|
+
"includeIncomplete": false,
|
|
139
|
+
"browser": {
|
|
140
|
+
"waitForSelector": "#app-loaded",
|
|
141
|
+
"waitForTimeout": 3000,
|
|
142
|
+
"viewport": {
|
|
143
|
+
"width": 1280,
|
|
144
|
+
"height": 720
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## analyze-with-pa11y
|
|
154
|
+
|
|
155
|
+
### Ejemplo 1: Análisis con standard específico
|
|
156
|
+
|
|
157
|
+
**Input:**
|
|
158
|
+
```json
|
|
159
|
+
{
|
|
160
|
+
"url": "https://example.com",
|
|
161
|
+
"options": {
|
|
162
|
+
"standard": "WCAG21AA",
|
|
163
|
+
"includeWarnings": true,
|
|
164
|
+
"includeNotices": false
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Output:**
|
|
170
|
+
```json
|
|
171
|
+
{
|
|
172
|
+
"success": true,
|
|
173
|
+
"target": "https://example.com",
|
|
174
|
+
"issueCount": 3,
|
|
175
|
+
"issues": [
|
|
176
|
+
{
|
|
177
|
+
"id": "pa11y:WCAG2AA.Principle1.Guideline1_1.1_1_1.H37:8f3a2b",
|
|
178
|
+
"ruleId": "WCAG2AA.Principle1.Guideline1_1.1_1_1.H37",
|
|
179
|
+
"tool": "pa11y",
|
|
180
|
+
"severity": "serious",
|
|
181
|
+
"wcag": {
|
|
182
|
+
"criterion": "1.1.1",
|
|
183
|
+
"level": "AA",
|
|
184
|
+
"principle": "perceivable",
|
|
185
|
+
"version": "2.1"
|
|
186
|
+
},
|
|
187
|
+
"location": {
|
|
188
|
+
"selector": "html > body > img:nth-child(3)",
|
|
189
|
+
"snippet": "<img src=\"banner.jpg\">"
|
|
190
|
+
},
|
|
191
|
+
"message": "Img element missing an alt attribute. Use the alt attribute to specify a short text alternative.",
|
|
192
|
+
"humanContext": "**Contenido no textual (WCAG 1.1.1 - Nivel A)**...",
|
|
193
|
+
"affectedUsers": ["screen-reader", "low-vision"],
|
|
194
|
+
"priority": "critical",
|
|
195
|
+
"remediationEffort": "low",
|
|
196
|
+
"confidence": 1
|
|
197
|
+
}
|
|
198
|
+
],
|
|
199
|
+
"summary": {
|
|
200
|
+
"total": 3,
|
|
201
|
+
"bySeverity": {
|
|
202
|
+
"critical": 0,
|
|
203
|
+
"serious": 2,
|
|
204
|
+
"moderate": 1,
|
|
205
|
+
"minor": 0
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
"metadata": {
|
|
209
|
+
"toolVersion": "9.0.1",
|
|
210
|
+
"pageTitle": "Example Domain"
|
|
211
|
+
},
|
|
212
|
+
"duration": 1890
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## analyze-with-eslint
|
|
219
|
+
|
|
220
|
+
### Ejemplo 1: Análisis de archivo Vue
|
|
221
|
+
|
|
222
|
+
**Input:**
|
|
223
|
+
```json
|
|
224
|
+
{
|
|
225
|
+
"files": ["src/components/LoginForm.vue"]
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
**Output:**
|
|
230
|
+
```json
|
|
231
|
+
{
|
|
232
|
+
"success": true,
|
|
233
|
+
"target": "src/components/LoginForm.vue",
|
|
234
|
+
"issueCount": 4,
|
|
235
|
+
"issues": [
|
|
236
|
+
{
|
|
237
|
+
"id": "eslint-vuejs-a11y:vuejs-accessibility/click-events-have-key-events:src/components/LoginForm.vue:42:15:f8a3c2",
|
|
238
|
+
"ruleId": "vuejs-accessibility/click-events-have-key-events",
|
|
239
|
+
"tool": "eslint-vuejs-a11y",
|
|
240
|
+
"severity": "serious",
|
|
241
|
+
"wcag": {
|
|
242
|
+
"criterion": "2.1.1",
|
|
243
|
+
"level": "A",
|
|
244
|
+
"principle": "operable",
|
|
245
|
+
"version": "2.1"
|
|
246
|
+
},
|
|
247
|
+
"location": {
|
|
248
|
+
"file": "src/components/LoginForm.vue",
|
|
249
|
+
"line": 42,
|
|
250
|
+
"column": 15,
|
|
251
|
+
"snippet": "<div @click=\"togglePassword\">"
|
|
252
|
+
},
|
|
253
|
+
"message": "Elements with click handlers must have corresponding key event handlers.",
|
|
254
|
+
"humanContext": "**Teclado (WCAG 2.1.1 - Nivel A)**\n\nToda funcionalidad debe ser operable mediante teclado...",
|
|
255
|
+
"suggestedActions": [
|
|
256
|
+
"Añadir manejadores de eventos de teclado (onKeyDown, onKeyPress)",
|
|
257
|
+
"Usar elementos interactivos nativos (button, a, input)"
|
|
258
|
+
],
|
|
259
|
+
"affectedUsers": ["keyboard-only", "motor-impaired", "screen-reader"],
|
|
260
|
+
"priority": "critical",
|
|
261
|
+
"remediationEffort": "medium",
|
|
262
|
+
"confidence": 1
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
"id": "eslint-vuejs-a11y:vuejs-accessibility/form-control-has-label:src/components/LoginForm.vue:28:10:b9f2a1",
|
|
266
|
+
"ruleId": "vuejs-accessibility/form-control-has-label",
|
|
267
|
+
"tool": "eslint-vuejs-a11y",
|
|
268
|
+
"severity": "serious",
|
|
269
|
+
"wcag": {
|
|
270
|
+
"criterion": "1.3.1",
|
|
271
|
+
"level": "A",
|
|
272
|
+
"principle": "perceivable",
|
|
273
|
+
"version": "2.1"
|
|
274
|
+
},
|
|
275
|
+
"location": {
|
|
276
|
+
"file": "src/components/LoginForm.vue",
|
|
277
|
+
"line": 28,
|
|
278
|
+
"column": 10
|
|
279
|
+
},
|
|
280
|
+
"message": "A form control must have a label.",
|
|
281
|
+
"humanContext": "**Información y relaciones (WCAG 1.3.1 - Nivel A)**...",
|
|
282
|
+
"affectedUsers": ["screen-reader", "cognitive"],
|
|
283
|
+
"priority": "high",
|
|
284
|
+
"remediationEffort": "low"
|
|
285
|
+
}
|
|
286
|
+
],
|
|
287
|
+
"summary": {
|
|
288
|
+
"total": 4,
|
|
289
|
+
"bySeverity": {
|
|
290
|
+
"critical": 0,
|
|
291
|
+
"serious": 4,
|
|
292
|
+
"moderate": 0,
|
|
293
|
+
"minor": 0
|
|
294
|
+
},
|
|
295
|
+
"byRule": {
|
|
296
|
+
"vuejs-accessibility/click-events-have-key-events": 2,
|
|
297
|
+
"vuejs-accessibility/form-control-has-label": 2
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
"duration": 450
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
### Ejemplo 2: Análisis de código inline
|
|
307
|
+
|
|
308
|
+
**Input:**
|
|
309
|
+
```json
|
|
310
|
+
{
|
|
311
|
+
"code": "<template>\n <div>\n <img src=\"avatar.jpg\" />\n <div @click=\"handleClick\">Click me</div>\n </div>\n</template>\n\n<script>\nexport default {\n methods: {\n handleClick() {\n console.log('clicked');\n }\n }\n};\n</script>"
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
**Output:**
|
|
316
|
+
```json
|
|
317
|
+
{
|
|
318
|
+
"success": true,
|
|
319
|
+
"target": "inline.vue",
|
|
320
|
+
"issueCount": 2,
|
|
321
|
+
"issues": [
|
|
322
|
+
{
|
|
323
|
+
"ruleId": "vuejs-accessibility/alt-text",
|
|
324
|
+
"message": "img elements must have an alt prop...",
|
|
325
|
+
"location": {
|
|
326
|
+
"file": "inline.vue",
|
|
327
|
+
"line": 3,
|
|
328
|
+
"column": 5
|
|
329
|
+
}
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
"ruleId": "vuejs-accessibility/no-static-element-interactions",
|
|
333
|
+
"message": "Static HTML elements with event handlers require a role...",
|
|
334
|
+
"location": {
|
|
335
|
+
"file": "inline.vue",
|
|
336
|
+
"line": 4,
|
|
337
|
+
"column": 5
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
]
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## analyze-all
|
|
347
|
+
|
|
348
|
+
### Ejemplo 1: Análisis combinado básico
|
|
349
|
+
|
|
350
|
+
**Input:**
|
|
351
|
+
```json
|
|
352
|
+
{
|
|
353
|
+
"url": "https://example.com",
|
|
354
|
+
"tools": ["axe-core", "pa11y"],
|
|
355
|
+
"options": {
|
|
356
|
+
"wcagLevel": "AA",
|
|
357
|
+
"deduplicateResults": true
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**Output:**
|
|
363
|
+
```json
|
|
364
|
+
{
|
|
365
|
+
"success": true,
|
|
366
|
+
"target": "https://example.com",
|
|
367
|
+
"toolsUsed": ["axe-core", "pa11y"],
|
|
368
|
+
"issueCount": 8,
|
|
369
|
+
"deduplicatedCount": 12,
|
|
370
|
+
"issues": [
|
|
371
|
+
{
|
|
372
|
+
"id": "axe-core:image-alt:a3f8b9",
|
|
373
|
+
"ruleId": "image-alt",
|
|
374
|
+
"tool": "axe-core",
|
|
375
|
+
"severity": "critical",
|
|
376
|
+
"message": "Images must have alternate text",
|
|
377
|
+
"humanContext": "**Contenido no textual (WCAG 1.1.1 - Nivel A)**...",
|
|
378
|
+
"affectedUsers": ["screen-reader", "low-vision"],
|
|
379
|
+
"priority": "critical",
|
|
380
|
+
"remediationEffort": "low"
|
|
381
|
+
}
|
|
382
|
+
],
|
|
383
|
+
"issuesByWCAG": {
|
|
384
|
+
"1.1.1": [
|
|
385
|
+
{
|
|
386
|
+
"tool": "axe-core",
|
|
387
|
+
"ruleId": "image-alt"
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
"tool": "axe-core",
|
|
391
|
+
"ruleId": "input-image-alt"
|
|
392
|
+
}
|
|
393
|
+
],
|
|
394
|
+
"1.3.1": [
|
|
395
|
+
{
|
|
396
|
+
"tool": "pa11y",
|
|
397
|
+
"ruleId": "WCAG2AA.Principle1.Guideline1_3..."
|
|
398
|
+
}
|
|
399
|
+
],
|
|
400
|
+
"2.1.1": [
|
|
401
|
+
{
|
|
402
|
+
"tool": "axe-core",
|
|
403
|
+
"ruleId": "button-name"
|
|
404
|
+
}
|
|
405
|
+
]
|
|
406
|
+
},
|
|
407
|
+
"summary": {
|
|
408
|
+
"total": 8,
|
|
409
|
+
"bySeverity": {
|
|
410
|
+
"critical": 2,
|
|
411
|
+
"serious": 4,
|
|
412
|
+
"moderate": 2,
|
|
413
|
+
"minor": 0
|
|
414
|
+
},
|
|
415
|
+
"byPrinciple": {
|
|
416
|
+
"perceivable": 5,
|
|
417
|
+
"operable": 3,
|
|
418
|
+
"understandable": 0,
|
|
419
|
+
"robust": 0
|
|
420
|
+
},
|
|
421
|
+
"byTool": {
|
|
422
|
+
"axe-core": 5,
|
|
423
|
+
"pa11y": 3
|
|
424
|
+
}
|
|
425
|
+
},
|
|
426
|
+
"individualResults": [
|
|
427
|
+
{
|
|
428
|
+
"tool": "axe-core",
|
|
429
|
+
"success": true,
|
|
430
|
+
"issues": [],
|
|
431
|
+
"duration": 2340
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
"tool": "pa11y",
|
|
435
|
+
"success": true,
|
|
436
|
+
"issues": [],
|
|
437
|
+
"duration": 1890
|
|
438
|
+
}
|
|
439
|
+
],
|
|
440
|
+
"duration": 2500
|
|
441
|
+
}
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
### Ejemplo 2: Sin deduplicación
|
|
447
|
+
|
|
448
|
+
**Input:**
|
|
449
|
+
```json
|
|
450
|
+
{
|
|
451
|
+
"url": "https://example.com",
|
|
452
|
+
"tools": ["axe-core", "pa11y"],
|
|
453
|
+
"options": {
|
|
454
|
+
"deduplicateResults": false
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
**Output:**
|
|
460
|
+
```json
|
|
461
|
+
{
|
|
462
|
+
"issueCount": 12,
|
|
463
|
+
"deduplicatedCount": 12,
|
|
464
|
+
"issues": [
|
|
465
|
+
{
|
|
466
|
+
"tool": "axe-core",
|
|
467
|
+
"ruleId": "image-alt",
|
|
468
|
+
"location": { "selector": "img:nth-child(2)" }
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
"tool": "pa11y",
|
|
472
|
+
"ruleId": "WCAG2AA.Principle1.Guideline1_1.1_1_1.H37",
|
|
473
|
+
"location": { "selector": "html > body > img:nth-child(2)" }
|
|
474
|
+
}
|
|
475
|
+
]
|
|
476
|
+
}
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
**Nota:** Ambos detectaron la misma imagen sin `alt`, pero con diferentes selectores.
|
|
480
|
+
|
|
481
|
+
---
|
|
482
|
+
|
|
483
|
+
### Ejemplo 3: Con viewport móvil
|
|
484
|
+
|
|
485
|
+
**Input:**
|
|
486
|
+
```json
|
|
487
|
+
{
|
|
488
|
+
"url": "https://responsive-site.com",
|
|
489
|
+
"tools": ["axe-core", "pa11y"],
|
|
490
|
+
"options": {
|
|
491
|
+
"wcagLevel": "AA",
|
|
492
|
+
"browser": {
|
|
493
|
+
"viewport": {
|
|
494
|
+
"width": 375,
|
|
495
|
+
"height": 667
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
---
|
|
503
|
+
|
|
504
|
+
## Comparación de Outputs por Herramienta
|
|
505
|
+
|
|
506
|
+
### Mismo Issue detectado por diferentes tools
|
|
507
|
+
|
|
508
|
+
**Axe-core:**
|
|
509
|
+
```json
|
|
510
|
+
{
|
|
511
|
+
"tool": "axe-core",
|
|
512
|
+
"ruleId": "image-alt",
|
|
513
|
+
"severity": "critical",
|
|
514
|
+
"location": {
|
|
515
|
+
"selector": "img:nth-child(2)"
|
|
516
|
+
},
|
|
517
|
+
"message": "Images must have alternate text"
|
|
518
|
+
}
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
**Pa11y:**
|
|
522
|
+
```json
|
|
523
|
+
{
|
|
524
|
+
"tool": "pa11y",
|
|
525
|
+
"ruleId": "WCAG2AA.Principle1.Guideline1_1.1_1_1.H37",
|
|
526
|
+
"severity": "serious",
|
|
527
|
+
"location": {
|
|
528
|
+
"selector": "html > body > img:nth-child(2)"
|
|
529
|
+
},
|
|
530
|
+
"message": "Img element missing an alt attribute..."
|
|
531
|
+
}
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
**ESLint (en código Vue):**
|
|
535
|
+
```json
|
|
536
|
+
{
|
|
537
|
+
"tool": "eslint-vuejs-a11y",
|
|
538
|
+
"ruleId": "vuejs-accessibility/alt-text",
|
|
539
|
+
"severity": "serious",
|
|
540
|
+
"location": {
|
|
541
|
+
"file": "src/components/Avatar.vue",
|
|
542
|
+
"line": 12,
|
|
543
|
+
"column": 8
|
|
544
|
+
},
|
|
545
|
+
"message": "img elements must have an alt prop..."
|
|
546
|
+
}
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
---
|
|
550
|
+
|
|
551
|
+
## Resumen de Diferencias
|
|
552
|
+
|
|
553
|
+
| Característica | axe-core | Pa11y | ESLint |
|
|
554
|
+
|----------------|----------|-------|--------|
|
|
555
|
+
| **Target** | URL/HTML | URL/HTML | Archivos .vue |
|
|
556
|
+
| **Selector** | CSS compacto | CSS completo | Línea/columna |
|
|
557
|
+
| **Severidades** | 4 niveles | 3 tipos | 2 niveles (warn/error) |
|
|
558
|
+
| **Snippet** | ✅ | ✅ | ✅ |
|
|
559
|
+
| **Confidence** | ✅ | ✅ | Siempre 1 |
|
|
560
|
+
| **Browser** | Puppeteer | Puppeteer | - |
|
|
561
|
+
| **Velocidad** | ~2-3s | ~2s | <1s |
|
|
562
|
+
| **Falsos positivos** | Pocos | Moderados | Muy pocos |
|
|
563
|
+
|
|
564
|
+
---
|
|
565
|
+
|
|
566
|
+
## Tips para Interpretar Resultados
|
|
567
|
+
|
|
568
|
+
### 1. Priorizar por Matriz
|
|
569
|
+
|
|
570
|
+
```
|
|
571
|
+
Critical + Low effort = Fix HOY
|
|
572
|
+
Critical + Medium/High effort = Planificar sprint
|
|
573
|
+
High + Low effort = Quick wins
|
|
574
|
+
Medium/Low + High effort = Backlog
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
### 2. Validar Duplicados
|
|
578
|
+
|
|
579
|
+
Si `deduplicatedCount` > `issueCount`, revisa `individualResults` para ver qué herramienta es más confiable para ese tipo de issue.
|
|
580
|
+
|
|
581
|
+
### 3. Revisar `affectedUsers`
|
|
582
|
+
|
|
583
|
+
Prioriza issues que afecten a usuarios de screen readers y keyboard-only (más comunes).
|
|
584
|
+
|
|
585
|
+
### 4. Aprovechar `humanContext`
|
|
586
|
+
|
|
587
|
+
Lee los ejemplos del mundo real para entender el impacto real en usuarios.
|
|
588
|
+
|
|
589
|
+
---
|
|
590
|
+
|
|
591
|
+
## Next Steps
|
|
592
|
+
|
|
593
|
+
- Ver [USAGE.md](./USAGE.md) para workflows completos
|
|
594
|
+
- Ver [README.md](./README.md) para configuración
|
|
595
|
+
- Ver `src/data/README.md` para añadir más criterios WCAG
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Diego Razquin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|