stimeo-ui 0.5.0 → 0.7.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/CHANGELOG.md +178 -0
- package/dist/controllers/alert_dialog_controller.d.ts +2 -0
- package/dist/controllers/alert_dialog_controller.js +75 -4
- package/dist/controllers/alert_dialog_controller.js.map +1 -1
- package/dist/controllers/aspect_ratio_controller.d.ts +1 -3
- package/dist/controllers/aspect_ratio_controller.js +19 -11
- package/dist/controllers/aspect_ratio_controller.js.map +1 -1
- package/dist/controllers/auto_submit_controller.d.ts +2 -0
- package/dist/controllers/auto_submit_controller.js.map +1 -1
- package/dist/controllers/avatar_controller.d.ts +36 -15
- package/dist/controllers/avatar_controller.js +237 -40
- package/dist/controllers/avatar_controller.js.map +1 -1
- package/dist/controllers/breadcrumb_controller.d.ts +2 -0
- package/dist/controllers/breadcrumb_controller.js.map +1 -1
- package/dist/controllers/bulk_select_controller.d.ts +2 -0
- package/dist/controllers/bulk_select_controller.js.map +1 -1
- package/dist/controllers/calendar_controller.d.ts +2 -0
- package/dist/controllers/calendar_controller.js.map +1 -1
- package/dist/controllers/carousel_controller.d.ts +12 -3
- package/dist/controllers/carousel_controller.js +85 -9
- package/dist/controllers/carousel_controller.js.map +1 -1
- package/dist/controllers/character_counter_controller.d.ts +52 -20
- package/dist/controllers/character_counter_controller.js +338 -63
- package/dist/controllers/character_counter_controller.js.map +1 -1
- package/dist/controllers/checkbox_controller.d.ts +34 -5
- package/dist/controllers/checkbox_controller.js +136 -25
- package/dist/controllers/checkbox_controller.js.map +1 -1
- package/dist/controllers/color_picker_controller.d.ts +10 -1
- package/dist/controllers/color_picker_controller.js +35 -9
- package/dist/controllers/color_picker_controller.js.map +1 -1
- package/dist/controllers/combobox_controller.d.ts +2 -0
- package/dist/controllers/combobox_controller.js.map +1 -1
- package/dist/controllers/command_palette_controller.d.ts +2 -0
- package/dist/controllers/command_palette_controller.js +75 -4
- package/dist/controllers/command_palette_controller.js.map +1 -1
- package/dist/controllers/conditional_fields_controller.d.ts +42 -14
- package/dist/controllers/conditional_fields_controller.js +345 -51
- package/dist/controllers/conditional_fields_controller.js.map +1 -1
- package/dist/controllers/confirm_controller.d.ts +2 -0
- package/dist/controllers/confirm_controller.js +75 -4
- package/dist/controllers/confirm_controller.js.map +1 -1
- package/dist/controllers/count_up_controller.d.ts +2 -0
- package/dist/controllers/count_up_controller.js.map +1 -1
- package/dist/controllers/countdown_controller.d.ts +4 -0
- package/dist/controllers/countdown_controller.js.map +1 -1
- package/dist/controllers/currency_input_controller.d.ts +2 -0
- package/dist/controllers/currency_input_controller.js.map +1 -1
- package/dist/controllers/data_grid_controller.d.ts +3 -0
- package/dist/controllers/data_grid_controller.js.map +1 -1
- package/dist/controllers/date_range_picker_controller.d.ts +23 -4
- package/dist/controllers/date_range_picker_controller.js +157 -30
- package/dist/controllers/date_range_picker_controller.js.map +1 -1
- package/dist/controllers/dialog_controller.js +75 -4
- package/dist/controllers/dialog_controller.js.map +1 -1
- package/dist/controllers/direct_upload_controller.d.ts +56 -24
- package/dist/controllers/direct_upload_controller.js +201 -45
- package/dist/controllers/direct_upload_controller.js.map +1 -1
- package/dist/controllers/dirty_form_controller.d.ts +14 -6
- package/dist/controllers/dirty_form_controller.js +192 -29
- package/dist/controllers/dirty_form_controller.js.map +1 -1
- package/dist/controllers/dismissible_controller.d.ts +2 -0
- package/dist/controllers/dismissible_controller.js +83 -18
- package/dist/controllers/dismissible_controller.js.map +1 -1
- package/dist/controllers/drawer_controller.js +75 -4
- package/dist/controllers/drawer_controller.js.map +1 -1
- package/dist/controllers/empty_state_controller.d.ts +2 -0
- package/dist/controllers/empty_state_controller.js.map +1 -1
- package/dist/controllers/file_dropzone_controller.d.ts +9 -1
- package/dist/controllers/file_dropzone_controller.js +26 -3
- package/dist/controllers/file_dropzone_controller.js.map +1 -1
- package/dist/controllers/filter_controller.d.ts +2 -0
- package/dist/controllers/filter_controller.js.map +1 -1
- package/dist/controllers/flash_controller.d.ts +4 -0
- package/dist/controllers/flash_controller.js.map +1 -1
- package/dist/controllers/focus_controller.d.ts +4 -3
- package/dist/controllers/focus_controller.js +75 -4
- package/dist/controllers/focus_controller.js.map +1 -1
- package/dist/controllers/form_field_controller.d.ts +50 -10
- package/dist/controllers/form_field_controller.js +280 -62
- package/dist/controllers/form_field_controller.js.map +1 -1
- package/dist/controllers/form_validation_controller.d.ts +10 -8
- package/dist/controllers/form_validation_controller.js +208 -83
- package/dist/controllers/form_validation_controller.js.map +1 -1
- package/dist/controllers/frame_loading_controller.d.ts +2 -0
- package/dist/controllers/frame_loading_controller.js.map +1 -1
- package/dist/controllers/highlight_controller.d.ts +2 -0
- package/dist/controllers/highlight_controller.js.map +1 -1
- package/dist/controllers/hover_card_controller.d.ts +2 -2
- package/dist/controllers/hover_card_controller.js.map +1 -1
- package/dist/controllers/idle_controller.d.ts +5 -3
- package/dist/controllers/idle_controller.js +27 -5
- package/dist/controllers/idle_controller.js.map +1 -1
- package/dist/controllers/input_mask_controller.d.ts +2 -0
- package/dist/controllers/input_mask_controller.js.map +1 -1
- package/dist/controllers/lazy_frame_controller.d.ts +2 -0
- package/dist/controllers/lazy_frame_controller.js.map +1 -1
- package/dist/controllers/listbox_controller.d.ts +2 -0
- package/dist/controllers/listbox_controller.js.map +1 -1
- package/dist/controllers/local_time_controller.d.ts +2 -0
- package/dist/controllers/local_time_controller.js.map +1 -1
- package/dist/controllers/masonry_controller.d.ts +2 -0
- package/dist/controllers/masonry_controller.js.map +1 -1
- package/dist/controllers/menubar_controller.js +5 -3
- package/dist/controllers/menubar_controller.js.map +1 -1
- package/dist/controllers/meter_controller.d.ts +2 -0
- package/dist/controllers/meter_controller.js.map +1 -1
- package/dist/controllers/multi_select_controller.d.ts +48 -12
- package/dist/controllers/multi_select_controller.js +460 -151
- package/dist/controllers/multi_select_controller.js.map +1 -1
- package/dist/controllers/nested_form_controller.d.ts +2 -0
- package/dist/controllers/nested_form_controller.js.map +1 -1
- package/dist/controllers/network_status_controller.d.ts +2 -0
- package/dist/controllers/network_status_controller.js.map +1 -1
- package/dist/controllers/number_input_controller.d.ts +26 -6
- package/dist/controllers/number_input_controller.js +317 -51
- package/dist/controllers/number_input_controller.js.map +1 -1
- package/dist/controllers/otp_controller.d.ts +3 -0
- package/dist/controllers/otp_controller.js.map +1 -1
- package/dist/controllers/overflow_indicator_controller.d.ts +2 -0
- package/dist/controllers/overflow_indicator_controller.js.map +1 -1
- package/dist/controllers/overflow_menu_controller.d.ts +2 -0
- package/dist/controllers/overflow_menu_controller.js +6 -1
- package/dist/controllers/overflow_menu_controller.js.map +1 -1
- package/dist/controllers/pagination_controller.d.ts +2 -0
- package/dist/controllers/pagination_controller.js +35 -1
- package/dist/controllers/pagination_controller.js.map +1 -1
- package/dist/controllers/password_reveal_controller.d.ts +2 -0
- package/dist/controllers/password_reveal_controller.js.map +1 -1
- package/dist/controllers/password_strength_controller.d.ts +5 -3
- package/dist/controllers/password_strength_controller.js +20 -2
- package/dist/controllers/password_strength_controller.js.map +1 -1
- package/dist/controllers/persist_controller.d.ts +33 -19
- package/dist/controllers/persist_controller.js +449 -120
- package/dist/controllers/persist_controller.js.map +1 -1
- package/dist/controllers/pointer_drag_controller.d.ts +3 -0
- package/dist/controllers/pointer_drag_controller.js.map +1 -1
- package/dist/controllers/popover_controller.d.ts +2 -2
- package/dist/controllers/popover_controller.js +77 -4
- package/dist/controllers/popover_controller.js.map +1 -1
- package/dist/controllers/portal_controller.d.ts +3 -2
- package/dist/controllers/portal_controller.js.map +1 -1
- package/dist/controllers/preview_guard_controller.d.ts +2 -0
- package/dist/controllers/preview_guard_controller.js.map +1 -1
- package/dist/controllers/progress_controller.d.ts +3 -0
- package/dist/controllers/progress_controller.js.map +1 -1
- package/dist/controllers/radio_group_controller.d.ts +44 -15
- package/dist/controllers/radio_group_controller.js +540 -56
- package/dist/controllers/radio_group_controller.js.map +1 -1
- package/dist/controllers/rating_controller.d.ts +38 -31
- package/dist/controllers/rating_controller.js +276 -89
- package/dist/controllers/rating_controller.js.map +1 -1
- package/dist/controllers/reading_progress_controller.d.ts +2 -0
- package/dist/controllers/reading_progress_controller.js.map +1 -1
- package/dist/controllers/resizable_controller.d.ts +2 -0
- package/dist/controllers/resizable_controller.js +33 -0
- package/dist/controllers/resizable_controller.js.map +1 -1
- package/dist/controllers/roving_controller.d.ts +6 -0
- package/dist/controllers/roving_controller.js +60 -5
- package/dist/controllers/roving_controller.js.map +1 -1
- package/dist/controllers/scroll_area_controller.d.ts +25 -11
- package/dist/controllers/scroll_area_controller.js +557 -125
- package/dist/controllers/scroll_area_controller.js.map +1 -1
- package/dist/controllers/scroll_visibility_controller.d.ts +2 -0
- package/dist/controllers/scroll_visibility_controller.js +33 -0
- package/dist/controllers/scroll_visibility_controller.js.map +1 -1
- package/dist/controllers/scrollspy_controller.d.ts +2 -0
- package/dist/controllers/scrollspy_controller.js.map +1 -1
- package/dist/controllers/separator_controller.d.ts +54 -11
- package/dist/controllers/separator_controller.js +354 -38
- package/dist/controllers/separator_controller.js.map +1 -1
- package/dist/controllers/sidebar_controller.js +83 -10
- package/dist/controllers/sidebar_controller.js.map +1 -1
- package/dist/controllers/skeleton_controller.d.ts +2 -0
- package/dist/controllers/skeleton_controller.js.map +1 -1
- package/dist/controllers/slider_controller.d.ts +2 -0
- package/dist/controllers/slider_controller.js.map +1 -1
- package/dist/controllers/smart_sticky_header_controller.d.ts +2 -0
- package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
- package/dist/controllers/spinner_controller.d.ts +2 -0
- package/dist/controllers/spinner_controller.js.map +1 -1
- package/dist/controllers/step_indicator_controller.d.ts +2 -0
- package/dist/controllers/step_indicator_controller.js.map +1 -1
- package/dist/controllers/stepper_controller.d.ts +2 -0
- package/dist/controllers/stepper_controller.js.map +1 -1
- package/dist/controllers/stick_to_bottom_controller.d.ts +2 -0
- package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
- package/dist/controllers/sticky_observer_controller.d.ts +2 -0
- package/dist/controllers/sticky_observer_controller.js.map +1 -1
- package/dist/controllers/submit_once_controller.d.ts +94 -38
- package/dist/controllers/submit_once_controller.js +399 -121
- package/dist/controllers/submit_once_controller.js.map +1 -1
- package/dist/controllers/switch_controller.d.ts +2 -0
- package/dist/controllers/switch_controller.js.map +1 -1
- package/dist/controllers/tags_input_controller.d.ts +43 -11
- package/dist/controllers/tags_input_controller.js +356 -120
- package/dist/controllers/tags_input_controller.js.map +1 -1
- package/dist/controllers/textarea_autosize_controller.d.ts +2 -0
- package/dist/controllers/textarea_autosize_controller.js.map +1 -1
- package/dist/controllers/theme_controller.d.ts +2 -0
- package/dist/controllers/theme_controller.js +8 -6
- package/dist/controllers/theme_controller.js.map +1 -1
- package/dist/controllers/time_picker_controller.d.ts +44 -13
- package/dist/controllers/time_picker_controller.js +296 -107
- package/dist/controllers/time_picker_controller.js.map +1 -1
- package/dist/controllers/toast_controller.d.ts +4 -0
- package/dist/controllers/toast_controller.js.map +1 -1
- package/dist/controllers/toggle_group_controller.d.ts +41 -13
- package/dist/controllers/toggle_group_controller.js +378 -55
- package/dist/controllers/toggle_group_controller.js.map +1 -1
- package/dist/controllers/toolbar_controller.js +5 -3
- package/dist/controllers/toolbar_controller.js.map +1 -1
- package/dist/controllers/tooltip_controller.d.ts +2 -2
- package/dist/controllers/tooltip_controller.js.map +1 -1
- package/dist/controllers/transition_controller.d.ts +4 -3
- package/dist/controllers/transition_controller.js.map +1 -1
- package/dist/controllers/tree_view_controller.d.ts +2 -0
- package/dist/controllers/tree_view_controller.js +7 -4
- package/dist/controllers/tree_view_controller.js.map +1 -1
- package/dist/index.js +4963 -1581
- package/dist/index.js.map +1 -1
- package/dist/inspector/cli.d.ts +123 -6
- package/dist/inspector/cli.js +212 -18
- package/dist/inspector/cli.js.map +1 -1
- package/dist/inspector/cli_bin.js +274 -50
- package/dist/inspector/cli_bin.js.map +1 -1
- package/dist/inspector/examples.json +15 -15
- package/dist/inspector/manifest.json +602 -80
- package/dist/positioning/index.d.ts +4 -2
- package/dist/positioning/index.js.map +1 -1
- package/package.json +1 -1
package/dist/inspector/cli.d.ts
CHANGED
|
@@ -48,6 +48,16 @@ interface ControllerManifest {
|
|
|
48
48
|
* {@link ConditionalTargetRule}.
|
|
49
49
|
*/
|
|
50
50
|
readonly conditionalTargets: readonly ConditionalTargetRule[];
|
|
51
|
+
/**
|
|
52
|
+
* Actions required on a particular element in one Value configuration. See
|
|
53
|
+
* {@link RequiredActionRule}.
|
|
54
|
+
*/
|
|
55
|
+
readonly requiredActions: readonly RequiredActionRule[];
|
|
56
|
+
/**
|
|
57
|
+
* States an action opens that the consumer's wiring has to close. See
|
|
58
|
+
* {@link ActionCompletionRule}.
|
|
59
|
+
*/
|
|
60
|
+
readonly actionCompletion: readonly ActionCompletionRule[];
|
|
51
61
|
/**
|
|
52
62
|
* Accessibility requirements the *consumer's markup* must satisfy (stage 3):
|
|
53
63
|
* ARIA attributes the controller does **not** set at runtime and therefore
|
|
@@ -140,6 +150,8 @@ interface ControllerManifest {
|
|
|
140
150
|
interface ValueCondition {
|
|
141
151
|
/** Value name (camelCase, as declared in `static values`). */
|
|
142
152
|
readonly value: string;
|
|
153
|
+
/** Stimulus decoder used before comparing the effective value. */
|
|
154
|
+
readonly type: "boolean" | "string";
|
|
143
155
|
/** Effective values that arm the rule. */
|
|
144
156
|
readonly equals: readonly string[];
|
|
145
157
|
/** The value's declared default, used when the attribute is absent. */
|
|
@@ -227,9 +239,11 @@ interface DocumentCondition {
|
|
|
227
239
|
* A single accessibility requirement on a controller's markup (Inspector
|
|
228
240
|
* stage 3). At least one of {@link attrs} must be present on the
|
|
229
241
|
* {@link target} element; when {@link values} is given, the present
|
|
230
|
-
* attribute's value must be one of them
|
|
231
|
-
*
|
|
232
|
-
*
|
|
242
|
+
* attribute's value must be one of them, and when it is not, the value must be
|
|
243
|
+
* non-empty — ARIA derives no name from `aria-label=""`, so an empty value
|
|
244
|
+
* leaves the requirement unmet. {@link or} widens the requirement with
|
|
245
|
+
* alternative attribute/value groups — the requirement is satisfied when *any*
|
|
246
|
+
* group is (e.g. `role="status"` **or** `aria-live`).
|
|
233
247
|
*/
|
|
234
248
|
interface A11yRequirement {
|
|
235
249
|
/**
|
|
@@ -597,6 +611,94 @@ interface ConditionalTargetRule {
|
|
|
597
611
|
readonly whenPresent: string;
|
|
598
612
|
/** Targets that become required once {@link whenPresent} appears. */
|
|
599
613
|
readonly require: readonly string[];
|
|
614
|
+
/**
|
|
615
|
+
* Require each {@link require} entry to sit **inside** the `whenPresent`
|
|
616
|
+
* element rather than anywhere in the scope.
|
|
617
|
+
*
|
|
618
|
+
* A `<template>` is cloned at runtime, so a part declared outside it never
|
|
619
|
+
* reaches the clone. Without this the presence check passes on markup the
|
|
620
|
+
* controller then refuses to build from.
|
|
621
|
+
*/
|
|
622
|
+
readonly requireInside?: boolean;
|
|
623
|
+
/**
|
|
624
|
+
* Require each {@link require} entry to share its nearest enclosing host —
|
|
625
|
+
* the closest ancestor matching one of these selectors — with the
|
|
626
|
+
* `whenPresent` element.
|
|
627
|
+
*
|
|
628
|
+
* Neither presence nor {@link requireInside} can express a pair that must sit
|
|
629
|
+
* in the *same* container without being nested in one another. A controller
|
|
630
|
+
* that swaps one host's two halves reads them per host, so halves split
|
|
631
|
+
* across two hosts leave each host with an incomplete pair, and the swap
|
|
632
|
+
* silently does nothing on markup where both names are present.
|
|
633
|
+
*
|
|
634
|
+
* Only a pair whose halves both resolve to a host is judged. A template
|
|
635
|
+
* helper that emits the host leaves nothing in the parsed markup, so an
|
|
636
|
+
* element with no host above it is indistinguishable from one whose host is
|
|
637
|
+
* generated — reporting either would be a guess, and the check stays quiet.
|
|
638
|
+
*/
|
|
639
|
+
readonly requireSameHost?: readonly HostSelector[];
|
|
640
|
+
/**
|
|
641
|
+
* What to call the shared host in the diagnostic (e.g. `submit control`).
|
|
642
|
+
* The selectors' tag names read as a disjunction of element names, which
|
|
643
|
+
* names the mechanism rather than the thing the author is looking at.
|
|
644
|
+
*/
|
|
645
|
+
readonly hostLabel?: string;
|
|
646
|
+
/** Human-readable fix suggestion shown by the CLI (stage 4). */
|
|
647
|
+
readonly suggestion: string;
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* One element shape that can act as a host for {@link
|
|
651
|
+
* ConditionalTargetRule.requireSameHost}.
|
|
652
|
+
*
|
|
653
|
+
* A tag alone is too coarse where the element's `type` decides its role, so an
|
|
654
|
+
* optional attribute filter narrows it. Omitting {@link attr} accepts the tag
|
|
655
|
+
* however it is spelled.
|
|
656
|
+
*/
|
|
657
|
+
interface HostSelector {
|
|
658
|
+
/** Lowercased tag name. */
|
|
659
|
+
readonly tag: string;
|
|
660
|
+
/** Attribute that must carry one of {@link values} for the tag to qualify. */
|
|
661
|
+
readonly attr?: string;
|
|
662
|
+
/** Accepted lowercased values of {@link attr}. */
|
|
663
|
+
readonly values?: readonly string[];
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* An action that puts a controller into a state it cannot leave on its own.
|
|
667
|
+
*
|
|
668
|
+
* A controller whose busy state is opened declaratively has no way to know the
|
|
669
|
+
* consumer never wired the matching exit: nothing throws, the markup is
|
|
670
|
+
* well-formed, and the only symptom is a control that stays disabled for the
|
|
671
|
+
* rest of the page's life. The check reads the wiring the author did declare
|
|
672
|
+
* and says so before it ships.
|
|
673
|
+
*/
|
|
674
|
+
interface ActionCompletionRule {
|
|
675
|
+
/** Action that opens the state. */
|
|
676
|
+
readonly opens: string;
|
|
677
|
+
/** Any one of these actions closes it again. */
|
|
678
|
+
readonly closedBy: readonly string[];
|
|
679
|
+
/** Event types for {@link opens} that the controller cannot complete itself. */
|
|
680
|
+
readonly whenTriggeredBy: readonly string[];
|
|
681
|
+
/** Value whose non-zero number supplies an automatic exit instead. */
|
|
682
|
+
readonly escapeValue?: string;
|
|
683
|
+
/** Human-readable fix suggestion shown by the CLI (stage 4). */
|
|
684
|
+
readonly suggestion: string;
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* An action binding that must exist for one configured behavior to be usable.
|
|
688
|
+
*
|
|
689
|
+
* Declaring an action method on the controller only proves the method exists;
|
|
690
|
+
* Stimulus still needs the consumer to wire it. Optional interactive variants
|
|
691
|
+
* can otherwise enter the Tab order while every key silently does nothing.
|
|
692
|
+
*/
|
|
693
|
+
interface RequiredActionRule {
|
|
694
|
+
/** Target whose element must carry the action; `""` means the scope element. */
|
|
695
|
+
readonly target: string;
|
|
696
|
+
/** Public controller action method that must be wired. */
|
|
697
|
+
readonly action: string;
|
|
698
|
+
/** Event types that make the binding usable for this contract. */
|
|
699
|
+
readonly eventTypes: readonly string[];
|
|
700
|
+
/** Configuration in which the binding becomes mandatory. */
|
|
701
|
+
readonly when?: ValueCondition;
|
|
600
702
|
/** Human-readable fix suggestion shown by the CLI (stage 4). */
|
|
601
703
|
readonly suggestion: string;
|
|
602
704
|
}
|
|
@@ -607,18 +709,33 @@ interface ConditionalTargetRule {
|
|
|
607
709
|
* ""))`) before applying these bounds. ERB-generated values are undecidable and
|
|
608
710
|
* skipped rather than guessed.
|
|
609
711
|
*/
|
|
610
|
-
interface
|
|
712
|
+
interface NumericValueConstraint {
|
|
611
713
|
/** Value name (camelCase, as declared in `static values`). */
|
|
612
714
|
readonly value: string;
|
|
613
|
-
/** Decoder family.
|
|
715
|
+
/** Decoder family. */
|
|
614
716
|
readonly type: "number";
|
|
615
717
|
/** Reject `NaN` and infinities when true. */
|
|
616
718
|
readonly finite?: boolean;
|
|
617
719
|
/** Require a decoded number strictly greater than this bound. */
|
|
618
720
|
readonly greaterThan?: number;
|
|
721
|
+
/** Require a decoded number with no fractional part. */
|
|
722
|
+
readonly integer?: boolean;
|
|
723
|
+
/** Human-readable fix suggestion shown by the CLI (stage 4). */
|
|
724
|
+
readonly suggestion: string;
|
|
725
|
+
}
|
|
726
|
+
/** A statically checkable finite set of accepted String Value literals. */
|
|
727
|
+
interface StringValueConstraint {
|
|
728
|
+
/** Value name (camelCase, as declared in `static values`). */
|
|
729
|
+
readonly value: string;
|
|
730
|
+
/** Decoder family. */
|
|
731
|
+
readonly type: "string";
|
|
732
|
+
/** Exact authored literals accepted by the public contract. */
|
|
733
|
+
readonly allowedValues: readonly string[];
|
|
619
734
|
/** Human-readable fix suggestion shown by the CLI (stage 4). */
|
|
620
735
|
readonly suggestion: string;
|
|
621
736
|
}
|
|
737
|
+
/** A statically checkable semantic contract on one declared Stimulus Value. */
|
|
738
|
+
type ValueConstraint = NumericValueConstraint | StringValueConstraint;
|
|
622
739
|
/**
|
|
623
740
|
* A statically checkable relationship between two numeric Stimulus Values.
|
|
624
741
|
*
|
|
@@ -646,7 +763,7 @@ type DiagnosticSeverity = "error" | "warning";
|
|
|
646
763
|
* for testing, machine-readable output, and `data-stimeo-ignore` suppression
|
|
647
764
|
* lists (which is why the set also exists as a runtime array).
|
|
648
765
|
*/
|
|
649
|
-
declare const DIAGNOSTIC_CODES: readonly ["unknown-controller", "unknown-target", "unknown-value", "invalid-value", "unknown-action-controller", "unknown-action-method", "orphan-target", "missing-required-target", "missing-conditional-target", "missing-aria", "invalid-aria-value", "keyboard-inaccessible", "invalid-host", "unresolved-idref", "managed-aria", "composition-mismatch", "missing-companion", "undeclared-target", "cardinality-violation", "forbidden-aria", "unknown-ignore-code"];
|
|
766
|
+
declare const DIAGNOSTIC_CODES: readonly ["unknown-controller", "unknown-target", "unknown-value", "invalid-value", "unknown-action-controller", "unknown-action-method", "orphan-target", "missing-required-target", "missing-conditional-target", "missing-required-action", "missing-action-completion", "missing-aria", "invalid-aria-value", "keyboard-inaccessible", "invalid-host", "unresolved-idref", "managed-aria", "composition-mismatch", "missing-companion", "undeclared-target", "cardinality-violation", "forbidden-aria", "missing-announcer", "unknown-ignore-code"];
|
|
650
767
|
/** See {@link DIAGNOSTIC_CODES}. */
|
|
651
768
|
type DiagnosticCode = (typeof DIAGNOSTIC_CODES)[number];
|
|
652
769
|
/**
|
package/dist/inspector/cli.js
CHANGED
|
@@ -5,6 +5,65 @@ import { fileURLToPath } from 'url';
|
|
|
5
5
|
|
|
6
6
|
// src/inspector/cli.ts
|
|
7
7
|
|
|
8
|
+
// src/inspector/announcer_rules.ts
|
|
9
|
+
var ANNOUNCER_IDENTIFIER = "stimeo--announcer";
|
|
10
|
+
var ANNOUNCING_CONTROLLERS = [
|
|
11
|
+
"stimeo--auto-submit",
|
|
12
|
+
"stimeo--character-counter",
|
|
13
|
+
"stimeo--countdown",
|
|
14
|
+
"stimeo--direct-upload",
|
|
15
|
+
"stimeo--empty-state",
|
|
16
|
+
"stimeo--flash",
|
|
17
|
+
"stimeo--form-field",
|
|
18
|
+
"stimeo--frame-loading",
|
|
19
|
+
"stimeo--meter",
|
|
20
|
+
"stimeo--multi-select",
|
|
21
|
+
"stimeo--nested-form",
|
|
22
|
+
"stimeo--network-status",
|
|
23
|
+
"stimeo--progress",
|
|
24
|
+
"stimeo--skeleton",
|
|
25
|
+
"stimeo--spinner",
|
|
26
|
+
"stimeo--submit-once",
|
|
27
|
+
"stimeo--tags-input"
|
|
28
|
+
];
|
|
29
|
+
function positionAt(source, index) {
|
|
30
|
+
const before = source.slice(0, index);
|
|
31
|
+
const line = before.split("\n").length;
|
|
32
|
+
const lastBreak = before.lastIndexOf("\n");
|
|
33
|
+
return { line, column: index - lastBreak };
|
|
34
|
+
}
|
|
35
|
+
function firstAnnouncingHit(scanned) {
|
|
36
|
+
let best = null;
|
|
37
|
+
let bestIndex = Number.POSITIVE_INFINITY;
|
|
38
|
+
for (const identifier of ANNOUNCING_CONTROLLERS) {
|
|
39
|
+
const index = scanned.source.indexOf(identifier);
|
|
40
|
+
if (index === -1 || index >= bestIndex) continue;
|
|
41
|
+
bestIndex = index;
|
|
42
|
+
best = { file: scanned.file, identifier, ...positionAt(scanned.source, index) };
|
|
43
|
+
}
|
|
44
|
+
return best;
|
|
45
|
+
}
|
|
46
|
+
function announcerSeatingDiagnostic(sources) {
|
|
47
|
+
let speaker = null;
|
|
48
|
+
for (const scanned of sources) {
|
|
49
|
+
if (scanned.source.includes(ANNOUNCER_IDENTIFIER)) return null;
|
|
50
|
+
if (!speaker) speaker = firstAnnouncingHit(scanned);
|
|
51
|
+
}
|
|
52
|
+
if (!speaker) return null;
|
|
53
|
+
return {
|
|
54
|
+
file: speaker.file,
|
|
55
|
+
diagnostic: {
|
|
56
|
+
code: "missing-announcer",
|
|
57
|
+
severity: "warning",
|
|
58
|
+
message: `"${speaker.identifier}" speaks through the shared announcer, and none of the scanned files seats one.`,
|
|
59
|
+
line: speaker.line,
|
|
60
|
+
column: speaker.column,
|
|
61
|
+
length: speaker.identifier.length,
|
|
62
|
+
suggestion: `Add an element with data-controller="${ANNOUNCER_IDENTIFIER}" (and an assertive/polite target) to the layout, or include the layout in the checked paths.`
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
8
67
|
// src/inspector/html_parser.ts
|
|
9
68
|
var ERB_ELEMENT_TAG = "#erb";
|
|
10
69
|
var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
@@ -930,10 +989,16 @@ function actionDescriptors(dataActionValue) {
|
|
|
930
989
|
if (hash === -1) continue;
|
|
931
990
|
let lhs = descriptor.slice(0, hash);
|
|
932
991
|
const arrow = lhs.indexOf("->");
|
|
933
|
-
|
|
992
|
+
let eventType = "";
|
|
993
|
+
if (arrow !== -1) {
|
|
994
|
+
eventType = lhs.slice(0, arrow);
|
|
995
|
+
lhs = lhs.slice(arrow + 2);
|
|
996
|
+
const at = eventType.indexOf("@");
|
|
997
|
+
if (at !== -1) eventType = eventType.slice(0, at);
|
|
998
|
+
}
|
|
934
999
|
if (!lhs.startsWith(NAMESPACE_PREFIX)) continue;
|
|
935
1000
|
const method = /^[a-zA-Z_$][\w$]*/.exec(descriptor.slice(hash + 1))?.[0] ?? "";
|
|
936
|
-
descriptors.push({ identifier: lhs, method });
|
|
1001
|
+
descriptors.push({ identifier: lhs, method, eventType });
|
|
937
1002
|
}
|
|
938
1003
|
return descriptors;
|
|
939
1004
|
}
|
|
@@ -952,6 +1017,8 @@ var DIAGNOSTIC_CODES = [
|
|
|
952
1017
|
"orphan-target",
|
|
953
1018
|
"missing-required-target",
|
|
954
1019
|
"missing-conditional-target",
|
|
1020
|
+
"missing-required-action",
|
|
1021
|
+
"missing-action-completion",
|
|
955
1022
|
"missing-aria",
|
|
956
1023
|
"invalid-aria-value",
|
|
957
1024
|
"keyboard-inaccessible",
|
|
@@ -963,10 +1030,30 @@ var DIAGNOSTIC_CODES = [
|
|
|
963
1030
|
"undeclared-target",
|
|
964
1031
|
"cardinality-violation",
|
|
965
1032
|
"forbidden-aria",
|
|
1033
|
+
"missing-announcer",
|
|
966
1034
|
"unknown-ignore-code"
|
|
967
1035
|
];
|
|
968
1036
|
|
|
969
1037
|
// src/inspector/check.ts
|
|
1038
|
+
function isInside(node, ancestor) {
|
|
1039
|
+
for (let current = node.parent; current; current = current.parent) {
|
|
1040
|
+
if (current === ancestor) return true;
|
|
1041
|
+
}
|
|
1042
|
+
return false;
|
|
1043
|
+
}
|
|
1044
|
+
function matchesHost(node, selector) {
|
|
1045
|
+
if (node.tag !== selector.tag) return false;
|
|
1046
|
+
if (!selector.attr) return true;
|
|
1047
|
+
const attr = node.attrs.find((candidate) => candidate.name === selector.attr);
|
|
1048
|
+
return attr !== void 0 && (selector.values ?? []).includes(attr.value.trim().toLowerCase());
|
|
1049
|
+
}
|
|
1050
|
+
function nearestHost(node, selectors) {
|
|
1051
|
+
for (let current = node.parent; current; current = current.parent) {
|
|
1052
|
+
if (current.origin !== "markup" || current.opaque) return void 0;
|
|
1053
|
+
if (selectors.some((selector) => matchesHost(current, selector))) return current;
|
|
1054
|
+
}
|
|
1055
|
+
return null;
|
|
1056
|
+
}
|
|
970
1057
|
function checkSource(source, manifest) {
|
|
971
1058
|
const diagnostics = [];
|
|
972
1059
|
const tree = parseHtml(neutralizeErb(source), erbElements(source));
|
|
@@ -985,7 +1072,9 @@ function checkSource(source, manifest) {
|
|
|
985
1072
|
(a) => a.name === `data-${identifier}-${dasherize(when.value)}-value`
|
|
986
1073
|
);
|
|
987
1074
|
if (hostAttr && isDynamicValue(hostAttr)) return null;
|
|
988
|
-
|
|
1075
|
+
const raw = hostAttr ? hostAttr.value : when.default;
|
|
1076
|
+
const effective = when.type === "boolean" ? String(!(raw === "0" || raw.toLowerCase() === "false")) : raw;
|
|
1077
|
+
return when.equals.includes(effective);
|
|
989
1078
|
};
|
|
990
1079
|
const isContentEditable2 = (element) => {
|
|
991
1080
|
let current = element;
|
|
@@ -1058,6 +1147,17 @@ function checkSource(source, manifest) {
|
|
|
1058
1147
|
const scopes = [];
|
|
1059
1148
|
const presence = /* @__PURE__ */ new Map();
|
|
1060
1149
|
const targetNodes = /* @__PURE__ */ new Map();
|
|
1150
|
+
const wiredActions = /* @__PURE__ */ new Map();
|
|
1151
|
+
const recordAction = (owner, identifier, element, method, eventType) => {
|
|
1152
|
+
let byId = wiredActions.get(owner);
|
|
1153
|
+
if (!byId) {
|
|
1154
|
+
byId = /* @__PURE__ */ new Map();
|
|
1155
|
+
wiredActions.set(owner, byId);
|
|
1156
|
+
}
|
|
1157
|
+
const found = byId.get(identifier);
|
|
1158
|
+
if (found) found.push({ element, method, eventType });
|
|
1159
|
+
else byId.set(identifier, [{ element, method, eventType }]);
|
|
1160
|
+
};
|
|
1061
1161
|
const recordPresence = (owner, identifier, target) => {
|
|
1062
1162
|
let byId = presence.get(owner);
|
|
1063
1163
|
if (!byId) {
|
|
@@ -1266,11 +1366,12 @@ function checkSource(source, manifest) {
|
|
|
1266
1366
|
(candidate) => dasherize(candidate.value) === parsed.valueToken
|
|
1267
1367
|
);
|
|
1268
1368
|
if (constraint && !valueSatisfiesConstraint(attr.value, constraint)) {
|
|
1369
|
+
const literal = constraint.type === "string" ? attr.value : attr.value.trim();
|
|
1269
1370
|
report(
|
|
1270
1371
|
node,
|
|
1271
1372
|
"invalid-value",
|
|
1272
1373
|
"error",
|
|
1273
|
-
`Invalid value "${
|
|
1374
|
+
`Invalid value "${literal}" for "${parsed.identifier}.${parsed.valueToken}". Expected ${describeValueConstraint(constraint)}.`,
|
|
1274
1375
|
attr,
|
|
1275
1376
|
constraint.suggestion
|
|
1276
1377
|
);
|
|
@@ -1281,8 +1382,12 @@ function checkSource(source, manifest) {
|
|
|
1281
1382
|
}
|
|
1282
1383
|
}
|
|
1283
1384
|
if (attr.name === "data-action") {
|
|
1284
|
-
for (const { identifier, method } of actionDescriptors(attr.value)) {
|
|
1385
|
+
for (const { identifier, method, eventType } of actionDescriptors(attr.value)) {
|
|
1285
1386
|
const controller = known[identifier];
|
|
1387
|
+
if (controller && method.length > 0) {
|
|
1388
|
+
const owner = findOwner(node, identifier);
|
|
1389
|
+
if (owner) recordAction(owner, identifier, node, method, eventType);
|
|
1390
|
+
}
|
|
1286
1391
|
if (!controller) {
|
|
1287
1392
|
const best = nearestName(identifier, knownIdentifiers);
|
|
1288
1393
|
report(
|
|
@@ -1364,18 +1469,89 @@ function checkSource(source, manifest) {
|
|
|
1364
1469
|
const present = presence.get(node)?.get(identifier) ?? /* @__PURE__ */ new Set();
|
|
1365
1470
|
for (const rule of controller.conditionalTargets) {
|
|
1366
1471
|
if (!present.has(rule.whenPresent)) continue;
|
|
1367
|
-
const
|
|
1472
|
+
const nodesOf = (target) => targetNodes.get(node)?.get(identifier)?.get(target) ?? [];
|
|
1473
|
+
const owners = nodesOf(rule.whenPresent);
|
|
1474
|
+
const hosts = rule.requireSameHost;
|
|
1475
|
+
const sharesHost = (target, selectors) => {
|
|
1476
|
+
const ownerHosts = owners.map((owner) => nearestHost(owner, selectors));
|
|
1477
|
+
if (ownerHosts.some((host) => !host)) return true;
|
|
1478
|
+
const candidates = nodesOf(target);
|
|
1479
|
+
if (candidates.length === 0) return false;
|
|
1480
|
+
return candidates.some((el) => {
|
|
1481
|
+
const host = nearestHost(el, selectors);
|
|
1482
|
+
return host ? ownerHosts.includes(host) : true;
|
|
1483
|
+
});
|
|
1484
|
+
};
|
|
1485
|
+
const satisfied = (target) => {
|
|
1486
|
+
if (hosts) return sharesHost(target, hosts);
|
|
1487
|
+
if (rule.requireInside)
|
|
1488
|
+
return nodesOf(target).some((el) => owners.some((owner) => isInside(el, owner)));
|
|
1489
|
+
return present.has(target);
|
|
1490
|
+
};
|
|
1491
|
+
const missing = rule.require.filter((target) => !satisfied(target));
|
|
1368
1492
|
if (missing.length === 0) continue;
|
|
1369
1493
|
report(
|
|
1370
1494
|
node,
|
|
1371
1495
|
"missing-conditional-target",
|
|
1372
1496
|
complete ? "error" : "warning",
|
|
1373
|
-
`"${identifier}" has a "${rule.whenPresent}" target, which also requires ${list(missing)}.`,
|
|
1497
|
+
hosts ? `"${identifier}" requires ${list(missing)} in the same ${rule.hostLabel ?? "element"} as its "${rule.whenPresent}".` : rule.requireInside ? `"${identifier}" requires ${list(missing)} inside its "${rule.whenPresent}".` : `"${identifier}" has a "${rule.whenPresent}" target, which also requires ${list(missing)}.`,
|
|
1374
1498
|
node,
|
|
1375
1499
|
complete ? rule.suggestion : UNRESOLVED_TARGET_HINT
|
|
1376
1500
|
);
|
|
1377
1501
|
}
|
|
1378
1502
|
}
|
|
1503
|
+
for (const { node, identifier } of scopes) {
|
|
1504
|
+
const controller = known[identifier];
|
|
1505
|
+
if (!controller) continue;
|
|
1506
|
+
const wired = wiredActions.get(node)?.get(identifier) ?? [];
|
|
1507
|
+
for (const rule of controller.requiredActions) {
|
|
1508
|
+
if (conditionHolds(node, identifier, rule.when) !== true) continue;
|
|
1509
|
+
const elements = rule.target === "" ? [node] : targetNodes.get(node)?.get(identifier)?.get(rule.target) ?? [];
|
|
1510
|
+
for (const element of elements) {
|
|
1511
|
+
const actionAttr = element.attrs.find((attr) => attr.name === "data-action");
|
|
1512
|
+
if (element.opaque || actionAttr && isDynamicValue(actionAttr)) continue;
|
|
1513
|
+
const satisfied = wired.some(
|
|
1514
|
+
(action) => action.element === element && action.method === rule.action && rule.eventTypes.includes(action.eventType)
|
|
1515
|
+
);
|
|
1516
|
+
if (satisfied) continue;
|
|
1517
|
+
const where = rule.target === "" ? "scope element" : `"${rule.target}" target`;
|
|
1518
|
+
report(
|
|
1519
|
+
element,
|
|
1520
|
+
"missing-required-action",
|
|
1521
|
+
"error",
|
|
1522
|
+
`The ${where} of "${identifier}" requires action "${rule.action}" on ${list(rule.eventTypes)} in this configuration.`,
|
|
1523
|
+
element,
|
|
1524
|
+
rule.suggestion
|
|
1525
|
+
);
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
for (const { node, identifier } of scopes) {
|
|
1530
|
+
const controller = known[identifier];
|
|
1531
|
+
if (!controller) continue;
|
|
1532
|
+
const wired = wiredActions.get(node)?.get(identifier) ?? [];
|
|
1533
|
+
if (wired.length === 0) continue;
|
|
1534
|
+
for (const rule of controller.actionCompletion) {
|
|
1535
|
+
const opens = wired.some(
|
|
1536
|
+
(action) => action.method === rule.opens && rule.whenTriggeredBy.includes(action.eventType)
|
|
1537
|
+
);
|
|
1538
|
+
if (!opens) continue;
|
|
1539
|
+
if (wired.some((action) => rule.closedBy.includes(action.method))) continue;
|
|
1540
|
+
if (rule.escapeValue) {
|
|
1541
|
+
const attrName = `data-${identifier}-${dasherize(rule.escapeValue)}-value`;
|
|
1542
|
+
const authored = node.attrs.find((attr) => attr.name === attrName);
|
|
1543
|
+
if (authored && (isDynamicValue(authored) || Number(authored.value.trim()) !== 0)) continue;
|
|
1544
|
+
}
|
|
1545
|
+
report(
|
|
1546
|
+
node,
|
|
1547
|
+
"missing-action-completion",
|
|
1548
|
+
"warning",
|
|
1549
|
+
`"${identifier}" opens a state with "${rule.opens}" here, and nothing in this scope closes it.`,
|
|
1550
|
+
node,
|
|
1551
|
+
rule.suggestion
|
|
1552
|
+
);
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1379
1555
|
for (const { node, identifier } of scopes) {
|
|
1380
1556
|
const controller = known[identifier];
|
|
1381
1557
|
if (!controller) continue;
|
|
@@ -1388,7 +1564,7 @@ function checkSource(source, manifest) {
|
|
|
1388
1564
|
if (!hasReadableMarkup(el)) continue;
|
|
1389
1565
|
if (!contentHolds(node, identifier, el, req.whenContains)) continue;
|
|
1390
1566
|
if (!elementHolds(el, req.whenElement)) continue;
|
|
1391
|
-
checkA11y(report, el, identifier, req, severity);
|
|
1567
|
+
checkA11y(report, el, identifier, req, severity, isDynamicValue);
|
|
1392
1568
|
}
|
|
1393
1569
|
}
|
|
1394
1570
|
}
|
|
@@ -1678,20 +1854,24 @@ function checkSource(source, manifest) {
|
|
|
1678
1854
|
return diagnostics;
|
|
1679
1855
|
}
|
|
1680
1856
|
function valueSatisfiesConstraint(raw, constraint) {
|
|
1857
|
+
if (constraint.type === "string") return constraint.allowedValues.includes(raw);
|
|
1681
1858
|
const value = decodeNumericValue(raw);
|
|
1682
1859
|
if (Number.isNaN(value)) return false;
|
|
1683
1860
|
if (constraint.finite && !Number.isFinite(value)) return false;
|
|
1684
1861
|
if (constraint.greaterThan !== void 0 && !(value > constraint.greaterThan)) return false;
|
|
1862
|
+
if (constraint.integer && !Number.isInteger(value)) return false;
|
|
1685
1863
|
return true;
|
|
1686
1864
|
}
|
|
1687
1865
|
function decodeNumericValue(raw) {
|
|
1688
1866
|
return Number(raw.replace(/_/g, ""));
|
|
1689
1867
|
}
|
|
1690
1868
|
function describeValueConstraint(constraint) {
|
|
1869
|
+
if (constraint.type === "string") return `one of ${list(constraint.allowedValues)}`;
|
|
1691
1870
|
const parts = [constraint.finite ? "a finite number" : "a number"];
|
|
1692
1871
|
if (constraint.greaterThan !== void 0) {
|
|
1693
1872
|
parts.push(`greater than ${constraint.greaterThan}`);
|
|
1694
1873
|
}
|
|
1874
|
+
if (constraint.integer) parts.push("with no fractional part");
|
|
1695
1875
|
return parts.join(" ");
|
|
1696
1876
|
}
|
|
1697
1877
|
var UNRESOLVED_TARGET_HINT = "Part of this scope is rendered by a helper or a non-literal data: hash, so the target may exist at runtime.";
|
|
@@ -1699,7 +1879,7 @@ var UNRESOLVED_HOST_HINT = "An enclosing helper's data: option is not a literal
|
|
|
1699
1879
|
function hasReadableMarkup(el) {
|
|
1700
1880
|
return el.origin === "markup";
|
|
1701
1881
|
}
|
|
1702
|
-
function checkA11y(report, el, identifier, req, severity) {
|
|
1882
|
+
function checkA11y(report, el, identifier, req, severity, isDynamicValue) {
|
|
1703
1883
|
const groups = [
|
|
1704
1884
|
{ attrs: req.attrs, values: req.values },
|
|
1705
1885
|
...req.or ?? []
|
|
@@ -1719,9 +1899,14 @@ function checkA11y(report, el, identifier, req, severity) {
|
|
|
1719
1899
|
}
|
|
1720
1900
|
const invalid = [];
|
|
1721
1901
|
let anyPresent = false;
|
|
1902
|
+
let blank;
|
|
1722
1903
|
for (const [name, allowed] of allowedByAttr) {
|
|
1723
1904
|
const attr = el.attrs.find((a) => a.name === name);
|
|
1724
1905
|
if (!attr) continue;
|
|
1906
|
+
if (allowed.anyValue && attr.value.trim() === "" && !isDynamicValue(attr)) {
|
|
1907
|
+
blank ??= attr;
|
|
1908
|
+
continue;
|
|
1909
|
+
}
|
|
1725
1910
|
anyPresent = true;
|
|
1726
1911
|
if (!allowed.anyValue && !allowed.values.has(attr.value.trim())) {
|
|
1727
1912
|
invalid.push({ attr, values: [...allowed.values] });
|
|
@@ -1733,8 +1918,8 @@ function checkA11y(report, el, identifier, req, severity) {
|
|
|
1733
1918
|
el,
|
|
1734
1919
|
"missing-aria",
|
|
1735
1920
|
severity,
|
|
1736
|
-
`"${identifier}" ${verb} ${describeAttrs([...allowedByAttr.keys()])} on its ${where}.`,
|
|
1737
|
-
el,
|
|
1921
|
+
blank ? `${blank.name} is empty on the ${where} of "${identifier}", which ${verb} a value there.` : `"${identifier}" ${verb} ${describeAttrs([...allowedByAttr.keys()])} on its ${where}.`,
|
|
1922
|
+
blank ?? el,
|
|
1738
1923
|
req.suggestion
|
|
1739
1924
|
);
|
|
1740
1925
|
return;
|
|
@@ -1936,6 +2121,8 @@ var CONTROLLER_ARRAY_FIELDS = [
|
|
|
1936
2121
|
"events",
|
|
1937
2122
|
"requiredTargets",
|
|
1938
2123
|
"conditionalTargets",
|
|
2124
|
+
"requiredActions",
|
|
2125
|
+
"actionCompletion",
|
|
1939
2126
|
"a11y",
|
|
1940
2127
|
"keyboard",
|
|
1941
2128
|
"hosts",
|
|
@@ -1998,10 +2185,16 @@ function collectFiles(target, out) {
|
|
|
1998
2185
|
}
|
|
1999
2186
|
if (isCheckableFile(target)) out.push(target);
|
|
2000
2187
|
}
|
|
2001
|
-
function checkFile(file, manifest) {
|
|
2002
|
-
const source = readFileSync(file, "utf8");
|
|
2188
|
+
function checkFile(file, source, manifest) {
|
|
2003
2189
|
return { file, diagnostics: checkSource(source, manifest) };
|
|
2004
2190
|
}
|
|
2191
|
+
function withAnnouncerSeating(reports, sources) {
|
|
2192
|
+
const seating = announcerSeatingDiagnostic(sources);
|
|
2193
|
+
if (!seating) return [...reports];
|
|
2194
|
+
return reports.map(
|
|
2195
|
+
(report) => report.file === seating.file ? { file: report.file, diagnostics: [...report.diagnostics, seating.diagnostic] } : report
|
|
2196
|
+
);
|
|
2197
|
+
}
|
|
2005
2198
|
function formatDiagnostic(d) {
|
|
2006
2199
|
const where = `${d.line}:${d.column}`.padEnd(7);
|
|
2007
2200
|
const head = ` ${where} ${d.severity.padEnd(7)} ${d.message} [${d.code}]`;
|
|
@@ -2134,13 +2327,14 @@ ${USAGE}`);
|
|
|
2134
2327
|
const manifest = load();
|
|
2135
2328
|
const cwd = process.cwd();
|
|
2136
2329
|
const reports = [];
|
|
2330
|
+
const sources = [];
|
|
2137
2331
|
for (const file of files.sort()) {
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2332
|
+
const path = relative(cwd, file) || file;
|
|
2333
|
+
const source = readFileSync(file, "utf8");
|
|
2334
|
+
sources.push({ file: path, source });
|
|
2335
|
+
reports.push(checkFile(path, source, manifest));
|
|
2142
2336
|
}
|
|
2143
|
-
const summary = buildCheckReport(reports, files.length);
|
|
2337
|
+
const summary = buildCheckReport(withAnnouncerSeating(reports, sources), files.length);
|
|
2144
2338
|
if (json) {
|
|
2145
2339
|
write(JSON.stringify(summary, null, 2));
|
|
2146
2340
|
return summary.errorCount > 0 ? 1 : 0;
|