claude-in-mobile 3.5.0 → 3.6.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 (126) hide show
  1. package/dist/a11y/formatter.d.ts +36 -0
  2. package/dist/a11y/formatter.d.ts.map +1 -0
  3. package/dist/a11y/formatter.js +134 -0
  4. package/dist/a11y/formatter.js.map +1 -0
  5. package/dist/a11y/rules/duplicate-descriptions.d.ts +3 -0
  6. package/dist/a11y/rules/duplicate-descriptions.d.ts.map +1 -0
  7. package/dist/a11y/rules/duplicate-descriptions.js +50 -0
  8. package/dist/a11y/rules/duplicate-descriptions.js.map +1 -0
  9. package/dist/a11y/rules/focus-order.d.ts +3 -0
  10. package/dist/a11y/rules/focus-order.d.ts.map +1 -0
  11. package/dist/a11y/rules/focus-order.js +35 -0
  12. package/dist/a11y/rules/focus-order.js.map +1 -0
  13. package/dist/a11y/rules/index.d.ts +4 -0
  14. package/dist/a11y/rules/index.d.ts.map +1 -0
  15. package/dist/a11y/rules/index.js +19 -0
  16. package/dist/a11y/rules/index.js.map +1 -0
  17. package/dist/a11y/rules/interactive-labels.d.ts +3 -0
  18. package/dist/a11y/rules/interactive-labels.d.ts.map +1 -0
  19. package/dist/a11y/rules/interactive-labels.js +39 -0
  20. package/dist/a11y/rules/interactive-labels.js.map +1 -0
  21. package/dist/a11y/rules/missing-label.d.ts +3 -0
  22. package/dist/a11y/rules/missing-label.d.ts.map +1 -0
  23. package/dist/a11y/rules/missing-label.js +64 -0
  24. package/dist/a11y/rules/missing-label.js.map +1 -0
  25. package/dist/a11y/rules/state-description.d.ts +3 -0
  26. package/dist/a11y/rules/state-description.d.ts.map +1 -0
  27. package/dist/a11y/rules/state-description.js +37 -0
  28. package/dist/a11y/rules/state-description.js.map +1 -0
  29. package/dist/a11y/rules/touch-target.d.ts +3 -0
  30. package/dist/a11y/rules/touch-target.d.ts.map +1 -0
  31. package/dist/a11y/rules/touch-target.js +37 -0
  32. package/dist/a11y/rules/touch-target.js.map +1 -0
  33. package/dist/a11y/score.d.ts +7 -0
  34. package/dist/a11y/score.d.ts.map +1 -0
  35. package/dist/a11y/score.js +10 -0
  36. package/dist/a11y/score.js.map +1 -0
  37. package/dist/a11y/severity.d.ts +4 -0
  38. package/dist/a11y/severity.d.ts.map +1 -0
  39. package/dist/a11y/severity.js +13 -0
  40. package/dist/a11y/severity.js.map +1 -0
  41. package/dist/a11y/types.d.ts +48 -0
  42. package/dist/a11y/types.d.ts.map +1 -0
  43. package/dist/a11y/types.js +2 -0
  44. package/dist/a11y/types.js.map +1 -0
  45. package/dist/autopilot/explorer.d.ts +15 -0
  46. package/dist/autopilot/explorer.d.ts.map +1 -0
  47. package/dist/autopilot/explorer.js +276 -0
  48. package/dist/autopilot/explorer.js.map +1 -0
  49. package/dist/autopilot/generator.d.ts +12 -0
  50. package/dist/autopilot/generator.d.ts.map +1 -0
  51. package/dist/autopilot/generator.js +101 -0
  52. package/dist/autopilot/generator.js.map +1 -0
  53. package/dist/autopilot/healer.d.ts +17 -0
  54. package/dist/autopilot/healer.d.ts.map +1 -0
  55. package/dist/autopilot/healer.js +142 -0
  56. package/dist/autopilot/healer.js.map +1 -0
  57. package/dist/autopilot/nav-graph.d.ts +26 -0
  58. package/dist/autopilot/nav-graph.d.ts.map +1 -0
  59. package/dist/autopilot/nav-graph.js +101 -0
  60. package/dist/autopilot/nav-graph.js.map +1 -0
  61. package/dist/autopilot/screen-fingerprint.d.ts +20 -0
  62. package/dist/autopilot/screen-fingerprint.d.ts.map +1 -0
  63. package/dist/autopilot/screen-fingerprint.js +36 -0
  64. package/dist/autopilot/screen-fingerprint.js.map +1 -0
  65. package/dist/autopilot/types.d.ts +109 -0
  66. package/dist/autopilot/types.d.ts.map +1 -0
  67. package/dist/autopilot/types.js +14 -0
  68. package/dist/autopilot/types.js.map +1 -0
  69. package/dist/device-manager.d.ts +8 -6
  70. package/dist/device-manager.d.ts.map +1 -1
  71. package/dist/device-manager.js +87 -38
  72. package/dist/device-manager.js.map +1 -1
  73. package/dist/errors.d.ts +27 -0
  74. package/dist/errors.d.ts.map +1 -1
  75. package/dist/errors.js +48 -0
  76. package/dist/errors.js.map +1 -1
  77. package/dist/index.js +26 -1
  78. package/dist/index.js.map +1 -1
  79. package/dist/perf/collector.d.ts +45 -0
  80. package/dist/perf/collector.d.ts.map +1 -0
  81. package/dist/perf/collector.js +295 -0
  82. package/dist/perf/collector.js.map +1 -0
  83. package/dist/perf/formatter.d.ts +22 -0
  84. package/dist/perf/formatter.d.ts.map +1 -0
  85. package/dist/perf/formatter.js +116 -0
  86. package/dist/perf/formatter.js.map +1 -0
  87. package/dist/perf/types.d.ts +72 -0
  88. package/dist/perf/types.d.ts.map +1 -0
  89. package/dist/perf/types.js +5 -0
  90. package/dist/perf/types.js.map +1 -0
  91. package/dist/tools/accessibility-tools.d.ts +3 -0
  92. package/dist/tools/accessibility-tools.d.ts.map +1 -0
  93. package/dist/tools/accessibility-tools.js +256 -0
  94. package/dist/tools/accessibility-tools.js.map +1 -0
  95. package/dist/tools/autopilot-tools.d.ts +13 -0
  96. package/dist/tools/autopilot-tools.d.ts.map +1 -0
  97. package/dist/tools/autopilot-tools.js +353 -0
  98. package/dist/tools/autopilot-tools.js.map +1 -0
  99. package/dist/tools/context.d.ts.map +1 -1
  100. package/dist/tools/context.js +2 -2
  101. package/dist/tools/context.js.map +1 -1
  102. package/dist/tools/meta/accessibility-meta.d.ts +6 -0
  103. package/dist/tools/meta/accessibility-meta.d.ts.map +1 -0
  104. package/dist/tools/meta/accessibility-meta.js +48 -0
  105. package/dist/tools/meta/accessibility-meta.js.map +1 -0
  106. package/dist/tools/meta/autopilot-meta.d.ts +6 -0
  107. package/dist/tools/meta/autopilot-meta.d.ts.map +1 -0
  108. package/dist/tools/meta/autopilot-meta.js +60 -0
  109. package/dist/tools/meta/autopilot-meta.js.map +1 -0
  110. package/dist/tools/meta/performance-meta.d.ts +6 -0
  111. package/dist/tools/meta/performance-meta.d.ts.map +1 -0
  112. package/dist/tools/meta/performance-meta.js +54 -0
  113. package/dist/tools/meta/performance-meta.js.map +1 -0
  114. package/dist/tools/performance-tools.d.ts +13 -0
  115. package/dist/tools/performance-tools.d.ts.map +1 -0
  116. package/dist/tools/performance-tools.js +397 -0
  117. package/dist/tools/performance-tools.js.map +1 -0
  118. package/dist/utils/exploration-store.d.ts +24 -0
  119. package/dist/utils/exploration-store.d.ts.map +1 -0
  120. package/dist/utils/exploration-store.js +133 -0
  121. package/dist/utils/exploration-store.js.map +1 -0
  122. package/dist/utils/perf-baseline-store.d.ts +29 -0
  123. package/dist/utils/perf-baseline-store.d.ts.map +1 -0
  124. package/dist/utils/perf-baseline-store.js +149 -0
  125. package/dist/utils/perf-baseline-store.js.map +1 -0
  126. package/package.json +52 -1
