From c6d694526d8217fa7f1f7c6ed8b07da8949b660a Mon Sep 17 00:00:00 2001 From: David Mosher Date: Sun, 9 May 2021 13:58:48 -0400 Subject: [PATCH] add aria-proptype validation to compiler --- src/compiler/compile/nodes/Element.ts | 158 ++++++++++ .../input.svelte | 2 + .../warnings.json | 33 ++ .../a11y-aria-proptypes-global/input.svelte | 9 + .../a11y-aria-proptypes-global/warnings.json | 145 +++++++++ .../input.svelte | 4 + .../warnings.json | 65 ++++ .../input.svelte | 16 + .../warnings.json | 258 ++++++++++++++++ .../a11y-aria-proptypes-widget/input.svelte | 18 ++ .../a11y-aria-proptypes-widget/warnings.json | 289 ++++++++++++++++++ 11 files changed, 997 insertions(+) create mode 100644 test/validator/samples/a11y-aria-proptypes-drag-and-drop/input.svelte create mode 100644 test/validator/samples/a11y-aria-proptypes-drag-and-drop/warnings.json create mode 100644 test/validator/samples/a11y-aria-proptypes-global/input.svelte create mode 100644 test/validator/samples/a11y-aria-proptypes-global/warnings.json create mode 100644 test/validator/samples/a11y-aria-proptypes-live-region/input.svelte create mode 100644 test/validator/samples/a11y-aria-proptypes-live-region/warnings.json create mode 100644 test/validator/samples/a11y-aria-proptypes-relationship/input.svelte create mode 100644 test/validator/samples/a11y-aria-proptypes-relationship/warnings.json create mode 100644 test/validator/samples/a11y-aria-proptypes-widget/input.svelte create mode 100644 test/validator/samples/a11y-aria-proptypes-widget/warnings.json diff --git a/src/compiler/compile/nodes/Element.ts b/src/compiler/compile/nodes/Element.ts index c9529fcbcba..03d51b4e35b 100644 --- a/src/compiler/compile/nodes/Element.ts +++ b/src/compiler/compile/nodes/Element.ts @@ -26,6 +26,154 @@ const aria_attribute_set = new Set(aria_attributes); const aria_roles = 'alert alertdialog application article banner blockquote button caption cell checkbox code columnheader combobox complementary contentinfo definition deletion dialog directory document emphasis feed figure form generic graphics-document graphics-object graphics-symbol grid gridcell group heading img link list listbox listitem log main marquee math meter menu menubar menuitem menuitemcheckbox menuitemradio navigation none note option paragraph presentation progressbar radio radiogroup region row rowgroup rowheader scrollbar search searchbox separator slider spinbutton status strong subscript superscript switch tab table tablist tabpanel term textbox time timer toolbar tooltip tree treegrid treeitem'.split(' '); const aria_role_set = new Set(aria_roles); +const aria_attribute_value_type_map = new Map([ + // global attributes + // https://www.w3.org/TR/wai-aria/#global_states + ['current', { + type: 'token', + valid_values: 'page step location date time true false'.split(' ') + }], + ['disabled', { type: 'boolean'}], + ['haspopup', { + type: 'token', + valid_values: 'false true menu listbox tree grid dialog'.split(' ') + }], + ['hidden', { type: 'boolean_or_undefined' }], + ['invalid', { + type: 'token', + valid_values: 'grammar false spelling true'.split(' ') + }], + ['keyshortcuts', { type: 'string' }], + ['label', { type: 'string' }], + ['roledescription', { type: 'string' }], + + // widget attributes + // https://www.w3.org/TR/wai-aria/#attrs_widgets + ['autocomplete', { + type: 'token', + valid_values: 'inline list both none'.split(' ') + }], + ['checked', { type: 'tristate' }], + ['expanded', { type: 'boolean_or_undefined' }], + ['level', { type: 'integer' }], + ['modal', { type: 'boolean' }], + ['multiline', { type: 'boolean' }], + ['multiselectable', { type: 'boolean' }], + ['orientation', { + type: 'token', + valid_values: 'vertical undefined horizontal'.split(' ') + }], + ['placeholder', { type: 'string' }], + ['pressed', { type: 'tristate' }], + ['readonly', { type: 'boolean' }], + ['required', { type: 'boolean' }], + ['selected', { type: 'boolean_or_undefined' }], + ['sort', { + type: 'token', + valid_values: 'ascending descending none other'.split(' ') + }], + ['valuemax', { type: 'number' }], + ['valuemin', { type: 'number' }], + ['valuenow', { type: 'number' }], + ['valuetext', { type: 'string' }], + + // live region attributes + // https://www.w3.org/TR/wai-aria/#attrs_liveregions + ['atomic', { type: 'boolean' }], + ['busy', { type: 'boolean'}], + ['live', { + type: 'token', + valid_values: 'assertive off polite'.split(' ') + }], + ['relevant', { + type: 'tokenlist', + valid_values: 'additions all removals text'.split(' ') + }], + + // drag-and-drop attributes + // https://www.w3.org/TR/wai-aria/#attrs_dragdrop + ['dropeffect', { + type: 'tokenlist', + valid_values: 'copy execute link move none popup'.split(' ') + }], + ['grabbed', { type: 'boolean_or_undefined'}], + + // relationship-attributes + // https://www.w3.org/TR/wai-aria/#attrs_relationships + ['activedescendant', { type: 'id'}], + ['colcount', { type: 'integer'}], + ['colindex', { type: 'integer'}], + ['colspan', { type: 'integer'}], + ['controls', { type: 'idlist'}], + ['describedby', { type: 'idlist'}], + ['details', { type: 'id'}], + ['errormessage', { type: 'id'}], + ['flowto', { type: 'idlist'}], + ['labelledby', { type: 'idlist' }], + ['owns', { type: 'idlist' }], + ['posinset', { type: 'integer' }], + ['rowcount', { type: 'integer' }], + ['rowindex', { type: 'integer' }], + ['rowspan', { type: 'integer' }], + ['setsize', { type: 'integer' }] +]); + +function invalid_aria_attribute_value_message(mapping: any, attribute: string) { + switch (mapping.type) { + case 'tristate': + return `The value for the aria attribute '${attribute}' must be exactly one of true, false, or mixed`; + case 'token': + return `The value for the aria attribute '${attribute}' must be exactly one of ${mapping.valid_values.join(', ')}`; + case 'tokenlist': + return `The value for the aria attribute '${attribute}' must be a space-separated list of one or more of ${mapping.valid_values.join(', ')}`; + case 'idlist': + // TODO: (smart-idlist) should we make this idlist dynamic? + return `The value for the aria attribute '${attribute}' must be a space-separated list of strings that represent DOM element IDs`; + case 'id': + return `The value for the aria attribute '${attribute}' must be a string that represents a DOM element ID`; + case 'boolean_or_undefined': + return `The value for the aria attribute '${attribute}' must be exactly one of true, false, or undefined`; + case 'boolean': + return `The value for the aria attribute '${attribute}' must be exactly one of true or false`; + case 'string': + case 'integer': + case 'number': + default: + return `The value for the aria attribute '${attribute}' must be of type ${mapping.type}`; + } +} + +function is_boolean(value: any): boolean { + return typeof value === 'boolean' || value === 'true' || value === 'false'; +} + +function valid_aria_attribute_value(mapping: any, value: any): boolean { + switch (mapping.type) { + case 'boolean': + return is_boolean(value); + case 'boolean_or_undefined': + return is_boolean(value) || value == null; + case 'string': + case 'id': + return typeof value === 'string'; + case 'tristate': + return value === 'true' || value === 'false' || value === 'mixed'; + case 'integer': + case 'number': + return typeof value !== 'boolean' && isNaN(Number(value)) === false; + case 'token': + return mapping.valid_values.indexOf(typeof value === 'string' ? value.toLowerCase() : value) > -1; + case 'idlist': + // TODO: (smart-idlist) should we make this idlist verification dynamic based on the ids present + // in the direct parent component that this element is contained within? + return typeof value === 'string' && value.split(' ').every((id) => typeof id === 'string'); + case 'tokenlist': + return typeof value === 'string' && value.split(' ').every((token) => mapping.valid_values.indexOf(token.toLowerCase()) > -1); + default: + return false; + } +} + const a11y_required_attributes = { a: ['href'], area: ['alt', 'aria-label', 'aria-labelledby'], @@ -367,6 +515,16 @@ export default class Element extends Node { message: `A11y: <${this.name}> element should not be hidden` }); } + + // aria-proptypes + const value = attribute.get_static_value(); + const aria_attribute_type_mapping = aria_attribute_value_type_map.get(type); + if (aria_attribute_type_mapping && !valid_aria_attribute_value(aria_attribute_type_mapping, value)) { + component.warn(attribute, { + code: 'a11y-invalid-aria-attribute-value', + message: `A11y: ${invalid_aria_attribute_value_message(aria_attribute_type_mapping, name)}` + }); + } } // aria-role diff --git a/test/validator/samples/a11y-aria-proptypes-drag-and-drop/input.svelte b/test/validator/samples/a11y-aria-proptypes-drag-and-drop/input.svelte new file mode 100644 index 00000000000..13a273ee4e4 --- /dev/null +++ b/test/validator/samples/a11y-aria-proptypes-drag-and-drop/input.svelte @@ -0,0 +1,2 @@ +foo +foo \ No newline at end of file diff --git a/test/validator/samples/a11y-aria-proptypes-drag-and-drop/warnings.json b/test/validator/samples/a11y-aria-proptypes-drag-and-drop/warnings.json new file mode 100644 index 00000000000..1c3b1dd0406 --- /dev/null +++ b/test/validator/samples/a11y-aria-proptypes-drag-and-drop/warnings.json @@ -0,0 +1,33 @@ +[ + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 45, + "column": 45, + "line": 1 + }, + "message": "A11y: The value for the aria attribute 'aria-dropeffect' must be a space-separated list of one or more of copy, execute, link, move, none, popup", + "pos": 6, + "start": { + "character": 6, + "column": 6, + "line": 1 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 81, + "column": 24, + "line": 2 + }, + "message": "A11y: The value for the aria attribute 'aria-grabbed' must be exactly one of true, false, or undefined", + "pos": 63, + "start": { + "character": 63, + "column": 6, + "line": 2 + } + } +] \ No newline at end of file diff --git a/test/validator/samples/a11y-aria-proptypes-global/input.svelte b/test/validator/samples/a11y-aria-proptypes-global/input.svelte new file mode 100644 index 00000000000..0df9a37ba71 --- /dev/null +++ b/test/validator/samples/a11y-aria-proptypes-global/input.svelte @@ -0,0 +1,9 @@ +foo +foo +foo +foo +foo +foo +foo +foo +foo \ No newline at end of file diff --git a/test/validator/samples/a11y-aria-proptypes-global/warnings.json b/test/validator/samples/a11y-aria-proptypes-global/warnings.json new file mode 100644 index 00000000000..29f05430804 --- /dev/null +++ b/test/validator/samples/a11y-aria-proptypes-global/warnings.json @@ -0,0 +1,145 @@ +[ + { + "code": "a11y-invalid-aria-attribute-value", + "message": "A11y: The value for the aria attribute 'aria-hidden' must be exactly one of true, false, or undefined", + "start": { + "line": 1, + "column": 6, + "character": 6 + }, + "end": { + "line": 1, + "column": 23, + "character": 23 + }, + "pos": 6 + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 73, + "column": 38, + "line": 2 + }, + "message": "A11y: The value for the aria attribute 'aria-current' must be exactly one of page, step, location, date, time, true, false", + "pos": 41, + "start": { + "character": 41, + "column": 6, + "line": 2 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "message": "A11y: The value for the aria attribute 'aria-details' must be a string that represents a DOM element ID", + "start": { + "line": 3, + "column": 6, + "character": 91 + }, + "end": { + "line": 3, + "column": 18, + "character": 103 + }, + "pos": 91 + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 140, + "column": 25, + "line": 4 + }, + "message": "A11y: The value for the aria attribute 'aria-disabled' must be exactly one of true or false", + "pos": 121, + "start": { + "character": 121, + "column": 6, + "line": 4 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 186, + "column": 34, + "line": 5 + }, + "message": "A11y: The value for the aria attribute 'aria-haspopup' must be exactly one of false, true, menu, listbox, tree, grid, dialog", + "pos": 158, + "start": { + "character": 158, + "column": 6, + "line": 5 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 235, + "column": 37, + "line": 6 + }, + "message": "A11y: The value for the aria attribute 'aria-invalid' must be exactly one of grammar, false, spelling, true", + "pos": 204, + "start": { + "character": 204, + "column": 6, + "line": 6 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 270, + "column": 23, + "line": 7 + }, + "message": "A11y: The value for the aria attribute 'aria-keyshortcuts' must be of type string", + "pos": 253, + "start": { + "character": 253, + "column": 6, + "line": 7 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 298, + "column": 16, + "line": 8 + }, + "message": "A11y: The value for the aria attribute 'aria-label' must be of type string", + "pos": 288, + "start": { + "character": 288, + "column": 6, + "line": 8 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 336, + "column": 26, + "line": 9 + }, + "message": "A11y: The value for the aria attribute 'aria-roledescription' must be of type string", + "pos": 316, + "start": { + "character": 316, + "column": 6, + "line": 9 + } + } +] \ No newline at end of file diff --git a/test/validator/samples/a11y-aria-proptypes-live-region/input.svelte b/test/validator/samples/a11y-aria-proptypes-live-region/input.svelte new file mode 100644 index 00000000000..d522d0f8ead --- /dev/null +++ b/test/validator/samples/a11y-aria-proptypes-live-region/input.svelte @@ -0,0 +1,4 @@ +foo +foo +foo +foo \ No newline at end of file diff --git a/test/validator/samples/a11y-aria-proptypes-live-region/warnings.json b/test/validator/samples/a11y-aria-proptypes-live-region/warnings.json new file mode 100644 index 00000000000..5338204eb36 --- /dev/null +++ b/test/validator/samples/a11y-aria-proptypes-live-region/warnings.json @@ -0,0 +1,65 @@ +[ + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 23, + "column": 23, + "line": 1 + }, + "message": "A11y: The value for the aria attribute 'aria-atomic' must be exactly one of true or false", + "pos": 6, + "start": { + "character": 6, + "column": 6, + "line": 1 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 56, + "column": 21, + "line": 2 + }, + "message": "A11y: The value for the aria attribute 'aria-busy' must be exactly one of true or false", + "pos": 41, + "start": { + "character": 41, + "column": 6, + "line": 2 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 102, + "column": 34, + "line": 3 + }, + "message": "A11y: The value for the aria attribute 'aria-live' must be exactly one of assertive, off, polite", + "pos": 74, + "start": { + "character": 74, + "column": 6, + "line": 3 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 163, + "column": 49, + "line": 4 + }, + "message": "A11y: The value for the aria attribute 'aria-relevant' must be a space-separated list of one or more of additions, all, removals, text", + "pos": 120, + "start": { + "character": 120, + "column": 6, + "line": 4 + } + } +] \ No newline at end of file diff --git a/test/validator/samples/a11y-aria-proptypes-relationship/input.svelte b/test/validator/samples/a11y-aria-proptypes-relationship/input.svelte new file mode 100644 index 00000000000..113fa906526 --- /dev/null +++ b/test/validator/samples/a11y-aria-proptypes-relationship/input.svelte @@ -0,0 +1,16 @@ +foo +foo +foo +foo +foo +foo +foo +foo +foo +foo +foo +foo +foo +foo +foo +foo \ No newline at end of file diff --git a/test/validator/samples/a11y-aria-proptypes-relationship/warnings.json b/test/validator/samples/a11y-aria-proptypes-relationship/warnings.json new file mode 100644 index 00000000000..073ce8f44e4 --- /dev/null +++ b/test/validator/samples/a11y-aria-proptypes-relationship/warnings.json @@ -0,0 +1,258 @@ +[ + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 27, + "column": 27, + "line": 1 + }, + "message": "A11y: The value for the aria attribute 'aria-activedescendant' must be a string that represents a DOM element ID", + "pos": 6, + "start": { + "character": 6, + "column": 6, + "line": 1 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 64, + "column": 25, + "line": 2 + }, + "message": "A11y: The value for the aria attribute 'aria-colcount' must be of type integer", + "pos": 45, + "start": { + "character": 45, + "column": 6, + "line": 2 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 101, + "column": 25, + "line": 3 + }, + "message": "A11y: The value for the aria attribute 'aria-colindex' must be of type integer", + "pos": 82, + "start": { + "character": 82, + "column": 6, + "line": 3 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 137, + "column": 24, + "line": 4 + }, + "message": "A11y: The value for the aria attribute 'aria-colspan' must be of type integer", + "pos": 119, + "start": { + "character": 119, + "column": 6, + "line": 4 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 168, + "column": 19, + "line": 5 + }, + "message": "A11y: The value for the aria attribute 'aria-controls' must be a space-separated list of strings that represent DOM element IDs", + "pos": 155, + "start": { + "character": 155, + "column": 6, + "line": 5 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 202, + "column": 22, + "line": 6 + }, + "message": "A11y: The value for the aria attribute 'aria-describedby' must be a space-separated list of strings that represent DOM element IDs", + "pos": 186, + "start": { + "character": 186, + "column": 6, + "line": 6 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 232, + "column": 18, + "line": 7 + }, + "message": "A11y: The value for the aria attribute 'aria-details' must be a string that represents a DOM element ID", + "pos": 220, + "start": { + "character": 220, + "column": 6, + "line": 7 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 267, + "column": 23, + "line": 8 + }, + "message": "A11y: The value for the aria attribute 'aria-errormessage' must be a string that represents a DOM element ID", + "pos": 250, + "start": { + "character": 250, + "column": 6, + "line": 8 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 296, + "column": 17, + "line": 9 + }, + "message": "A11y: The value for the aria attribute 'aria-flowto' must be a space-separated list of strings that represent DOM element IDs", + "pos": 285, + "start": { + "character": 285, + "column": 6, + "line": 9 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 329, + "column": 21, + "line": 10 + }, + "message": "A11y: The value for the aria attribute 'aria-labelledby' must be a space-separated list of strings that represent DOM element IDs", + "pos": 314, + "start": { + "character": 314, + "column": 6, + "line": 10 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 356, + "column": 15, + "line": 11 + }, + "message": "A11y: The value for the aria attribute 'aria-owns' must be a space-separated list of strings that represent DOM element IDs", + "pos": 347, + "start": { + "character": 347, + "column": 6, + "line": 11 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 393, + "column": 25, + "line": 12 + }, + "message": "A11y: The value for the aria attribute 'aria-posinset' must be of type integer", + "pos": 374, + "start": { + "character": 374, + "column": 6, + "line": 12 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 430, + "column": 25, + "line": 13 + }, + "message": "A11y: The value for the aria attribute 'aria-rowcount' must be of type integer", + "pos": 411, + "start": { + "character": 411, + "column": 6, + "line": 13 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 467, + "column": 25, + "line": 14 + }, + "message": "A11y: The value for the aria attribute 'aria-rowindex' must be of type integer", + "pos": 448, + "start": { + "character": 448, + "column": 6, + "line": 14 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 503, + "column": 24, + "line": 15 + }, + "message": "A11y: The value for the aria attribute 'aria-rowspan' must be of type integer", + "pos": 485, + "start": { + "character": 485, + "column": 6, + "line": 15 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 539, + "column": 24, + "line": 16 + }, + "message": "A11y: The value for the aria attribute 'aria-setsize' must be of type integer", + "pos": 521, + "start": { + "character": 521, + "column": 6, + "line": 16 + } + } +] + diff --git a/test/validator/samples/a11y-aria-proptypes-widget/input.svelte b/test/validator/samples/a11y-aria-proptypes-widget/input.svelte new file mode 100644 index 00000000000..fb7a1ce06b6 --- /dev/null +++ b/test/validator/samples/a11y-aria-proptypes-widget/input.svelte @@ -0,0 +1,18 @@ +foo +foo +foo +foo +foo +foo +foo +foo +foo +foo +foo +foo +foo +foo +foo +foo +foo +foo diff --git a/test/validator/samples/a11y-aria-proptypes-widget/warnings.json b/test/validator/samples/a11y-aria-proptypes-widget/warnings.json new file mode 100644 index 00000000000..b2271bd0270 --- /dev/null +++ b/test/validator/samples/a11y-aria-proptypes-widget/warnings.json @@ -0,0 +1,289 @@ +[ + { + "code": "a11y-invalid-aria-attribute-value", + "message": "A11y: The value for the aria attribute 'aria-autocomplete' must be exactly one of inline, list, both, none", + "start": { + "line": 1, + "column": 6, + "character": 6 + }, + "end": { + "line": 1, + "column": 29, + "character": 29 + }, + "pos": 6 + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 65, + "column": 24, + "line": 2 + }, + "message": "A11y: The value for the aria attribute 'aria-checked' must be exactly one of true, false, or mixed", + "pos": 47, + "start": { + "character": 47, + "column": 6, + "line": 2 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 102, + "column": 25, + "line": 3 + }, + "message": "A11y: The value for the aria attribute 'aria-expanded' must be exactly one of true, false, or undefined", + "pos": 83, + "start": { + "character": 83, + "column": 6, + "line": 3 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 136, + "column": 22, + "line": 4 + }, + "message": "A11y: The value for the aria attribute 'aria-level' must be of type integer", + "pos": 120, + "start": { + "character": 120, + "column": 6, + "line": 4 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 170, + "column": 22, + "line": 5 + }, + "message": "A11y: The value for the aria attribute 'aria-modal' must be exactly one of true or false", + "pos": 154, + "start": { + "character": 154, + "column": 6, + "line": 5 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 208, + "column": 26, + "line": 6 + }, + "message": "A11y: The value for the aria attribute 'aria-multiline' must be exactly one of true or false", + "pos": 188, + "start": { + "character": 188, + "column": 6, + "line": 6 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 252, + "column": 32, + "line": 7 + }, + "message": "A11y: The value for the aria attribute 'aria-multiselectable' must be exactly one of true or false", + "pos": 226, + "start": { + "character": 226, + "column": 6, + "line": 7 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 308, + "column": 44, + "line": 8 + }, + "message": "A11y: The value for the aria attribute 'aria-orientation' must be exactly one of vertical, undefined, horizontal", + "pos": 270, + "start": { + "character": 270, + "column": 6, + "line": 8 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 342, + "column": 22, + "line": 9 + }, + "message": "A11y: The value for the aria attribute 'aria-placeholder' must be of type string", + "pos": 326, + "start": { + "character": 326, + "column": 6, + "line": 9 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 378, + "column": 24, + "line": 10 + }, + "message": "A11y: The value for the aria attribute 'aria-pressed' must be exactly one of true, false, or mixed", + "pos": 360, + "start": { + "character": 360, + "column": 6, + "line": 10 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 415, + "column": 25, + "line": 11 + }, + "message": "A11y: The value for the aria attribute 'aria-readonly' must be exactly one of true or false", + "pos": 396, + "start": { + "character": 396, + "column": 6, + "line": 11 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 452, + "column": 25, + "line": 12 + }, + "message": "A11y: The value for the aria attribute 'aria-required' must be exactly one of true or false", + "pos": 433, + "start": { + "character": 433, + "column": 6, + "line": 12 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 489, + "column": 25, + "line": 13 + }, + "message": "A11y: The value for the aria attribute 'aria-selected' must be exactly one of true, false, or undefined", + "pos": 470, + "start": { + "character": 470, + "column": 6, + "line": 13 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 539, + "column": 38, + "line": 14 + }, + "message": "A11y: The value for the aria attribute 'aria-sort' must be exactly one of ascending, descending, none, other", + "pos": 507, + "start": { + "character": 507, + "column": 6, + "line": 14 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 576, + "column": 25, + "line": 15 + }, + "message": "A11y: The value for the aria attribute 'aria-valuemax' must be of type number", + "pos": 557, + "start": { + "character": 557, + "column": 6, + "line": 15 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 613, + "column": 25, + "line": 16 + }, + "message": "A11y: The value for the aria attribute 'aria-valuemin' must be of type number", + "pos": 594, + "start": { + "character": 594, + "column": 6, + "line": 16 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 650, + "column": 25, + "line": 17 + }, + "message": "A11y: The value for the aria attribute 'aria-valuenow' must be of type number", + "pos": 631, + "start": { + "character": 631, + "column": 6, + "line": 17 + } + }, + + { + "code": "a11y-invalid-aria-attribute-value", + "end": { + "character": 682, + "column": 20, + "line": 18 + }, + "message": "A11y: The value for the aria attribute 'aria-valuetext' must be of type string", + "pos": 668, + "start": { + "character": 668, + "column": 6, + "line": 18 + } + } +]