@webability/core 1.4.0 → 1.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.
@@ -25,7 +25,7 @@ interface PageLike {
25
25
  };
26
26
  }
27
27
  /** All fix issue types the pipeline can detect and fix. */
28
- type FixIssueType = 'weak_button_name' | 'weak_link_name' | 'weak_heading' | 'weak_iframe_title' | 'weak_page_title' | 'weak_svg_name' | 'weak_skip_link' | 'missing_button_role' | 'missing_semantic_role' | 'missing_landmark' | 'heading_skip' | 'svg_missing_name' | 'aria_hidden_focusable' | 'adjacent_redundant_link' | 'contrast_insufficient' | 'non_text_contrast_insufficient' | 'target_too_small' | 'focus_not_visible' | 'empty_link' | 'unlabeled_button' | 'missing_label' | 'decorative_icon' | 'skip_link' | 'aria_live' | 'missing_alt' | 'identify_input_purpose' | 'redundant_role' | 'duplicate_id' | 'new_window_link' | 'missing_fieldset_legend' | 'missing_table_header' | 'missing_table_caption' | 'missing_table_scope' | 'external_link_warning' | 'download_link_warning' | 'broken_anchor' | 'placeholder_link' | 'missing_aria_required' | 'missing_pattern_title' | 'missing_autocomplete' | 'missing_media_controls' | 'unsafe_autoplay' | 'invalid_aria_role' | 'zoom_restriction' | 'missing_button_type' | 'link_consistency' | 'semantic_emphasis' | 'keyboard_trap' | 'focus_order_disruption' | 'missing_captions' | 'color_only_link' | 'label_in_name' | 'onfocus_context_change' | 'focus_obscured_by_sticky' | 'text_spacing_blocked' | 'nested_landmark' | 'combobox_name_missing' | 'landmark_duplicate_unlabeled' | 'motion_uncontrollable' | 'auto_refresh' | 'motion_without_reduced_motion' | 'flashing_content' | 'animated_gif_no_pause' | 'missing_required_indicator' | 'background_image_unlabeled' | 'missing_h1' | 'multiple_h1' | 'empty_heading' | 'javascript_link' | 'broken_aria_reference' | 'main_content_hidden' | 'scrollable_not_focusable' | 'meaningful_sequence' | 'sensory_characteristic' | 'orientation_lock' | 'image_of_text' | 'reflow_overflow' | 'missing_audio_description' | 'missing_transcript' | 'character_key_shortcut' | 'on_input_change' | 'pointer_gesture' | 'pointer_cancellation' | 'motion_actuation' | 'error_prevention_missing' | 'insufficient_navigation' | 'inconsistent_navigation';
28
+ type FixIssueType = 'weak_button_name' | 'weak_link_name' | 'weak_heading' | 'weak_iframe_title' | 'weak_page_title' | 'weak_svg_name' | 'weak_skip_link' | 'missing_button_role' | 'missing_semantic_role' | 'missing_landmark' | 'heading_skip' | 'svg_missing_name' | 'aria_hidden_focusable' | 'adjacent_redundant_link' | 'contrast_insufficient' | 'non_text_contrast_insufficient' | 'target_too_small' | 'focus_not_visible' | 'empty_link' | 'unlabeled_button' | 'missing_label' | 'decorative_icon' | 'skip_link' | 'aria_live' | 'missing_alt' | 'identify_input_purpose' | 'redundant_role' | 'duplicate_id' | 'new_window_link' | 'missing_fieldset_legend' | 'missing_table_header' | 'missing_table_caption' | 'missing_table_scope' | 'external_link_warning' | 'download_link_warning' | 'broken_anchor' | 'placeholder_link' | 'missing_pattern_title' | 'missing_autocomplete' | 'missing_media_controls' | 'unsafe_autoplay' | 'invalid_aria_role' | 'zoom_restriction' | 'missing_button_type' | 'link_consistency' | 'semantic_emphasis' | 'keyboard_trap' | 'focus_order_disruption' | 'missing_captions' | 'color_only_link' | 'label_in_name' | 'onfocus_context_change' | 'focus_obscured_by_sticky' | 'text_spacing_blocked' | 'nested_landmark' | 'combobox_name_missing' | 'landmark_duplicate_unlabeled' | 'motion_uncontrollable' | 'auto_refresh' | 'motion_without_reduced_motion' | 'flashing_content' | 'animated_gif_no_pause' | 'missing_required_indicator' | 'background_image_unlabeled' | 'missing_h1' | 'multiple_h1' | 'empty_heading' | 'javascript_link' | 'broken_aria_reference' | 'main_content_hidden' | 'scrollable_not_focusable' | 'meaningful_sequence' | 'sensory_characteristic' | 'orientation_lock' | 'image_of_text' | 'reflow_overflow' | 'missing_audio_description' | 'missing_transcript' | 'character_key_shortcut' | 'on_input_change' | 'pointer_gesture' | 'pointer_cancellation' | 'motion_actuation' | 'error_prevention_missing' | 'insufficient_navigation' | 'inconsistent_navigation';
29
29
  /** WCAG criterion for each issue type. */
