@webability/core 1.11.0 → 1.13.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.
@@ -219,7 +219,7 @@ interface PageLike {
219
219
  axePage?(): unknown;
220
220
  }
221
221
  /** All fix issue types the pipeline can detect and fix. */
222
- 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_document_language' | 'missing_landmark' | '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' | 'form_missing_submit' | 'decorative_image_with_title' | 'placeholder_link' | 'missing_pattern_title' | 'missing_autocomplete' | 'missing_media_controls' | 'unsafe_autoplay' | 'zoom_restriction' | 'missing_button_type' | 'link_consistency' | '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' | 'motion_uncontrollable' | 'auto_refresh' | 'motion_without_reduced_motion' | 'flashing_content' | 'animated_gif_no_pause' | 'missing_required_indicator' | 'background_image_unlabeled' | 'empty_heading' | 'javascript_link' | 'broken_aria_reference' | 'main_content_hidden' | 'scrollable_not_focusable' | 'meaningful_sequence' | 'sensory_characteristic' | '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' | 'inconsistent_navigation';
222
+ type FixIssueType = 'weak_link_name' | 'weak_heading' | 'weak_iframe_title' | 'weak_page_title' | 'weak_svg_name' | 'missing_button_role' | 'missing_semantic_role' | 'missing_document_language' | 'svg_missing_name' | 'aria_hidden_focusable' | 'contrast_insufficient' | 'non_text_contrast_insufficient' | 'focus_not_visible' | 'empty_link' | 'unlabeled_button' | 'missing_label' | 'skip_link' | 'aria_live' | 'missing_alt' | 'identify_input_purpose' | 'redundant_role' | 'new_window_link' | 'missing_fieldset_legend' | 'missing_table_header' | 'missing_table_caption' | 'missing_table_scope' | 'external_link_warning' | 'download_link_warning' | 'form_missing_submit' | 'placeholder_link' | 'missing_autocomplete' | 'missing_media_controls' | 'unsafe_autoplay' | 'zoom_restriction' | 'resize_text_clipped' | 'link_consistency' | 'keyboard_trap' | 'keyboard_trap_self_focus' | 'focus_order_disruption' | 'missing_captions' | 'color_only_link' | 'label_in_name' | 'onfocus_context_change' | 'focus_obscured_by_sticky' | 'text_spacing_blocked' | 'motion_uncontrollable' | 'auto_refresh' | 'motion_without_reduced_motion' | 'flashing_content' | 'animated_gif_no_pause' | 'carousel_autoplay_no_pause' | 'missing_required_indicator' | 'background_image_unlabeled' | 'broken_aria_reference' | 'main_content_hidden' | 'meaningful_sequence' | 'sensory_characteristic' | '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' | 'inconsistent_navigation' | 'adjacent_redundant_link' | 'missing_button_type' | 'decorative_image_with_title' | 'nested_landmark';
223
223
  /** WCAG criterion for each issue type. */
224
224
  declare const WCAG_BY_ISSUE: Record<FixIssueType, string>;
225
225
  /** A single accessibility issue detected on the page. */