@@ -0,0 +1,36 @@
1
+ import type { A11yReport, A11ySeverity } from "./types.js";
2
+ /**
3
+ * Format an accessibility report as text for LLM consumption.
4
+ * Follows the PASS/FAIL pattern from visual-tools.
5
+ */
6
+ export declare function formatAuditReport(report: A11yReport, options?: {
7
+ compact?: boolean;
8
+ passwordIndices?: Set<number>;
9
+ }): string;
10
+ /**
11
+ * Format a summary-only report (score + counts, no individual issues).
12
+ */
13
+ export declare function formatAuditSummary(report: A11yReport): string;
14
+ /**
15
+ * Format a list of all rules.
16
+ */
17
+ export declare function formatRuleList(rules: Array<{
18
+ id: string;
19
+ name: string;
20
+ wcag: string;
21
+ severity: A11ySeverity;
22
+ description: string;
23
+ platforms: string[];
24
+ }>): string;
25
+ /**
26
+ * Format details of a single rule.
27
+ */
28
+ export declare function formatRuleDetail(rule: {
29
+ id: string;
30
+ name: string;
31
+ wcag: string;
32
+ severity: A11ySeverity;
33
+ description: string;
34
+ platforms: string[];
35
+ }): string;
36
+ //# sourceMappingURL=formatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../src/a11y/formatter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAa,YAAY,EAAE,MAAM,YAAY,CAAC;AAoDtE;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,UAAU,EAClB,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAAE,GAC7D,MAAM,CAgER;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAW7D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,YAAY,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,GACzH,MAAM,CAWR;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,YAAY,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB,GAAG,MAAM,CAST"}
@@ -0,0 +1,134 @@
1
+ import { SEVERITY_ORDER } from "./severity.js";
2
+ function shortClassName(className) {
3
+ return className.split(".").pop() ?? className;
4
+ }
5
+ function shortResourceId(resourceId) {
6
+ if (!resourceId)
7
+ return "";
8
+ return resourceId.split(":id/").pop() ?? resourceId;
9
+ }
10
+ function formatElementRef(issue, redactPasswords) {
11
+ const el = issue.element;
12
+ const shortClass = shortClassName(el.className);
13
+ const parts = [`<${shortClass}>`];
14
+ const shortId = shortResourceId(el.resourceId);
15
+ if (shortId) {
16
+ parts.push(`id="${shortId}"`);
17
+ }
18
+ parts.push(`@ (${el.centerX}, ${el.centerY})`);
19
+ if (redactPasswords.has(el.index)) {
20
+ parts.push("text=[REDACTED]");
21
+ }
22
+ return parts.join(" ");
23
+ }
24
+ function formatIssueFull(issue, num, redactPasswords) {
25
+ const ref = formatElementRef(issue, redactPasswords);
26
+ return [
27
+ ` [${num}] ${issue.ruleId} (WCAG ${issue.wcag}) — ${ref}`,
28
+ ` ${issue.message}`,
29
+ ].join("\n");
30
+ }
31
+ function formatIssueCompact(issue, num, redactPasswords) {
32
+ const ref = formatElementRef(issue, redactPasswords);
33
+ return ` [${num}] ${issue.ruleId} (${issue.wcag}) — ${ref}`;
34
+ }
35
+ /**
36
+ * Format an accessibility report as text for LLM consumption.
37
+ * Follows the PASS/FAIL pattern from visual-tools.
38
+ */
39
+ export function formatAuditReport(report, options) {
40
+ const compact = options?.compact === true;
41
+ const passwordIndices = options?.passwordIndices ?? new Set();
42
+ const hasCritical = report.issueCount.critical > 0;
43
+ const isPassing = report.score >= 100 && !hasCritical;
44
+ const status = isPassing ? "PASS" : "FAIL";
45
+ const header = `A11Y AUDIT: ${status} (score: ${report.score}/100)`;
46
+ const meta = `Platform: ${report.platform} | Elements: ${report.totalElements} | Standard: ${report.standard}`;
47
+ const counts = `Issues: ${report.issueCount.critical} critical, ${report.issueCount.serious} serious, ` +
48
+ `${report.issueCount.moderate} moderate, ${report.issueCount.minor} minor (${report.issueCount.total} total)`;
49
+ const lines = [header, meta, counts];
50
+ if (report.issues.length > 0) {
51
+ // Sort issues by severity
52
+ const sorted = [...report.issues].sort((a, b) => SEVERITY_ORDER[a.severity] - SEVERITY_ORDER[b.severity]);
53
+ // Group by severity
54
+ const groups = new Map();
55
+ for (const issue of sorted) {
56
+ const existing = groups.get(issue.severity);
57
+ if (existing) {
58
+ existing.push(issue);
59
+ }
60
+ else {
61
+ groups.set(issue.severity, [issue]);
62
+ }
63
+ }
64
+ let issueNum = 1;
65
+ const severityLabels = [
66
+ ["critical", "CRITICAL"],
67
+ ["serious", "SERIOUS"],
68
+ ["moderate", "MODERATE"],
69
+ ["minor", "MINOR"],
70
+ ];
71
+ for (const [sev, label] of severityLabels) {
72
+ const groupIssues = groups.get(sev);
73
+ if (!groupIssues || groupIssues.length === 0)
74
+ continue;
75
+ lines.push("");
76
+ lines.push(`${label}:`);
77
+ for (const issue of groupIssues) {
78
+ if (compact) {
79
+ lines.push(formatIssueCompact(issue, issueNum, passwordIndices));
80
+ }
81
+ else {
82
+ lines.push(formatIssueFull(issue, issueNum, passwordIndices));
83
+ }
84
+ issueNum++;
85
+ }
86
+ }
87
+ }
88
+ if (report.passedRules.length > 0) {
89
+ lines.push("");
90
+ lines.push(`Passed rules: ${report.passedRules.join(", ")}`);
91
+ }
92
+ return lines.join("\n");
93
+ }
94
+ /**
95
+ * Format a summary-only report (score + counts, no individual issues).
96
+ */
97
+ export function formatAuditSummary(report) {
98
+ const hasCritical = report.issueCount.critical > 0;
99
+ const isPassing = report.score >= 100 && !hasCritical;
100
+ const status = isPassing ? "PASS" : "FAIL";
101
+ return [
102
+ `A11Y: ${status} (score: ${report.score}/100)`,
103
+ `Platform: ${report.platform} | Elements: ${report.totalElements} | Standard: ${report.standard}`,
104
+ `Issues: ${report.issueCount.critical} critical, ${report.issueCount.serious} serious, ${report.issueCount.moderate} moderate, ${report.issueCount.minor} minor (${report.issueCount.total} total)`,
105
+ `Passed: ${report.passedRules.length} rules`,
106
+ ].join("\n");
107
+ }
108
+ /**
109
+ * Format a list of all rules.
110
+ */
111
+ export function formatRuleList(rules) {
112
+ const lines = [`Accessibility rules: ${rules.length} total`, ""];
113
+ for (const rule of rules) {
114
+ lines.push(` ${rule.id} (WCAG ${rule.wcag}, ${rule.severity})`);
115
+ lines.push(` ${rule.description}`);
116
+ lines.push(` Platforms: ${rule.platforms.join(", ")}`);
117
+ lines.push("");
118
+ }
119
+ return lines.join("\n").trimEnd();
120
+ }
121
+ /**
122
+ * Format details of a single rule.
123
+ */
124
+ export function formatRuleDetail(rule) {
125
+ return [
126
+ `Rule: ${rule.id}`,
127
+ `Name: ${rule.name}`,
128
+ `WCAG: ${rule.wcag}`,
129
+ `Severity: ${rule.severity}`,
130
+ `Description: ${rule.description}`,
131
+ `Platforms: ${rule.platforms.join(", ")}`,
132
+ ].join("\n");
133
+ }
134
+ //# sourceMappingURL=formatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter.js","sourceRoot":"","sources":["../../src/a11y/formatter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { A11yRule } from "../types.js";
2
+ export declare const duplicateDescriptionsRule: A11yRule;
3
+ //# sourceMappingURL=duplicate-descriptions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duplicate-descriptions.d.ts","sourceRoot":"","sources":["../../../src/a11y/rules/duplicate-descriptions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAa,MAAM,aAAa,CAAC;AAEvD,eAAO,MAAM,yBAAyB,EAAE,QAmDvC,CAAC"}
@@ -0,0 +1,50 @@
1
+ export const duplicateDescriptionsRule = {
2
+ id: "duplicate-descriptions",
3
+ name: "Duplicate Descriptions",
4
+ wcag: "1.3.1",
5
+ severity: "moderate",
6
+ description: "Multiple elements with identical content descriptions confuse screen reader users.",
7
+ platforms: ["android", "ios", "desktop"],
8
+ run(elements) {
9
+ // Group by non-empty contentDesc, exclude short (<=1 char) descriptions
10
+ const groups = new Map();
11
+ for (const el of elements) {
12
+ const desc = el.contentDesc.trim();
13
+ if (desc.length <= 1)
14
+ continue;
15
+ if (el.width <= 0 || el.height <= 0)
16
+ continue;
17
+ const existing = groups.get(desc);
18
+ if (existing) {
19
+ existing.push(el);
20
+ }
21
+ else {
22
+ groups.set(desc, [el]);
23
+ }
24
+ }
25
+ const issues = [];
26
+ for (const [desc, els] of groups) {
27
+ if (els.length <= 1)
28
+ continue;
29
+ // Report each duplicate element
30
+ for (const el of els) {
31
+ issues.push({
32
+ ruleId: "duplicate-descriptions",
33
+ wcag: "1.3.1",
34
+ severity: "moderate",
35
+ message: `Duplicate content description "${desc}" shared by ${els.length} elements`,
36
+ element: {
37
+ index: el.index,
38
+ className: el.className,
39
+ resourceId: el.resourceId,
40
+ bounds: el.bounds,
41
+ centerX: el.centerX,
42
+ centerY: el.centerY,
43
+ },
44
+ });
45
+ }
46
+ }
47
+ return issues;
48
+ },
49
+ };
50
+ //# sourceMappingURL=duplicate-descriptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duplicate-descriptions.js","sourceRoot":"","sources":["../../../src/a11y/rules/duplicate-descriptions.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,yBAAyB,GAAa;IACjD,EAAE,EAAE,wBAAwB;IAC5B,IAAI,EAAE,wBAAwB;IAC9B,IAAI,EAAE,OAAO;IACb,QAAQ,EAAE,UAAU;IACpB,WAAW,EACT,oFAAoF;IACtF,SAAS,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,SAAS,CAAC;IACxC,GAAG,CAAC,QAAqB;QACvB,wEAAwE;QACxE,MAAM,MAAM,GAAG,IAAI,GAAG,EAAuB,CAAC;QAE9C,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;YAC1B,MAAM,IAAI,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;YACnC,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC;gBAAE,SAAS;YAC/B,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,IAAI,CAAC;gBAAE,SAAS;YAE9C,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAClC,IAAI,QAAQ,EAAE,CAAC;gBACb,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACpB,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAgB,EAAE,CAAC;QAE/B,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,EAAE,CAAC;YACjC,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC;gBAAE,SAAS;YAE9B,gCAAgC;YAChC,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;gBACrB,MAAM,CAAC,IAAI,CAAC;oBACV,MAAM,EAAE,wBAAwB;oBAChC,IAAI,EAAE,OAAO;oBACb,QAAQ,EAAE,UAAU;oBACpB,OAAO,EAAE,kCAAkC,IAAI,eAAe,GAAG,CAAC,MAAM,WAAW;oBACnF,OAAO,EAAE;wBACP,KAAK,EAAE,EAAE,CAAC,KAAK;wBACf,SAAS,EAAE,EAAE,CAAC,SAAS;wBACvB,UAAU,EAAE,EAAE,CAAC,UAAU;wBACzB,MAAM,EAAE,EAAE,CAAC,MAAM;wBACjB,OAAO,EAAE,EAAE,CAAC,OAAO;wBACnB,OAAO,EAAE,EAAE,CAAC,OAAO;qBACpB;iBACF,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { A11yRule } from "../types.js";
2
+ export declare const focusOrderRule: A11yRule;
3
+ //# sourceMappingURL=focus-order.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"focus-order.d.ts","sourceRoot":"","sources":["../../../src/a11y/rules/focus-order.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAa,MAAM,aAAa,CAAC;AAEvD,eAAO,MAAM,cAAc,EAAE,QAmC5B,CAAC"}
@@ -0,0 +1,35 @@
1
+ export const focusOrderRule = {
2
+ id: "focus-order",
3
+ name: "Focus Order",
4
+ wcag: "2.1.1",
5
+ severity: "serious",
6
+ description: "Clickable elements should be focusable so they can be reached via keyboard or switch navigation.",
7
+ platforms: ["android", "ios", "desktop"],
8
+ run(elements) {
9
+ const issues = [];
10
+ for (const el of elements) {
11
+ if (!el.clickable)
12
+ continue;
13
+ if (el.width <= 0 || el.height <= 0)
14
+ continue;
15
+ if (!el.focusable) {
16
+ issues.push({
17
+ ruleId: "focus-order",
18
+ wcag: "2.1.1",
19
+ severity: "serious",
20
+ message: "Clickable element is not focusable for keyboard/switch navigation",
21
+ element: {
22
+ index: el.index,
23
+ className: el.className,
24
+ resourceId: el.resourceId,
25
+ bounds: el.bounds,
26
+ centerX: el.centerX,
27
+ centerY: el.centerY,
28
+ },
29
+ });
30
+ }
31
+ }
32
+ return issues;
33
+ },
34
+ };
35
+ //# sourceMappingURL=focus-order.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"focus-order.js","sourceRoot":"","sources":["../../../src/a11y/rules/focus-order.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,cAAc,GAAa;IACtC,EAAE,EAAE,aAAa;IACjB,IAAI,EAAE,aAAa;IACnB,IAAI,EAAE,OAAO;IACb,QAAQ,EAAE,SAAS;IACnB,WAAW,EACT,kGAAkG;IACpG,SAAS,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,SAAS,CAAC;IACxC,GAAG,CAAC,QAAqB;QACvB,MAAM,MAAM,GAAgB,EAAE,CAAC;QAE/B,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;YAC1B,IAAI,CAAC,EAAE,CAAC,SAAS;gBAAE,SAAS;YAC5B,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,IAAI,CAAC;gBAAE,SAAS;YAE9C,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC;gBAClB,MAAM,CAAC,IAAI,CAAC;oBACV,MAAM,EAAE,aAAa;oBACrB,IAAI,EAAE,OAAO;oBACb,QAAQ,EAAE,SAAS;oBACnB,OAAO,EAAE,mEAAmE;oBAC5E,OAAO,EAAE;wBACP,KAAK,EAAE,EAAE,CAAC,KAAK;wBACf,SAAS,EAAE,EAAE,CAAC,SAAS;wBACvB,UAAU,EAAE,EAAE,CAAC,UAAU;wBACzB,MAAM,EAAE,EAAE,CAAC,MAAM;wBACjB,OAAO,EAAE,EAAE,CAAC,OAAO;wBACnB,OAAO,EAAE,EAAE,CAAC,OAAO;qBACpB;iBACF,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { A11yRule } from "../types.js";
2
+ export declare const ALL_RULES: A11yRule[];
3
+ export declare function getRuleById(id: string): A11yRule | undefined;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/a11y/rules/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAQ5C,eAAO,MAAM,SAAS,EAAE,QAAQ,EAO/B,CAAC;AAMF,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAE5D"}
@@ -0,0 +1,19 @@
1
+ import { missingLabelRule } from "./missing-label.js";
2
+ import { touchTargetRule } from "./touch-target.js";
3
+ import { interactiveLabelsRule } from "./interactive-labels.js";
4
+ import { focusOrderRule } from "./focus-order.js";
5
+ import { duplicateDescriptionsRule } from "./duplicate-descriptions.js";
6
+ import { stateDescriptionRule } from "./state-description.js";
7
+ export const ALL_RULES = [
8
+ missingLabelRule,
9
+ touchTargetRule,
10
+ interactiveLabelsRule,
11
+ focusOrderRule,
12
+ duplicateDescriptionsRule,
13
+ stateDescriptionRule,
14
+ ];
15
+ const ruleMap = new Map(ALL_RULES.map((r) => [r.id, r]));
16
+ export function getRuleById(id) {
17
+ return ruleMap.get(id);
18
+ }
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/a11y/rules/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,MAAM,CAAC,MAAM,SAAS,GAAe;IACnC,gBAAgB;IAChB,eAAe;IACf,qBAAqB;IACrB,cAAc;IACd,yBAAyB;IACzB,oBAAoB;CACrB,CAAC;AAEF,MAAM,OAAO,GAAG,IAAI,GAAG,CACrB,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAChC,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,EAAU;IACpC,OAAO,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AACzB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { A11yRule } from "../types.js";
2
+ export declare const interactiveLabelsRule: A11yRule;
3
+ //# sourceMappingURL=interactive-labels.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive-labels.d.ts","sourceRoot":"","sources":["../../../src/a11y/rules/interactive-labels.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAa,MAAM,aAAa,CAAC;AAEvD,eAAO,MAAM,qBAAqB,EAAE,QAyCnC,CAAC"}
@@ -0,0 +1,39 @@
1
+ export const interactiveLabelsRule = {
2
+ id: "interactive-labels",
3
+ name: "Interactive Image Labels",
4
+ wcag: "4.1.2",
5
+ severity: "critical",
6
+ description: "Clickable ImageView and ImageButton elements must have a content description.",
7
+ platforms: ["android", "ios", "desktop"],
8
+ run(elements) {
9
+ const issues = [];
10
+ for (const el of elements) {
11
+ if (!el.clickable)
12
+ continue;
13
+ if (el.width <= 0 || el.height <= 0)
14
+ continue;
15
+ const isImage = el.className.includes("ImageView") ||
16
+ el.className.includes("ImageButton");
17
+ if (!isImage)
18
+ continue;
19
+ if (el.contentDesc.trim().length === 0) {
20
+ issues.push({
21
+ ruleId: "interactive-labels",
22
+ wcag: "4.1.2",
23
+ severity: "critical",
24
+ message: "Clickable image element has no content description for screen readers",
25
+ element: {
26
+ index: el.index,
27
+ className: el.className,
28
+ resourceId: el.resourceId,
29
+ bounds: el.bounds,
30
+ centerX: el.centerX,
31
+ centerY: el.centerY,
32
+ },
33
+ });
34
+ }
35
+ }
36
+ return issues;
37
+ },
38
+ };
39
+ //# sourceMappingURL=interactive-labels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive-labels.js","sourceRoot":"","sources":["../../../src/a11y/rules/interactive-labels.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,qBAAqB,GAAa;IAC7C,EAAE,EAAE,oBAAoB;IACxB,IAAI,EAAE,0BAA0B;IAChC,IAAI,EAAE,OAAO;IACb,QAAQ,EAAE,UAAU;IACpB,WAAW,EACT,+EAA+E;IACjF,SAAS,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,SAAS,CAAC;IACxC,GAAG,CAAC,QAAqB;QACvB,MAAM,MAAM,GAAgB,EAAE,CAAC;QAE/B,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;YAC1B,IAAI,CAAC,EAAE,CAAC,SAAS;gBAAE,SAAS;YAC5B,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,IAAI,CAAC;gBAAE,SAAS;YAE9C,MAAM,OAAO,GACX,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC;gBAClC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;YACvC,IAAI,CAAC,OAAO;gBAAE,SAAS;YAEvB,IAAI,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvC,MAAM,CAAC,IAAI,CAAC;oBACV,MAAM,EAAE,oBAAoB;oBAC5B,IAAI,EAAE,OAAO;oBACb,QAAQ,EAAE,UAAU;oBACpB,OAAO,EACL,uEAAuE;oBACzE,OAAO,EAAE;wBACP,KAAK,EAAE,EAAE,CAAC,KAAK;wBACf,SAAS,EAAE,EAAE,CAAC,SAAS;wBACvB,UAAU,EAAE,EAAE,CAAC,UAAU;wBACzB,MAAM,EAAE,EAAE,CAAC,MAAM;wBACjB,OAAO,EAAE,EAAE,CAAC,OAAO;wBACnB,OAAO,EAAE,EAAE,CAAC,OAAO;qBACpB;iBACF,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { A11yRule } from "../types.js";
2
+ export declare const missingLabelRule: A11yRule;
3
+ //# sourceMappingURL=missing-label.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"missing-label.d.ts","sourceRoot":"","sources":["../../../src/a11y/rules/missing-label.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAa,MAAM,aAAa,CAAC;AAQvD,eAAO,MAAM,gBAAgB,EAAE,QA8D9B,CAAC"}
@@ -0,0 +1,64 @@
1
+ const CONTAINER_PATTERNS = ["Layout", "ViewGroup", "ScrollView"];
2
+ function isContainer(className) {
3
+ return CONTAINER_PATTERNS.some((p) => className.includes(p));
4
+ }
5
+ export const missingLabelRule = {
6
+ id: "missing-label",
7
+ name: "Missing Label",
8
+ wcag: "1.1.1",
9
+ severity: "critical",
10
+ description: "Clickable elements must have a text label or content description for screen readers.",
11
+ platforms: ["android", "ios", "desktop"],
12
+ run(elements) {
13
+ const issues = [];
14
+ for (const el of elements) {
15
+ if (!el.clickable)
16
+ continue;
17
+ if (isContainer(el.className))
18
+ continue;
19
+ // Invisible elements are skipped
20
+ if (el.width <= 0 || el.height <= 0)
21
+ continue;
22
+ const hasContentDesc = el.contentDesc.trim().length > 0;
23
+ const hasText = el.text.trim().length > 0;
24
+ // Password elements: contentDesc still required, but missing text is ok
25
+ if (el.password) {
26
+ if (!hasContentDesc) {
27
+ issues.push({
28
+ ruleId: "missing-label",
29
+ wcag: "1.1.1",
30
+ severity: "critical",
31
+ message: "Password field has no content description for screen readers",
32
+ element: {
33
+ index: el.index,
34
+ className: el.className,
35
+ resourceId: el.resourceId,
36
+ bounds: el.bounds,
37
+ centerX: el.centerX,
38
+ centerY: el.centerY,
39
+ },
40
+ });
41
+ }
42
+ continue;
43
+ }
44
+ if (!hasText && !hasContentDesc) {
45
+ issues.push({
46
+ ruleId: "missing-label",
47
+ wcag: "1.1.1",
48
+ severity: "critical",
49
+ message: "Clickable element has no text or content description",
50
+ element: {
51
+ index: el.index,
52
+ className: el.className,
53
+ resourceId: el.resourceId,
54
+ bounds: el.bounds,
55
+ centerX: el.centerX,
56
+ centerY: el.centerY,
57
+ },
58
+ });
59
+ }
60
+ }
61
+ return issues;
62
+ },
63
+ };
64
+ //# sourceMappingURL=missing-label.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"missing-label.js","sourceRoot":"","sources":["../../../src/a11y/rules/missing-label.ts"],"names":[],"mappings":"AAGA,MAAM,kBAAkB,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,YAAY,CAAC,CAAC;AAEjE,SAAS,WAAW,CAAC,SAAiB;IACpC,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAa;IACxC,EAAE,EAAE,eAAe;IACnB,IAAI,EAAE,eAAe;IACrB,IAAI,EAAE,OAAO;IACb,QAAQ,EAAE,UAAU;IACpB,WAAW,EACT,sFAAsF;IACxF,SAAS,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,SAAS,CAAC;IACxC,GAAG,CAAC,QAAqB;QACvB,MAAM,MAAM,GAAgB,EAAE,CAAC;QAE/B,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;YAC1B,IAAI,CAAC,EAAE,CAAC,SAAS;gBAAE,SAAS;YAC5B,IAAI,WAAW,CAAC,EAAE,CAAC,SAAS,CAAC;gBAAE,SAAS;YACxC,iCAAiC;YACjC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,IAAI,CAAC;gBAAE,SAAS;YAE9C,MAAM,cAAc,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;YACxD,MAAM,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;YAE1C,wEAAwE;YACxE,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC;gBAChB,IAAI,CAAC,cAAc,EAAE,CAAC;oBACpB,MAAM,CAAC,IAAI,CAAC;wBACV,MAAM,EAAE,eAAe;wBACvB,IAAI,EAAE,OAAO;wBACb,QAAQ,EAAE,UAAU;wBACpB,OAAO,EACL,8DAA8D;wBAChE,OAAO,EAAE;4BACP,KAAK,EAAE,EAAE,CAAC,KAAK;4BACf,SAAS,EAAE,EAAE,CAAC,SAAS;4BACvB,UAAU,EAAE,EAAE,CAAC,UAAU;4BACzB,MAAM,EAAE,EAAE,CAAC,MAAM;4BACjB,OAAO,EAAE,EAAE,CAAC,OAAO;4BACnB,OAAO,EAAE,EAAE,CAAC,OAAO;yBACpB;qBACF,CAAC,CAAC;gBACL,CAAC;gBACD,SAAS;YACX,CAAC;YAED,IAAI,CAAC,OAAO,IAAI,CAAC,cAAc,EAAE,CAAC;gBAChC,MAAM,CAAC,IAAI,CAAC;oBACV,MAAM,EAAE,eAAe;oBACvB,IAAI,EAAE,OAAO;oBACb,QAAQ,EAAE,UAAU;oBACpB,OAAO,EAAE,sDAAsD;oBAC/D,OAAO,EAAE;wBACP,KAAK,EAAE,EAAE,CAAC,KAAK;wBACf,SAAS,EAAE,EAAE,CAAC,SAAS;wBACvB,UAAU,EAAE,EAAE,CAAC,UAAU;wBACzB,MAAM,EAAE,EAAE,CAAC,MAAM;wBACjB,OAAO,EAAE,EAAE,CAAC,OAAO;wBACnB,OAAO,EAAE,EAAE,CAAC,OAAO;qBACpB;iBACF,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { A11yRule } from "../types.js";
2
+ export declare const stateDescriptionRule: A11yRule;
3
+ //# sourceMappingURL=state-description.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-description.d.ts","sourceRoot":"","sources":["../../../src/a11y/rules/state-description.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAa,MAAM,aAAa,CAAC;AAEvD,eAAO,MAAM,oBAAoB,EAAE,QAuClC,CAAC"}
@@ -0,0 +1,37 @@
1
+ export const stateDescriptionRule = {
2
+ id: "state-description",
3
+ name: "State Description",
4
+ wcag: "4.1.2",
5
+ severity: "moderate",
6
+ description: "Checkable elements (checkboxes, switches, toggles) must have a text label or content description.",
7
+ platforms: ["android", "ios", "desktop"],
8
+ run(elements) {
9
+ const issues = [];
10
+ for (const el of elements) {
11
+ if (!el.checkable)
12
+ continue;
13
+ if (el.width <= 0 || el.height <= 0)
14
+ continue;
15
+ const hasText = el.text.trim().length > 0;
16
+ const hasContentDesc = el.contentDesc.trim().length > 0;
17
+ if (!hasText && !hasContentDesc) {
18
+ issues.push({
19
+ ruleId: "state-description",
20
+ wcag: "4.1.2",
21
+ severity: "moderate",
22
+ message: "Checkable element has no text or content description to convey its purpose",
23
+ element: {
24
+ index: el.index,
25
+ className: el.className,
26
+ resourceId: el.resourceId,
27
+ bounds: el.bounds,
28
+ centerX: el.centerX,
29
+ centerY: el.centerY,
30
+ },
31
+ });
32
+ }
33
+ }
34
+ return issues;
35
+ },
36
+ };
37
+ //# sourceMappingURL=state-description.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-description.js","sourceRoot":"","sources":["../../../src/a11y/rules/state-description.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,oBAAoB,GAAa;IAC5C,EAAE,EAAE,mBAAmB;IACvB,IAAI,EAAE,mBAAmB;IACzB,IAAI,EAAE,OAAO;IACb,QAAQ,EAAE,UAAU;IACpB,WAAW,EACT,mGAAmG;IACrG,SAAS,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,SAAS,CAAC;IACxC,GAAG,CAAC,QAAqB;QACvB,MAAM,MAAM,GAAgB,EAAE,CAAC;QAE/B,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;YAC1B,IAAI,CAAC,EAAE,CAAC,SAAS;gBAAE,SAAS;YAC5B,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,IAAI,CAAC;gBAAE,SAAS;YAE9C,MAAM,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;YAC1C,MAAM,cAAc,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;YAExD,IAAI,CAAC,OAAO,IAAI,CAAC,cAAc,EAAE,CAAC;gBAChC,MAAM,CAAC,IAAI,CAAC;oBACV,MAAM,EAAE,mBAAmB;oBAC3B,IAAI,EAAE,OAAO;oBACb,QAAQ,EAAE,UAAU;oBACpB,OAAO,EACL,4EAA4E;oBAC9E,OAAO,EAAE;wBACP,KAAK,EAAE,EAAE,CAAC,KAAK;wBACf,SAAS,EAAE,EAAE,CAAC,SAAS;wBACvB,UAAU,EAAE,EAAE,CAAC,UAAU;wBACzB,MAAM,EAAE,EAAE,CAAC,MAAM;wBACjB,OAAO,EAAE,EAAE,CAAC,OAAO;wBACnB,OAAO,EAAE,EAAE,CAAC,OAAO;qBACpB;iBACF,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { A11yRule } from "../types.js";
2
+ export declare const touchTargetRule: A11yRule;
3
+ //# sourceMappingURL=touch-target.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"touch-target.d.ts","sourceRoot":"","sources":["../../../src/a11y/rules/touch-target.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAa,MAAM,aAAa,CAAC;AAIvD,eAAO,MAAM,eAAe,EAAE,QAmC7B,CAAC"}
@@ -0,0 +1,37 @@
1
+ const MIN_TARGET_SIZE = 48;
2
+ export const touchTargetRule = {
3
+ id: "touch-target",
4
+ name: "Touch Target Size",
5
+ wcag: "2.5.8",
6
+ severity: "serious",
7
+ description: `Interactive elements must have a minimum touch target size of ${MIN_TARGET_SIZE}x${MIN_TARGET_SIZE}dp.`,
8
+ platforms: ["android", "ios", "desktop"],
9
+ run(elements) {
10
+ const issues = [];
11
+ for (const el of elements) {
12
+ if (!el.clickable)
13
+ continue;
14
+ // Skip invisible elements
15
+ if (el.width <= 0 || el.height <= 0)
16
+ continue;
17
+ if (el.width < MIN_TARGET_SIZE || el.height < MIN_TARGET_SIZE) {
18
+ issues.push({
19
+ ruleId: "touch-target",
20
+ wcag: "2.5.8",
21
+ severity: "serious",
22
+ message: `Touch target ${el.width}x${el.height} is smaller than minimum ${MIN_TARGET_SIZE}x${MIN_TARGET_SIZE}`,
23
+ element: {
24
+ index: el.index,
25
+ className: el.className,
26
+ resourceId: el.resourceId,
27
+ bounds: el.bounds,
28
+ centerX: el.centerX,
29
+ centerY: el.centerY,
30
+ },
31
+ });
32
+ }
33
+ }
34
+ return issues;
35
+ },
36
+ };
37
+ //# sourceMappingURL=touch-target.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"touch-target.js","sourceRoot":"","sources":["../../../src/a11y/rules/touch-target.ts"],"names":[],"mappings":"AAGA,MAAM,eAAe,GAAG,EAAE,CAAC;AAE3B,MAAM,CAAC,MAAM,eAAe,GAAa;IACvC,EAAE,EAAE,cAAc;IAClB,IAAI,EAAE,mBAAmB;IACzB,IAAI,EAAE,OAAO;IACb,QAAQ,EAAE,SAAS;IACnB,WAAW,EAAE,iEAAiE,eAAe,IAAI,eAAe,KAAK;IACrH,SAAS,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,SAAS,CAAC;IACxC,GAAG,CAAC,QAAqB;QACvB,MAAM,MAAM,GAAgB,EAAE,CAAC;QAE/B,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;YAC1B,IAAI,CAAC,EAAE,CAAC,SAAS;gBAAE,SAAS;YAC5B,0BAA0B;YAC1B,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,IAAI,CAAC;gBAAE,SAAS;YAE9C,IAAI,EAAE,CAAC,KAAK,GAAG,eAAe,IAAI,EAAE,CAAC,MAAM,GAAG,eAAe,EAAE,CAAC;gBAC9D,MAAM,CAAC,IAAI,CAAC;oBACV,MAAM,EAAE,cAAc;oBACtB,IAAI,EAAE,OAAO;oBACb,QAAQ,EAAE,SAAS;oBACnB,OAAO,EAAE,gBAAgB,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,MAAM,4BAA4B,eAAe,IAAI,eAAe,EAAE;oBAC9G,OAAO,EAAE;wBACP,KAAK,EAAE,EAAE,CAAC,KAAK;wBACf,SAAS,EAAE,EAAE,CAAC,SAAS;wBACvB,UAAU,EAAE,EAAE,CAAC,UAAU;wBACzB,MAAM,EAAE,EAAE,CAAC,MAAM;wBACjB,OAAO,EAAE,EAAE,CAAC,OAAO;wBACnB,OAAO,EAAE,EAAE,CAAC,OAAO;qBACpB;iBACF,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { A11yIssue } from "./types.js";
2
+ /**
3
+ * Calculate accessibility score from issues.
4
+ * Score = 100 - sum(severity weights), clamped to [0, 100].
5
+ */
6
+ export declare function calculateScore(issues: A11yIssue[]): number;
7
+ //# sourceMappingURL=score.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"score.d.ts","sourceRoot":"","sources":["../../src/a11y/score.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAG5C;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAM1D"}
@@ -0,0 +1,10 @@
1
+ import { SEVERITY_WEIGHTS } from "./severity.js";
2
+ /**
3
+ * Calculate accessibility score from issues.
4
+ * Score = 100 - sum(severity weights), clamped to [0, 100].
5
+ */
6
+ export function calculateScore(issues) {
7
+ const penalty = issues.reduce((sum, issue) => sum + (SEVERITY_WEIGHTS[issue.severity] ?? 0), 0);
8
+ return Math.max(0, Math.min(100, 100 - penalty));
9
+ }
10
+ //# sourceMappingURL=score.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"score.js","sourceRoot":"","sources":["../../src/a11y/score.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,MAAmB;IAChD,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAC3B,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,gBAAgB,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAC7D,CAAC,CACF,CAAC;IACF,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC;AACnD,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { A11ySeverity } from "./types.js";
2
+ export declare const SEVERITY_WEIGHTS: Record<A11ySeverity, number>;
3
+ export declare const SEVERITY_ORDER: Record<A11ySeverity, number>;
4
+ //# sourceMappingURL=severity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"severity.d.ts","sourceRoot":"","sources":["../../src/a11y/severity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAKzD,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAKvD,CAAC"}
@@ -0,0 +1,13 @@
1
+ export const SEVERITY_WEIGHTS = {
2
+ critical: 15,
3
+ serious: 8,
4
+ moderate: 3,
5
+ minor: 1,
6
+ };
7
+ export const SEVERITY_ORDER = {
8
+ critical: 0,
9
+ serious: 1,
10
+ moderate: 2,
11
+ minor: 3,
12
+ };
13
+ //# sourceMappingURL=severity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"severity.js","sourceRoot":"","sources":["../../src/a11y/severity.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,gBAAgB,GAAiC;IAC5D,QAAQ,EAAE,EAAE;IACZ,OAAO,EAAE,CAAC;IACV,QAAQ,EAAE,CAAC;IACX,KAAK,EAAE,CAAC;CACT,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAiC;IAC1D,QAAQ,EAAE,CAAC;IACX,OAAO,EAAE,CAAC;IACV,QAAQ,EAAE,CAAC;IACX,KAAK,EAAE,CAAC;CACT,CAAC"}