30
30
  declare const WCAG_BY_ISSUE: Record<FixIssueType, string>;
31
31
  /** A single accessibility issue detected on the page. */
@@ -51,12 +51,17 @@ interface DetectedIssue {
51
51
  /** Optional: outer HTML snippet (first 300 chars) for Claude context. */
52
52
  outerHtml?: string;
53
53
  /**
54
- * Detector-side signal that the finding is ambiguous and should land in
55
- * `ScanResult.incomplete[]` (e.g. contrast against a gradient). The scanner
56
- * propagates this to ScanIssue.confidence so the confidence classifier
57
- * doesn't have to reverse-engineer the situation from HTML strings.
54
+ * Detector-side signal that the VERDICT is uncertain (e.g. contrast against
55
+ * a gradient). The scanner never reports such a finding: it is resolved to a
56
+ * verdict by an engine resolver or dropped. For "verdict certain, fix not
57
+ * mechanical" use `manualFix`.
58
58
  */
59
59
  needsReview?: boolean;
60
+ /**
61
+ * The verdict is certain but the suggested fix cannot be applied
62
+ * mechanically. Sets `fix.needsManualReview`; never changes the verdict.
63
+ */
64
+ manualFix?: boolean;
60
65
  /** Why this finding needs review — surfaced to MCP/SDK consumers. */
61
66
  reviewReason?: string;
62
67
  /**
@@ -182,9 +187,9 @@ interface ScanResult {
182
187
  /** Engine (core package) version that produced this result — provenance */
183
188
  engine?: string;
184
189
  /**
185
- * Findings the classifier or axe-core flagged as ambiguous. Show to the user
186
- * for review — never auto-fix. Empty array (not omitted) when no incompletes,
187
- * so consumers can rely on the field.
190
+ * @deprecated Always `[]`. The scanner judges uncertain findings itself:
191
+ * each becomes a verdict in `issues` or is dropped. The field stays only so
192
+ * existing consumers that read it keep compiling.
188
193
  */
189
194
  incomplete: ScanIssue[];
190
195
  summary: {
@@ -193,7 +198,7 @@ interface ScanResult {
193
198
  serious: number;
194
199
  moderate: number;
195
200
  minor: number;
196
- /** Count of items in `incomplete[]`. */
201
+ /** @deprecated Always 0 — there is no incomplete bucket. */
197
202
  incomplete: number;
198
203
  };
199
204
  axeResults?: unknown;
@@ -205,6 +210,12 @@ declare const VIEWPORT_SIZES: Record<ViewportPreset, {
205
210
  }>;
206
211
  interface ScanOptions {
207
212
  wcagTags?: string[];
213
+ /**
214
+ * Highest WCAG conformance level to report. Default 'AA': findings whose
215
+ * criteria are all Level AAA are not reported anywhere (issues, incomplete,
216
+ * summary). 'AAA' opts in (and adds axe's wcag2aaa rules); 'A' keeps Level A only.
217
+ */
218
+ level?: WcagLevel;
208
219
  includeAxe?: boolean;
209
220
  deep?: boolean;
210
221
  deepApiUrl?: string;
@@ -243,4 +254,4 @@ interface ScanOptions {
243
254
  mainStatus?: number;
244
255
  }
245
256
 
246
- export { type BrowserDetector as B, type DetectedIssue as D, type FixDetector as F, type IssueImpact as I, type PageLike as P, type ScanResult as S, VIEWPORT_SIZES as V, WCAG_BY_ISSUE as W, type ScanOptions as a, type SiteTheme as b, type ScanIssue as c, type FixIssueType as d, type IssueSource as e, type ViewportPreset as f, type WcagLevel as g };
257
+ export { type BrowserDetector as B, type DetectedIssue as D, type FixDetector as F, type IssueImpact as I, type PageLike as P, type ScanResult as S, VIEWPORT_SIZES as V, type WcagLevel as W, type ScanOptions as a, type SiteTheme as b, type ScanIssue as c, type FixIssueType as d, type IssueSource as e, type ViewportPreset as f, WCAG_BY_ISSUE as g };
@@ -25,7 +25,7 @@ interface PageLike {
25
25
  };
26
26
  }
27
27
  /** All fix issue types the pipeline can detect and fix. */
28
- type FixIssueType = 'weak_button_name' | 'weak_link_name' | 'weak_heading' | 'weak_iframe_title' | 'weak_page_title' | 'weak_svg_name' | 'weak_skip_link' | 'missing_button_role' | 'missing_semantic_role' | 'missing_landmark' | 'heading_skip' | 'svg_missing_name' | 'aria_hidden_focusable' | 'adjacent_redundant_link' | 'contrast_insufficient' | 'non_text_contrast_insufficient' | 'target_too_small' | 'focus_not_visible' | 'empty_link' | 'unlabeled_button' | 'missing_label' | 'decorative_icon' | 'skip_link' | 'aria_live' | 'missing_alt' | 'identify_input_purpose' | 'redundant_role' | 'duplicate_id' | 'new_window_link' | 'missing_fieldset_legend' | 'missing_table_header' | 'missing_table_caption' | 'missing_table_scope' | 'external_link_warning' | 'download_link_warning' | 'broken_anchor' | 'placeholder_link' | 'missing_aria_required' | 'missing_pattern_title' | 'missing_autocomplete' | 'missing_media_controls' | 'unsafe_autoplay' | 'invalid_aria_role' | 'zoom_restriction' | 'missing_button_type' | 'link_consistency' | 'semantic_emphasis' | 'keyboard_trap' | 'focus_order_disruption' | 'missing_captions' | 'color_only_link' | 'label_in_name' | 'onfocus_context_change' | 'focus_obscured_by_sticky' | 'text_spacing_blocked' | 'nested_landmark' | 'combobox_name_missing' | 'landmark_duplicate_unlabeled' | 'motion_uncontrollable' | 'auto_refresh' | 'motion_without_reduced_motion' | 'flashing_content' | 'animated_gif_no_pause' | 'missing_required_indicator' | 'background_image_unlabeled' | 'missing_h1' | 'multiple_h1' | 'empty_heading' | 'javascript_link' | 'broken_aria_reference' | 'main_content_hidden' | 'scrollable_not_focusable' | 'meaningful_sequence' | 'sensory_characteristic' | 'orientation_lock' | 'image_of_text' | 'reflow_overflow' | 'missing_audio_description' | 'missing_transcript' | 'character_key_shortcut' | 'on_input_change' | 'pointer_gesture' | 'pointer_cancellation' | 'motion_actuation' | 'error_prevention_missing' | 'insufficient_navigation' | 'inconsistent_navigation';
28
+ type FixIssueType = 'weak_button_name' | 'weak_link_name' | 'weak_heading' | 'weak_iframe_title' | 'weak_page_title' | 'weak_svg_name' | 'weak_skip_link' | 'missing_button_role' | 'missing_semantic_role' | 'missing_landmark' | 'heading_skip' | 'svg_missing_name' | 'aria_hidden_focusable' | 'adjacent_redundant_link' | 'contrast_insufficient' | 'non_text_contrast_insufficient' | 'target_too_small' | 'focus_not_visible' | 'empty_link' | 'unlabeled_button' | 'missing_label' | 'decorative_icon' | 'skip_link' | 'aria_live' | 'missing_alt' | 'identify_input_purpose' | 'redundant_role' | 'duplicate_id' | 'new_window_link' | 'missing_fieldset_legend' | 'missing_table_header' | 'missing_table_caption' | 'missing_table_scope' | 'external_link_warning' | 'download_link_warning' | 'broken_anchor' | 'placeholder_link' | 'missing_pattern_title' | 'missing_autocomplete' | 'missing_media_controls' | 'unsafe_autoplay' | 'invalid_aria_role' | 'zoom_restriction' | 'missing_button_type' | 'link_consistency' | 'semantic_emphasis' | 'keyboard_trap' | 'focus_order_disruption' | 'missing_captions' | 'color_only_link' | 'label_in_name' | 'onfocus_context_change' | 'focus_obscured_by_sticky' | 'text_spacing_blocked' | 'nested_landmark' | 'combobox_name_missing' | 'landmark_duplicate_unlabeled' | 'motion_uncontrollable' | 'auto_refresh' | 'motion_without_reduced_motion' | 'flashing_content' | 'animated_gif_no_pause' | 'missing_required_indicator' | 'background_image_unlabeled' | 'missing_h1' | 'multiple_h1' | 'empty_heading' | 'javascript_link' | 'broken_aria_reference' | 'main_content_hidden' | 'scrollable_not_focusable' | 'meaningful_sequence' | 'sensory_characteristic' | 'orientation_lock' | 'image_of_text' | 'reflow_overflow' | 'missing_audio_description' | 'missing_transcript' | 'character_key_shortcut' | 'on_input_change' | 'pointer_gesture' | 'pointer_cancellation' | 'motion_actuation' | 'error_prevention_missing' | 'insufficient_navigation' | 'inconsistent_navigation';
29
29
  /** WCAG criterion for each issue type. */
30
30
  declare const WCAG_BY_ISSUE: Record<FixIssueType, string>;
31
31
  /** A single accessibility issue detected on the page. */
@@ -51,12 +51,17 @@ interface DetectedIssue {
51
51
  /** Optional: outer HTML snippet (first 300 chars) for Claude context. */
52
52
  outerHtml?: string;
53
53
  /**
54
- * Detector-side signal that the finding is ambiguous and should land in
55
- * `ScanResult.incomplete[]` (e.g. contrast against a gradient). The scanner
56
- * propagates this to ScanIssue.confidence so the confidence classifier
57
- * doesn't have to reverse-engineer the situation from HTML strings.
54
+ * Detector-side signal that the VERDICT is uncertain (e.g. contrast against
55
+ * a gradient). The scanner never reports such a finding: it is resolved to a
56
+ * verdict by an engine resolver or dropped. For "verdict certain, fix not
57
+ * mechanical" use `manualFix`.
58
58
  */
59
59
  needsReview?: boolean;
60
+ /**
61
+ * The verdict is certain but the suggested fix cannot be applied
62
+ * mechanically. Sets `fix.needsManualReview`; never changes the verdict.
63
+ */
64
+ manualFix?: boolean;
60
65
  /** Why this finding needs review — surfaced to MCP/SDK consumers. */
61
66
  reviewReason?: string;
62
67
  /**
@@ -182,9 +187,9 @@ interface ScanResult {
182
187
  /** Engine (core package) version that produced this result — provenance */
183
188
  engine?: string;
184
189
  /**
185
- * Findings the classifier or axe-core flagged as ambiguous. Show to the user
186
- * for review — never auto-fix. Empty array (not omitted) when no incompletes,
187
- * so consumers can rely on the field.
190
+ * @deprecated Always `[]`. The scanner judges uncertain findings itself:
191
+ * each becomes a verdict in `issues` or is dropped. The field stays only so
192
+ * existing consumers that read it keep compiling.
188
193
  */
189
194
  incomplete: ScanIssue[];
190
195
  summary: {
@@ -193,7 +198,7 @@ interface ScanResult {
193
198
  serious: number;
194
199
  moderate: number;
195
200
  minor: number;
196
- /** Count of items in `incomplete[]`. */
201
+ /** @deprecated Always 0 — there is no incomplete bucket. */
197
202
  incomplete: number;
198
203
  };
199
204
  axeResults?: unknown;
@@ -205,6 +210,12 @@ declare const VIEWPORT_SIZES: Record<ViewportPreset, {
205
210
  }>;
206
211
  interface ScanOptions {
207
212
  wcagTags?: string[];
213
+ /**
214
+ * Highest WCAG conformance level to report. Default 'AA': findings whose
215
+ * criteria are all Level AAA are not reported anywhere (issues, incomplete,
216
+ * summary). 'AAA' opts in (and adds axe's wcag2aaa rules); 'A' keeps Level A only.
217
+ */
218
+ level?: WcagLevel;
208
219
  includeAxe?: boolean;
209
220
  deep?: boolean;
210
221
  deepApiUrl?: string;
@@ -243,4 +254,4 @@ interface ScanOptions {
243
254
  mainStatus?: number;
244
255
  }
245
256
 
246
- export { type BrowserDetector as B, type DetectedIssue as D, type FixDetector as F, type IssueImpact as I, type PageLike as P, type ScanResult as S, VIEWPORT_SIZES as V, WCAG_BY_ISSUE as W, type ScanOptions as a, type SiteTheme as b, type ScanIssue as c, type FixIssueType as d, type IssueSource as e, type ViewportPreset as f, type WcagLevel as g };
257
+ export { type BrowserDetector as B, type DetectedIssue as D, type FixDetector as F, type IssueImpact as I, type PageLike as P, type ScanResult as S, VIEWPORT_SIZES as V, type WcagLevel as W, type ScanOptions as a, type SiteTheme as b, type ScanIssue as c, type FixIssueType as d, type IssueSource as e, type ViewportPreset as f, WCAG_BY_ISSUE as g };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@webability/core",
3
- "version": "1.4.0",
4
- "description": "Accessibility scanner engine — WCAG 2.2 AA/AAA compliance testing with 200+ rules",
3
+ "version": "1.6.0",
4
+ "description": "Accessibility scanner engine \u2014 WCAG 2.2 AA compliance testing with 200+ rules",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
7
7
  "module": "./dist/index.js",
@@ -27,6 +27,15 @@
27
27
  "dist",
28
28
  "NOTICES.md"
29
29
  ],
30
+ "scripts": {
31
+ "build": "npm run gen:dom-kernel && tsup",
32
+ "dev": "tsup --watch",
33
+ "test": "vitest run",
34
+ "test:watch": "vitest",
35
+ "typecheck": "tsc --noEmit",
36
+ "clean": "rm -rf dist",
37
+ "gen:dom-kernel": "node scripts/gen-dom-kernel.mjs"
38
+ },
30
39
  "keywords": [
31
40
  "a11y",
32
41
  "abilyo",
@@ -67,14 +76,5 @@
67
76
  "engines": {
68
77
  "node": ">=18"
69
78
  },
70
- "homepage": "https://abilyo.com",
71
- "scripts": {
72
- "build": "npm run gen:dom-kernel && tsup",
73
- "dev": "tsup --watch",
74
- "test": "vitest run",
75
- "test:watch": "vitest",
76
- "typecheck": "tsc --noEmit",
77
- "clean": "rm -rf dist",
78
- "gen:dom-kernel": "node scripts/gen-dom-kernel.mjs"
79
- }
80
- }
79
+ "homepage": "https://webability.io"
80
+ }