chrome-devtools-frontend
Version:
Chrome DevTools UI
113 lines (108 loc) • 5.23 kB
text/typescript
// Copyright 2025 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview A library to identify and templatize UI.ARIAUtils calls.
*/
import type {TSESTree} from '@typescript-eslint/utils';
import {isIdentifier, isIdentifierChain, isMemberExpression} from './ast.ts';
import type {DomFragment} from './dom-fragment.ts';
type Node = TSESTree.Node;
type CallExpression = TSESTree.CallExpression;
type Identifier = TSESTree.Identifier;
export const ariaUtils = {
create(_) {
return {
functionCall(call: CallExpression, _firstArg: Node, secondArg: Node, domFragment: DomFragment): boolean {
const func = isMemberExpression(
call.callee, n => isIdentifierChain(n, ['UI', 'ARIAUtils']), n => n.type === 'Identifier');
if (!func) {
return false;
}
if (isIdentifier(func, [
'markAsAlert', 'markAsApplication', 'markAsButton', 'markAsCheckbox',
'markAsCombobox', 'markAsComplementary', 'markAsGroup', 'markAsHeading',
'markAsLink', 'markAsList', 'markAsListBox', 'markAsListItem',
'markAsMain', 'markAsMenu', 'markAsMenuItem', 'markAsMenuItemCheckBox',
'markAsNavigation', 'markAsOption', 'markAsPresentation', 'markAsProgressBar',
'markAsRadioGroup', 'markAsSlider', 'markAsStatus', 'markAsTab',
'markAsTablist', 'markAsTabpanel', 'markAsTextbox', 'markAsTree',
'markAsTreeitem',
])) {
domFragment.attributes.push({
key: 'role',
value: (func as Identifier).name.substr('markAs'.length).toLowerCase(),
});
if (isIdentifier(func, 'markAsAlert')) {
domFragment.attributes.push({
key: 'aria-live',
value: 'polite',
});
} else if (isIdentifier(func, ['markAsProgressBar', 'markAsSlider'])) {
domFragment.attributes.push({key: 'aria-valuemin', value: call.arguments[1] ?? '0'});
domFragment.attributes.push({key: 'aria-valuemax', value: call.arguments[2] ?? '100'});
} else if (isIdentifier(func, 'markAsHeading')) {
domFragment.attributes.push({key: 'aria-level', value: secondArg});
}
} else if (isIdentifier(func, 'markAsModalDialog')) {
domFragment.attributes.push({key: 'role', value: 'dialog'});
domFragment.attributes.push({key: 'aria-modal', value: 'true'});
} else if (isIdentifier(func, 'markAsMenuButton')) {
domFragment.attributes.push({key: 'role', value: 'button'});
domFragment.attributes.push({key: 'aria-haspopup', value: 'true'});
} else if (isIdentifier(func, 'markAsMenuItemSubMenu')) {
domFragment.attributes.push({key: 'role', value: 'menuitem'});
domFragment.attributes.push({key: 'aria-haspopup', value: 'true'});
} else if (isIdentifier(func, 'markAsPoliteLiveRegion')) {
domFragment.attributes.push({key: 'aria-live', value: 'polite'});
domFragment.attributes.push({key: 'aria-atomic', value: secondArg});
} else if (isIdentifier(func, [
'setAutocomplete', 'setChecked', 'setDescription', 'setDisabled', 'setExpanded', 'setHasPopup',
'setHidden', 'setInvalid', 'setLabel', 'setLevel', 'setPlaceholder', 'setPressed', 'setSelected',
'setSetSize', 'setValueNow', 'setValueText'
])) {
domFragment.attributes.push({
key: `aria-${(func as Identifier).name.substr('set'.length).toLowerCase()}`,
value: secondArg,
});
} else if (isIdentifier(func, 'setPositionInSet')) {
domFragment.attributes.push({
key: 'aria-posinset',
value: secondArg,
});
} else if (isIdentifier(func, 'setCheckboxAsIndeterminate')) {
domFragment.attributes.push({
key: 'aria-checked',
value: 'mixed',
});
} else if (isIdentifier(func, 'setProgressBarValue')) {
domFragment.attributes.push({key: 'aria-valuenow', value: secondArg});
const valueText = call.arguments[2];
if (valueText) {
domFragment.attributes.push({
key: 'aria-valuetext',
value: valueText,
});
}
} else if (isIdentifier(func, ['setAriaValueNow', 'setAriaValueText'])) {
domFragment.attributes.push({
key: `aria-${(func as Identifier).name.substr('setAria'.length).toLowerCase()}`,
value: secondArg,
});
} else if (isIdentifier(func, 'setAriaValueMinMax')) {
domFragment.attributes.push({
key: 'aria-valuemin',
value: call.arguments[1],
});
domFragment.attributes.push({
key: 'aria-valuemax',
value: call.arguments[2],
});
} else {
return false;
}
return true;
},
};
}
};