@@ -258,6 +258,12 @@ interface DetectedIssue {
258
258
  manualFix?: boolean;
259
259
  /** Why this finding needs review — surfaced to MCP/SDK consumers. */
260
260
  reviewReason?: string;
261
+ /**
262
+ * State pseudo-class the fix applies in (`:focus-visible` for
263
+ * focus_not_visible). `selector` always names the element at rest; a
264
+ * consumer that writes CSS appends this to the selector.
265
+ */
266
+ pseudo?: string;
261
267
  /**
262
268
  * Optional exact user-facing message. Use when the generic
263
269
  * attribute/currentValue template ("missing X", "X is \"Y\"") would state
@@ -425,6 +431,12 @@ interface ScanResult {
425
431
  internal_bugs?: InternalBug[];
426
432
  /** Engine (core package) version that produced this result — provenance */
427
433
  engine?: string;
434
+ /**
435
+ * @internal The WebAbility detectors' raw rows, before conversion, judging,
436
+ * dedup and level gating. Present only with `keepDetected`. Not findings: a
437
+ * row here may have been dropped from `issues`.
438
+ */
439
+ detected?: DetectedIssue[];
428
440
  /**
429
441
  * @deprecated Always `[]`. The scanner judges uncertain findings itself:
430
442
  * each becomes a verdict in `issues` or is dropped. The field stays only so
@@ -458,12 +470,25 @@ interface ScanOptions {
458
470
  wcagTags?: string[];
459
471
  /** @internal test seam: extra detectors run serially, each in its own state guard. */
460
472
  extraSerialDetectors?: FixDetector[];
473
+ /**
474
+ * @internal Return the WebAbility detectors' raw rows as `ScanResult.detected`
475
+ * (runEngine joins them to the reported issues for the platform). Default off:
476
+ * the result carries no `detected` key.
477
+ */
478
+ keepDetected?: boolean;
461
479
  /**
462
480
  * Highest WCAG conformance level to report. Default 'AA': findings whose
463
481
  * criteria are all Level AAA are not reported anywhere (issues, incomplete,
464
482
  * summary). 'AAA' opts in (and adds axe's wcag2aaa rules); 'A' keeps Level A only.
465
483
  */
466
484
  level?: WcagLevel;
485
+ /**
486
+ * Also run the experimental best-practice checks (default false). They are
487
+ * not WCAG 2.2 A/AA requirements, so the default scan never runs them:
488
+ * adjacent_redundant_link, missing_button_type, decorative_image_with_title,
489
+ * nested_landmark.
490
+ */
491
+ experimental?: boolean;
467
492
  /**
468
493
  * Run axe-core (default true). axe is the only engine for the checks it
469
494
  * covers on the ACT test suite: form-field / select / combobox names and
@@ -219,7 +219,7 @@ interface PageLike {
219
219
  axePage?(): unknown;
220
220
  }
221
221
  /** All fix issue types the pipeline can detect and fix. */
222
- 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_document_language' | 'missing_landmark' | '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' | 'form_missing_submit' | 'decorative_image_with_title' | 'placeholder_link' | 'missing_pattern_title' | 'missing_autocomplete' | 'missing_media_controls' | 'unsafe_autoplay' | 'zoom_restriction' | 'missing_button_type' | 'link_consistency' | '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' | 'motion_uncontrollable' | 'auto_refresh' | 'motion_without_reduced_motion' | 'flashing_content' | 'animated_gif_no_pause' | 'missing_required_indicator' | 'background_image_unlabeled' | 'empty_heading' | 'javascript_link' | 'broken_aria_reference' | 'main_content_hidden' | 'scrollable_not_focusable' | 'meaningful_sequence' | 'sensory_characteristic' | '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' | 'inconsistent_navigation';
222
+ type FixIssueType = 'weak_link_name' | 'weak_heading' | 'weak_iframe_title' | 'weak_page_title' | 'weak_svg_name' | 'missing_button_role' | 'missing_semantic_role' | 'missing_document_language' | 'svg_missing_name' | 'aria_hidden_focusable' | 'contrast_insufficient' | 'non_text_contrast_insufficient' | 'focus_not_visible' | 'empty_link' | 'unlabeled_button' | 'missing_label' | 'skip_link' | 'aria_live' | 'missing_alt' | 'identify_input_purpose' | 'redundant_role' | 'new_window_link' | 'missing_fieldset_legend' | 'missing_table_header' | 'missing_table_caption' | 'missing_table_scope' | 'external_link_warning' | 'download_link_warning' | 'form_missing_submit' | 'placeholder_link' | 'missing_autocomplete' | 'missing_media_controls' | 'unsafe_autoplay' | 'zoom_restriction' | 'resize_text_clipped' | 'link_consistency' | 'keyboard_trap' | 'keyboard_trap_self_focus' | 'focus_order_disruption' | 'missing_captions' | 'color_only_link' | 'label_in_name' | 'onfocus_context_change' | 'focus_obscured_by_sticky' | 'text_spacing_blocked' | 'motion_uncontrollable' | 'auto_refresh' | 'motion_without_reduced_motion' | 'flashing_content' | 'animated_gif_no_pause' | 'carousel_autoplay_no_pause' | 'missing_required_indicator' | 'background_image_unlabeled' | 'broken_aria_reference' | 'main_content_hidden' | 'meaningful_sequence' | 'sensory_characteristic' | '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' | 'inconsistent_navigation' | 'adjacent_redundant_link' | 'missing_button_type' | 'decorative_image_with_title' | 'nested_landmark';
223
223
  /** WCAG criterion for each issue type. */
224
224
  declare const WCAG_BY_ISSUE: Record<FixIssueType, string>;
225
225
  /** A single accessibility issue detected on the page. */
@@ -258,6 +258,12 @@ interface DetectedIssue {
258
258
  manualFix?: boolean;
259
259
  /** Why this finding needs review — surfaced to MCP/SDK consumers. */
260
260
  reviewReason?: string;
261
+ /**
262
+ * State pseudo-class the fix applies in (`:focus-visible` for
263
+ * focus_not_visible). `selector` always names the element at rest; a
264
+ * consumer that writes CSS appends this to the selector.
265
+ */
266
+ pseudo?: string;
261
267
  /**
262
268
  * Optional exact user-facing message. Use when the generic
263
269
  * attribute/currentValue template ("missing X", "X is \"Y\"") would state
@@ -425,6 +431,12 @@ interface ScanResult {
425
431
  internal_bugs?: InternalBug[];
426
432
  /** Engine (core package) version that produced this result — provenance */
427
433
  engine?: string;
434
+ /**
435
+ * @internal The WebAbility detectors' raw rows, before conversion, judging,
436
+ * dedup and level gating. Present only with `keepDetected`. Not findings: a
437
+ * row here may have been dropped from `issues`.
438
+ */
439
+ detected?: DetectedIssue[];
428
440
  /**
429
441
  * @deprecated Always `[]`. The scanner judges uncertain findings itself:
430
442
  * each becomes a verdict in `issues` or is dropped. The field stays only so
@@ -458,12 +470,25 @@ interface ScanOptions {
458
470
  wcagTags?: string[];
459
471
  /** @internal test seam: extra detectors run serially, each in its own state guard. */
460
472
  extraSerialDetectors?: FixDetector[];
473
+ /**
474
+ * @internal Return the WebAbility detectors' raw rows as `ScanResult.detected`
475
+ * (runEngine joins them to the reported issues for the platform). Default off:
476
+ * the result carries no `detected` key.
477
+ */
478
+ keepDetected?: boolean;
461
479
  /**
462
480
  * Highest WCAG conformance level to report. Default 'AA': findings whose
463
481
  * criteria are all Level AAA are not reported anywhere (issues, incomplete,
464
482
  * summary). 'AAA' opts in (and adds axe's wcag2aaa rules); 'A' keeps Level A only.
465
483
  */
466
484
  level?: WcagLevel;
485
+ /**
486
+ * Also run the experimental best-practice checks (default false). They are
487
+ * not WCAG 2.2 A/AA requirements, so the default scan never runs them:
488
+ * adjacent_redundant_link, missing_button_type, decorative_image_with_title,
489
+ * nested_landmark.
490
+ */
491
+ experimental?: boolean;
467
492
  /**
468
493
  * Run axe-core (default true). axe is the only engine for the checks it
469
494
  * covers on the ACT test suite: form-field / select / combobox names and
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webability/core",
3
- "version": "1.11.0",
3
+ "version": "1.13.0",
4
4
  "description": "Accessibility scanner engine — WCAG 2.2 AA compliance testing with 200+ rules",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -82,7 +82,9 @@
82
82
  "devDependencies": {
83
83
  "axe-core": "^4.11.3",
84
84
  "esbuild": "0.27.7",
85
+ "jsdom": "29.0.2",
85
86
  "playwright": "1.59.1",
87
+ "puppeteer-core": "24",
86
88
  "tsup": "^8.3.0",
87
89
  "typescript": "^5.6.0",
88
90
  "vitest": "^2.0.0"