From 186b8ebf20124dccc06d797723ee97320d89fbc9 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Thu, 11 May 2023 18:16:28 +0200 Subject: [PATCH] Lint and format src/compiler/compile/utils/a11y.js --- src/compiler/compile/utils/a11y.js | 452 +++++++++++++++-------------- 1 file changed, 237 insertions(+), 215 deletions(-) diff --git a/src/compiler/compile/utils/a11y.js b/src/compiler/compile/utils/a11y.js index 45463b6e4c..c21d8af0ce 100644 --- a/src/compiler/compile/utils/a11y.js +++ b/src/compiler/compile/utils/a11y.js @@ -4,52 +4,61 @@ import { regex_whitespaces } from '../../utils/patterns.js'; const aria_roles = roles_map.keys(); const abstract_roles = new Set(aria_roles.filter((role) => roles_map.get(role).abstract)); const non_abstract_roles = aria_roles.filter((name) => !abstract_roles.has(name)); -const non_interactive_roles = new Set(non_abstract_roles - .filter((name) => { - const role = roles_map.get(name); - return ( - // 'toolbar' does not descend from widget, but it does support - // aria-activedescendant, thus in practice we treat it as a widget. - // focusable tabpanel elements are recommended if any panels in a set contain content where the first element in the panel is not focusable. - // 'generic' is meant to have no semantic meaning. - !['toolbar', 'tabpanel', 'generic'].includes(name) && - !role.superClass.some((classes) => classes.includes('widget'))); -}) - .concat( -// The `progressbar` is descended from `widget`, but in practice, its -// value is always `readonly`, so we treat it as a non-interactive role. -'progressbar')); -const interactive_roles = new Set(non_abstract_roles.filter((name) => !non_interactive_roles.has(name) && - // 'generic' is meant to have no semantic meaning. - name !== 'generic')); +const non_interactive_roles = new Set( + non_abstract_roles + .filter((name) => { + const role = roles_map.get(name); + return ( + // 'toolbar' does not descend from widget, but it does support + // aria-activedescendant, thus in practice we treat it as a widget. + // focusable tabpanel elements are recommended if any panels in a set contain content where the first element in the panel is not focusable. + // 'generic' is meant to have no semantic meaning. + !['toolbar', 'tabpanel', 'generic'].includes(name) && + !role.superClass.some((classes) => classes.includes('widget')) + ); + }) + .concat( + // The `progressbar` is descended from `widget`, but in practice, its + // value is always `readonly`, so we treat it as a non-interactive role. + 'progressbar' + ) +); +const interactive_roles = new Set( + non_abstract_roles.filter( + (name) => + !non_interactive_roles.has(name) && + // 'generic' is meant to have no semantic meaning. + name !== 'generic' + ) +); /** -* @param {ARIARoleDefinitionKey} role + * @param {ARIARoleDefinitionKey} role */ export function is_non_interactive_roles(role) { - return non_interactive_roles.has(role); + return non_interactive_roles.has(role); } /** -* @param {ARIARoleDefinitionKey} role + * @param {ARIARoleDefinitionKey} role */ export function is_interactive_roles(role) { - return interactive_roles.has(role); + return interactive_roles.has(role); } /** -* @param {ARIARoleDefinitionKey} role + * @param {ARIARoleDefinitionKey} role */ export function is_abstract_role(role) { - return abstract_roles.has(role); + return abstract_roles.has(role); } const presentation_roles = new Set(['presentation', 'none']); /** -* @param {ARIARoleDefinitionKey} role + * @param {ARIARoleDefinitionKey} role */ export function is_presentation_role(role) { - return presentation_roles.has(role); + return presentation_roles.has(role); } /** @@ -57,80 +66,84 @@ export function is_presentation_role(role) { * @param {Map} attribute_map */ export function is_hidden_from_screen_reader(tag_name, attribute_map) { - if (tag_name === 'input') { - const type = attribute_map.get('type')?.get_static_value(); - if (type && type === 'hidden') { - return true; - } - } - const aria_hidden = attribute_map.get('aria-hidden'); - if (!aria_hidden) - return false; - if (!aria_hidden.is_static) - return true; - const aria_hidden_value = aria_hidden.get_static_value(); - return aria_hidden_value === true || aria_hidden_value === 'true'; + if (tag_name === 'input') { + const type = attribute_map.get('type')?.get_static_value(); + if (type && type === 'hidden') { + return true; + } + } + const aria_hidden = attribute_map.get('aria-hidden'); + if (!aria_hidden) return false; + if (!aria_hidden.is_static) return true; + const aria_hidden_value = aria_hidden.get_static_value(); + return aria_hidden_value === true || aria_hidden_value === 'true'; } /** -* @param {Map} attribute_map + * @param {Map} attribute_map */ export function has_disabled_attribute(attribute_map) { - const disabled_attr = attribute_map.get('disabled'); - const disabled_attr_value = disabled_attr && disabled_attr.get_static_value(); - if (disabled_attr_value) { - return true; - } - const aria_disabled_attr = attribute_map.get('aria-disabled'); - if (aria_disabled_attr) { - const aria_disabled_attr_value = aria_disabled_attr.get_static_value(); - if (aria_disabled_attr_value === true) { - return true; - } - } - return false; + const disabled_attr = attribute_map.get('disabled'); + const disabled_attr_value = disabled_attr && disabled_attr.get_static_value(); + if (disabled_attr_value) { + return true; + } + const aria_disabled_attr = attribute_map.get('aria-disabled'); + if (aria_disabled_attr) { + const aria_disabled_attr_value = aria_disabled_attr.get_static_value(); + if (aria_disabled_attr_value === true) { + return true; + } + } + return false; } /** -* @type {ARIARoleRelationConcept[]} + * @type {ARIARoleRelationConcept[]} */ const non_interactive_element_role_schemas = []; elementRoles.entries().forEach(([schema, roles]) => { - if ([...roles].every((role) => role !== 'generic' && non_interactive_roles.has(role))) { - non_interactive_element_role_schemas.push(schema); - } + if ([...roles].every((role) => role !== 'generic' && non_interactive_roles.has(role))) { + non_interactive_element_role_schemas.push(schema); + } }); /** -* @type {ARIARoleRelationConcept[]} + * @type {ARIARoleRelationConcept[]} */ const interactive_element_role_schemas = []; elementRoles.entries().forEach(([schema, roles]) => { - if ([...roles].every((role) => interactive_roles.has(role))) { - interactive_element_role_schemas.push(schema); - } + if ([...roles].every((role) => interactive_roles.has(role))) { + interactive_element_role_schemas.push(schema); + } }); -const interactive_ax_objects = new Set([...AXObjects.keys()].filter((name) => AXObjects.get(name).type === 'widget')); -const non_interactive_ax_objects = new Set([...AXObjects.keys()].filter((name) => ['windows', 'structure'].includes(AXObjects.get(name).type))); +const interactive_ax_objects = new Set( + [...AXObjects.keys()].filter((name) => AXObjects.get(name).type === 'widget') +); +const non_interactive_ax_objects = new Set( + [...AXObjects.keys()].filter((name) => + ['windows', 'structure'].includes(AXObjects.get(name).type) + ) +); /** -* @type {ARIARoleRelationConcept[]} + * @type {ARIARoleRelationConcept[]} */ const interactive_element_ax_object_schemas = []; elementAXObjects.entries().forEach(([schema, ax_object]) => { - if ([...ax_object].every((role) => interactive_ax_objects.has(role))) { - interactive_element_ax_object_schemas.push(schema); - } + if ([...ax_object].every((role) => interactive_ax_objects.has(role))) { + interactive_element_ax_object_schemas.push(schema); + } }); /** -* @type {ARIARoleRelationConcept[]} + * @type {ARIARoleRelationConcept[]} */ const non_interactive_element_ax_object_schemas = []; elementAXObjects.entries().forEach(([schema, ax_object]) => { - if ([...ax_object].every((role) => non_interactive_ax_objects.has(role))) { - non_interactive_element_ax_object_schemas.push(schema); - } + if ([...ax_object].every((role) => non_interactive_ax_objects.has(role))) { + non_interactive_element_ax_object_schemas.push(schema); + } }); /** @@ -139,25 +152,22 @@ elementAXObjects.entries().forEach(([schema, ax_object]) => { * @param {Map} attribute_map */ function match_schema(schema, tag_name, attribute_map) { - if (schema.name !== tag_name) - return false; - if (!schema.attributes) - return true; - return schema.attributes.every((schema_attribute) => { - const attribute = attribute_map.get(schema_attribute.name); - if (!attribute) - return false; - if (schema_attribute.value && schema_attribute.value !== attribute.get_static_value()) { - return false; - } - return true; - }); + if (schema.name !== tag_name) return false; + if (!schema.attributes) return true; + return schema.attributes.every((schema_attribute) => { + const attribute = attribute_map.get(schema_attribute.name); + if (!attribute) return false; + if (schema_attribute.value && schema_attribute.value !== attribute.get_static_value()) { + return false; + } + return true; + }); } export var ElementInteractivity; (function (ElementInteractivity) { - ElementInteractivity["Interactive"] = "interactive"; - ElementInteractivity["NonInteractive"] = "non-interactive"; - ElementInteractivity["Static"] = "static"; + ElementInteractivity['Interactive'] = 'interactive'; + ElementInteractivity['NonInteractive'] = 'non-interactive'; + ElementInteractivity['Static'] = 'static'; })(ElementInteractivity || (ElementInteractivity = {})); /** @@ -166,20 +176,34 @@ export var ElementInteractivity; * @returns {import("C:/repos/svelte/svelte/a11y.ts-to-jsdoc").ElementInteractivity} */ export function element_interactivity(tag_name, attribute_map) { - if (interactive_element_role_schemas.some((schema) => match_schema(schema, tag_name, attribute_map))) { - return ElementInteractivity.Interactive; - } - if (tag_name !== 'header' && - non_interactive_element_role_schemas.some((schema) => match_schema(schema, tag_name, attribute_map))) { - return ElementInteractivity.NonInteractive; - } - if (interactive_element_ax_object_schemas.some((schema) => match_schema(schema, tag_name, attribute_map))) { - return ElementInteractivity.Interactive; - } - if (non_interactive_element_ax_object_schemas.some((schema) => match_schema(schema, tag_name, attribute_map))) { - return ElementInteractivity.NonInteractive; - } - return ElementInteractivity.Static; + if ( + interactive_element_role_schemas.some((schema) => match_schema(schema, tag_name, attribute_map)) + ) { + return ElementInteractivity.Interactive; + } + if ( + tag_name !== 'header' && + non_interactive_element_role_schemas.some((schema) => + match_schema(schema, tag_name, attribute_map) + ) + ) { + return ElementInteractivity.NonInteractive; + } + if ( + interactive_element_ax_object_schemas.some((schema) => + match_schema(schema, tag_name, attribute_map) + ) + ) { + return ElementInteractivity.Interactive; + } + if ( + non_interactive_element_ax_object_schemas.some((schema) => + match_schema(schema, tag_name, attribute_map) + ) + ) { + return ElementInteractivity.NonInteractive; + } + return ElementInteractivity.Static; } /** @@ -188,7 +212,7 @@ export function element_interactivity(tag_name, attribute_map) { * @returns {boolean} */ export function is_interactive_element(tag_name, attribute_map) { - return element_interactivity(tag_name, attribute_map) === ElementInteractivity.Interactive; + return element_interactivity(tag_name, attribute_map) === ElementInteractivity.Interactive; } /** @@ -197,7 +221,7 @@ export function is_interactive_element(tag_name, attribute_map) { * @returns {boolean} */ export function is_non_interactive_element(tag_name, attribute_map) { - return element_interactivity(tag_name, attribute_map) === ElementInteractivity.NonInteractive; + return element_interactivity(tag_name, attribute_map) === ElementInteractivity.NonInteractive; } /** @@ -206,7 +230,7 @@ export function is_non_interactive_element(tag_name, attribute_map) { * @returns {boolean} */ export function is_static_element(tag_name, attribute_map) { - return element_interactivity(tag_name, attribute_map) === ElementInteractivity.Static; + return element_interactivity(tag_name, attribute_map) === ElementInteractivity.Static; } /** @@ -215,127 +239,125 @@ export function is_static_element(tag_name, attribute_map) { * @param {Map} attribute_map */ export function is_semantic_role_element(role, tag_name, attribute_map) { - for (const [schema, ax_object] of elementAXObjects.entries()) { - if (schema.name === tag_name && - (!schema.attributes || - schema.attributes.every((attr) => attribute_map.has(attr.name) && - attribute_map.get(attr.name).get_static_value() === attr.value))) { - for (const name of ax_object) { - const roles = AXObjectRoles.get(name); - if (roles) { - for (const { name } of roles) { - if (name === role) { - return true; - } - } - } - } - } - } - return false; + for (const [schema, ax_object] of elementAXObjects.entries()) { + if ( + schema.name === tag_name && + (!schema.attributes || + schema.attributes.every( + (attr) => + attribute_map.has(attr.name) && + attribute_map.get(attr.name).get_static_value() === attr.value + )) + ) { + for (const name of ax_object) { + const roles = AXObjectRoles.get(name); + if (roles) { + for (const { name } of roles) { + if (name === role) { + return true; + } + } + } + } + } + } + return false; } // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute const address_type_tokens = new Set(['shipping', 'billing']); const autofill_field_name_tokens = new Set([ - '', - 'on', - 'off', - 'name', - 'honorific-prefix', - 'given-name', - 'additional-name', - 'family-name', - 'honorific-suffix', - 'nickname', - 'username', - 'new-password', - 'current-password', - 'one-time-code', - 'organization-title', - 'organization', - 'street-address', - 'address-line1', - 'address-line2', - 'address-line3', - 'address-level4', - 'address-level3', - 'address-level2', - 'address-level1', - 'country', - 'country-name', - 'postal-code', - 'cc-name', - 'cc-given-name', - 'cc-additional-name', - 'cc-family-name', - 'cc-number', - 'cc-exp', - 'cc-exp-month', - 'cc-exp-year', - 'cc-csc', - 'cc-type', - 'transaction-currency', - 'transaction-amount', - 'language', - 'bday', - 'bday-day', - 'bday-month', - 'bday-year', - 'sex', - 'url', - 'photo' + '', + 'on', + 'off', + 'name', + 'honorific-prefix', + 'given-name', + 'additional-name', + 'family-name', + 'honorific-suffix', + 'nickname', + 'username', + 'new-password', + 'current-password', + 'one-time-code', + 'organization-title', + 'organization', + 'street-address', + 'address-line1', + 'address-line2', + 'address-line3', + 'address-level4', + 'address-level3', + 'address-level2', + 'address-level1', + 'country', + 'country-name', + 'postal-code', + 'cc-name', + 'cc-given-name', + 'cc-additional-name', + 'cc-family-name', + 'cc-number', + 'cc-exp', + 'cc-exp-month', + 'cc-exp-year', + 'cc-csc', + 'cc-type', + 'transaction-currency', + 'transaction-amount', + 'language', + 'bday', + 'bday-day', + 'bday-month', + 'bday-year', + 'sex', + 'url', + 'photo' ]); const contact_type_tokens = new Set(['home', 'work', 'mobile', 'fax', 'pager']); const autofill_contact_field_name_tokens = new Set([ - 'tel', - 'tel-country-code', - 'tel-national', - 'tel-area-code', - 'tel-local', - 'tel-local-prefix', - 'tel-local-suffix', - 'tel-extension', - 'email', - 'impp' + 'tel', + 'tel-country-code', + 'tel-national', + 'tel-area-code', + 'tel-local', + 'tel-local-prefix', + 'tel-local-suffix', + 'tel-extension', + 'email', + 'impp' ]); /** -* @param {null | true | string} autocomplete + * @param {null | true | string} autocomplete */ export function is_valid_autocomplete(autocomplete) { - if (autocomplete === true) { - return false; - } - else if (!autocomplete) { - return true; // dynamic value - } - const tokens = autocomplete.trim().toLowerCase().split(regex_whitespaces); - if (typeof tokens[0] === 'string' && tokens[0].startsWith('section-')) { - tokens.shift(); - } - if (address_type_tokens.has(tokens[0])) { - tokens.shift(); - } - if (autofill_field_name_tokens.has(tokens[0])) { - tokens.shift(); - } - else { - if (contact_type_tokens.has(tokens[0])) { - tokens.shift(); - } - if (autofill_contact_field_name_tokens.has(tokens[0])) { - tokens.shift(); - } - else { - return false; - } - } - if (tokens[0] === 'webauthn') { - tokens.shift(); - } - return tokens.length === 0; + if (autocomplete === true) { + return false; + } else if (!autocomplete) { + return true; // dynamic value + } + const tokens = autocomplete.trim().toLowerCase().split(regex_whitespaces); + if (typeof tokens[0] === 'string' && tokens[0].startsWith('section-')) { + tokens.shift(); + } + if (address_type_tokens.has(tokens[0])) { + tokens.shift(); + } + if (autofill_field_name_tokens.has(tokens[0])) { + tokens.shift(); + } else { + if (contact_type_tokens.has(tokens[0])) { + tokens.shift(); + } + if (autofill_contact_field_name_tokens.has(tokens[0])) { + tokens.shift(); + } else { + return false; + } + } + if (tokens[0] === 'webauthn') { + tokens.shift(); + } + return tokens.length === 0; } - - - -