mirror of
https://github.com/github/codeql-action.git
synced 2025-12-26 17:20:10 +08:00
* Bump the npm group with 3 updates Bumps the npm group with 3 updates: [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin), [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) and [eslint-plugin-github](https://github.com/github/eslint-plugin-github). Updates `@typescript-eslint/eslint-plugin` from 6.7.2 to 6.7.3 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.7.3/packages/eslint-plugin) Updates `@typescript-eslint/parser` from 6.7.2 to 6.7.3 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.7.3/packages/parser) Updates `eslint-plugin-github` from 4.10.0 to 4.10.1 - [Release notes](https://github.com/github/eslint-plugin-github/releases) - [Commits](https://github.com/github/eslint-plugin-github/compare/v4.10.0...v4.10.1) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm - dependency-name: "@typescript-eslint/parser" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm - dependency-name: eslint-plugin-github dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm ... Signed-off-by: dependabot[bot] <support@github.com> * Update checked-in dependencies --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Angela P Wen <angelapwen@github.com>
112 lines
4.1 KiB
JavaScript
112 lines
4.1 KiB
JavaScript
const {getProp, getLiteralPropValue} = require('jsx-ast-utils')
|
||
const {elementRoles} = require('aria-query')
|
||
const {getElementType} = require('./get-element-type')
|
||
const ObjectMap = require('./object-map')
|
||
|
||
const elementRolesMap = cleanElementRolesMap()
|
||
|
||
/*
|
||
Returns an element roles map which uses `aria-query`'s elementRoles as the foundation.
|
||
We additionally clean the data so we're able to fetch a role using a key we construct based on the node we're looking at.
|
||
In a few scenarios, we stray from the roles returned by `aria-query` and hard code the mapping.
|
||
*/
|
||
function cleanElementRolesMap() {
|
||
const rolesMap = new ObjectMap()
|
||
|
||
for (const [key, value] of elementRoles.entries()) {
|
||
// - Remove empty `attributes` key
|
||
if (!key.attributes || key.attributes?.length === 0) {
|
||
delete key.attributes
|
||
}
|
||
rolesMap.set(key, value)
|
||
}
|
||
// Remove insufficiently-disambiguated `menuitem` entry
|
||
rolesMap.delete({name: 'menuitem'})
|
||
// Disambiguate `menuitem` and `menu` roles by `type`
|
||
rolesMap.set({name: 'menuitem', attributes: [{name: 'type', value: 'command'}]}, ['menuitem'])
|
||
rolesMap.set({name: 'menuitem', attributes: [{name: 'type', value: 'radio'}]}, ['menuitemradio'])
|
||
rolesMap.set({name: 'menuitem', attributes: [{name: 'type', value: 'toolbar'}]}, ['toolbar'])
|
||
rolesMap.set({name: 'menu', attributes: [{name: 'type', value: 'toolbar'}]}, ['toolbar'])
|
||
|
||
/* These have constraints defined in aria-query's `elementRoles` which depend on knowledge of ancestor roles which we cant accurately determine in a linter context.
|
||
However, we benefit more from assuming the role, than assuming it's generic or undefined so we opt to hard code the mapping */
|
||
rolesMap.set({name: 'aside'}, ['complementary']) // `aside` still maps to `complementary` in https://www.w3.org/TR/html-aria/#docconformance.
|
||
rolesMap.set({name: 'li'}, ['listitem']) // `li` can be generic if it's not within a list but we would never want to render `li` outside of a list.
|
||
|
||
return rolesMap
|
||
}
|
||
|
||
/*
|
||
Determine role of an element, based on its name and attributes.
|
||
We construct a key and look up the element's role in `elementRolesMap`.
|
||
If there is no match, we return undefined.
|
||
*/
|
||
function getRole(context, node) {
|
||
// Early return if role is explicitly set
|
||
const explicitRole = getLiteralPropValue(getProp(node.attributes, 'role'))
|
||
if (explicitRole) {
|
||
return explicitRole
|
||
} else if (getProp(node.attributes, 'role')) {
|
||
// If role is set to anything other than a literal prop
|
||
return undefined
|
||
}
|
||
|
||
// Assemble a key for looking-up the element’s role in the `elementRolesMap`
|
||
// - Get the element’s name
|
||
const key = {name: getElementType(context, node)}
|
||
|
||
for (const prop of [
|
||
'aria-label',
|
||
'aria-labelledby',
|
||
'alt',
|
||
'type',
|
||
'size',
|
||
'role',
|
||
'href',
|
||
'multiple',
|
||
'scope',
|
||
'name',
|
||
]) {
|
||
if ((prop === 'aria-labelledby' || prop === 'aria-label') && !['section', 'form'].includes(key.name)) continue
|
||
if (prop === 'name' && key.name !== 'form') continue
|
||
if (prop === 'href' && key.name !== 'a' && key.name !== 'area') continue
|
||
if (prop === 'alt' && key.name !== 'img') continue
|
||
|
||
const propOnNode = getProp(node.attributes, prop)
|
||
|
||
if (!('attributes' in key)) {
|
||
key.attributes = []
|
||
}
|
||
// Disambiguate "undefined" props
|
||
if (propOnNode === undefined && prop === 'alt' && key.name === 'img') {
|
||
key.attributes.push({name: prop, constraints: ['undefined']})
|
||
continue
|
||
}
|
||
|
||
const value = getLiteralPropValue(propOnNode)
|
||
if (propOnNode) {
|
||
if (
|
||
prop === 'href' ||
|
||
prop === 'aria-labelledby' ||
|
||
prop === 'aria-label' ||
|
||
prop === 'name' ||
|
||
(prop === 'alt' && value !== '')
|
||
) {
|
||
key.attributes.push({name: prop, constraints: ['set']})
|
||
} else if (value || (value === '' && prop === 'alt')) {
|
||
key.attributes.push({name: prop, value})
|
||
}
|
||
}
|
||
}
|
||
|
||
// - Remove empty `attributes` key
|
||
if (!key.attributes || key.attributes?.length === 0) {
|
||
delete key.attributes
|
||
}
|
||
|
||
// Get the element’s implicit role
|
||
return elementRolesMap.get(key)?.[0]
|
||
}
|
||
|
||
module.exports = {getRole}
|