A11yance / aria-query

Programmatic access to the ARIA specification

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

5.2 regression - `elementRoles` no longer works when `undefined` is passed

boris-petrov opened this issue · comments

I'm using ember-template-lint and it started blowing up with aria-query 5.2.1. It breaks on this line:

let implicitRoles = elementRoles.get(elementRoles.keys().find((key) => key.name === element))

elementRoles.keys().find((key) => key.name === element) returns undefined so get is called with undefined. That used to work in 5.1.3 (and returned undefined).

@boris-petrov what is the specific value for the key?

elementRoles.keys().find will return undefined if it finds nothing. If element doesn't match any key.name, then find will return undefined and get will try to find undefined.

ember-template-lint was never passing in the right type to the get method. In v5.0.2, the method looked like this:

get: function (key: ARIARoleRelationConcept): ?RoleSet {
const item = elementRoles.find(
tuple => JSON.stringify(tuple[0]) === JSON.stringify(key) ? true : false
);
return item && item[1];
},

The method expects an ARIARoleRelationConcept, which is defined here.

aria-query/flow/aria.js

Lines 335 to 344 in 7f1fd66

type ARIARoleRelationConcept = {
name: string,
attributes?: Array<ARIARoleRelationConceptAttribute>,
// These constraints are drawn from the mapping between ARIA and HTML:
// https://www.w3.org/TR/html-aria
constraints?: Array<'direct descendant of document'
| 'direct descendant of ol, ul or menu'
| 'direct descendant of details element with the open attribute defined'
| 'descendant of table'>,
};

The implementation in ember-template-lint happened to work because in aria-query@v5.0.2, the argument is passed to JSON.stringify, which would have returned "undefined" as a string.

In aria-query@5.2.1, the signature of the get method is unchanged, but the internal implementation is updated. If you pass in the same expected shape, it will return the same expected shape.

get: function (key: ARIARoleRelationConcept): ?RoleSet {
const item = elementRoles.find(tuple => (
key.name === tuple[0].name && dequal(key.attributes, tuple[0].attributes)
));
return item && item[1];
},

This implementation will explode if undefined is passed to the method, but undefined is an invalid type to pass to the method, so the error is expected.

This is a bug for ember-template-lint and their implementation of their rule. Feel free to link them here :) Here's how they can fix it:

if (element != null) {
  const implicitRoles = elementRoles.get(element);
  return implicitRoles && implicitRoles[0];
}
return null;

Thank you for the detailed response! I thought it might be a bug on their side but anyway wanted to mention that this is a change in behavior in aria-query. I'll let them know, thanks!