Update checked-in dependencies

This commit is contained in:
github-actions[bot]
2023-07-13 09:09:17 +00:00
parent 4fad06f438
commit 40a500c743
4168 changed files with 298222 additions and 374905 deletions

View File

@@ -0,0 +1,31 @@
const {getProp} = require('jsx-ast-utils')
module.exports = {
meta: {
docs: {
description: '[aria-label] text should be formatted as you would visual text.',
url: require('../url')(module),
},
schema: [],
},
create(context) {
return {
JSXOpeningElement: node => {
const prop = getProp(node.attributes, 'aria-label')
if (!prop) return
const propValue = prop.value
if (propValue.type !== 'Literal') return
const ariaLabel = propValue.value
if (ariaLabel.match(/^[a-z]+.*$/)) {
context.report({
node,
message: '[aria-label] text should be formatted the same as you would visual text. Use sentence case.',
})
}
},
}
},
}

View File

@@ -16,9 +16,11 @@ module.exports = {
meta: {
docs: {
description: 'disallow generic link text',
url: require('../url')(module)
url: require('../url')(module),
},
schema: []
deprecated: true,
replacedBy: ['jsx-a11y/anchor-ambiguous-text'],
schema: [],
},
create(context) {
@@ -46,13 +48,13 @@ module.exports = {
context.report({
node,
message:
'Avoid setting generic link text like `Here`, `Click here`, `Read more`. Make sure that your link text is both descriptive and concise.'
'Avoid setting generic link text like `Here`, `Click here`, `Read more`. Make sure that your link text is both descriptive and concise.',
})
}
if (cleanTextContent && !cleanAriaLabelValue.includes(cleanTextContent)) {
context.report({
node,
message: 'When using ARIA to set a more descriptive text, it must fully contain the visible label.'
message: 'When using ARIA to set a more descriptive text, it must fully contain the visible label.',
})
}
} else {
@@ -61,11 +63,11 @@ module.exports = {
context.report({
node: jsxTextNode,
message:
'Avoid setting generic link text like `Here`, `Click here`, `Read more`. Make sure that your link text is both descriptive and concise.'
'Avoid setting generic link text like `Here`, `Click here`, `Read more`. Make sure that your link text is both descriptive and concise.',
})
}
}
}
},
}
}
},
}

View File

@@ -3,9 +3,9 @@ module.exports = {
type: 'suggestion',
docs: {
description: 'enforce `for..of` loops over `Array.forEach`',
url: require('../url')(module)
url: require('../url')(module),
},
schema: []
schema: [],
},
create(context) {
@@ -14,7 +14,7 @@ module.exports = {
if (node.callee.property && node.callee.property.name === 'forEach') {
context.report({node, message: 'Prefer for...of instead of Array.forEach'})
}
}
},
}
}
},
}

View File

@@ -3,9 +3,9 @@ module.exports = {
type: 'problem',
docs: {
description: 'disallow `event.currentTarget` calls inside of async functions',
url: require('../url')(module)
url: require('../url')(module),
},
schema: []
schema: [],
},
create(context) {
@@ -22,7 +22,7 @@ module.exports = {
context.report({node, message: 'event.currentTarget inside an async function is error prone'})
}
}
}
},
}
}
},
}

View File

@@ -3,9 +3,9 @@ module.exports = {
type: 'problem',
docs: {
description: 'disallow `event.preventDefault` calls inside of async functions',
url: require('../url')(module)
url: require('../url')(module),
},
schema: []
schema: [],
},
create(context) {
@@ -22,7 +22,7 @@ module.exports = {
context.report({node, message: 'event.preventDefault() inside an async function is error prone'})
}
}
}
},
}
}
},
}

View File

@@ -3,9 +3,9 @@ module.exports = {
type: 'problem',
docs: {
description: 'disallow usage of CSRF tokens in JavaScript',
url: require('../url')(module)
url: require('../url')(module),
},
schema: []
schema: [],
},
create(context) {
@@ -14,7 +14,7 @@ module.exports = {
context.report({
node,
message:
'Form CSRF tokens (authenticity tokens) should not be created in JavaScript and their values should not be used directly for XHR requests.'
'Form CSRF tokens (authenticity tokens) should not be created in JavaScript and their values should not be used directly for XHR requests.',
})
}
}
@@ -24,7 +24,7 @@ module.exports = {
if (typeof node.value === 'string') {
checkAuthenticityTokenUsage(node, node.value)
}
}
},
}
}
},
}

View File

@@ -22,10 +22,10 @@ module.exports = {
type: 'problem',
docs: {
description: 'disallow wrong usage of attribute names',
url: require('../url')(module)
url: require('../url')(module),
},
fixable: 'code',
schema: []
schema: [],
},
create(context) {
return {
@@ -44,10 +44,10 @@ module.exports = {
message: 'Attributes should be lowercase and hyphen separated, or part of the SVG whitelist.',
fix(fixer) {
return fixer.replaceText(attributeNameNode, `'${attributeNameNode.value.toLowerCase()}'`)
}
},
})
}
}
},
}
}
},
}

View File

@@ -3,9 +3,9 @@ module.exports = {
type: 'suggestion',
docs: {
description: 'enforce a naming convention for js- prefixed classes',
url: require('../url')(module)
url: require('../url')(module),
},
schema: []
schema: [],
},
create(context) {
@@ -51,7 +51,7 @@ module.exports = {
checkStringEndsWithJSClassName(quasi, quasi.value.raw)
}
}
}
},
}
}
},
}

View File

@@ -3,9 +3,9 @@ module.exports = {
type: 'problem',
docs: {
description: 'disallow usage of `Element.prototype.blur()`',
url: require('../url')(module)
url: require('../url')(module),
},
schema: []
schema: [],
},
create(context) {
return {
@@ -13,7 +13,7 @@ module.exports = {
if (node.callee.property && node.callee.property.name === 'blur') {
context.report({node, message: 'Do not use element.blur(), instead restore the focus of a previous element.'})
}
}
},
}
}
},
}

View File

@@ -3,9 +3,9 @@ module.exports = {
type: 'problem',
docs: {
description: 'disallow usage the `d-none` CSS class',
url: require('../url')(module)
url: require('../url')(module),
},
schema: []
schema: [],
},
create(context) {
return {
@@ -21,11 +21,11 @@ module.exports = {
if (invalidArgument) {
context.report({
node,
message: 'Prefer hidden property to d-none class'
message: 'Prefer hidden property to d-none class',
})
}
}
}
},
}
}
},
}

View File

@@ -3,9 +3,9 @@ module.exports = {
type: 'problem',
docs: {
description: 'enforce usage of `Element.prototype.getAttribute` instead of `Element.prototype.datalist`',
url: require('../url')(module)
url: require('../url')(module),
},
schema: []
schema: [],
},
create(context) {
@@ -14,7 +14,7 @@ module.exports = {
if (node.property && node.property.name === 'dataset') {
context.report({node, message: "Use getAttribute('data-your-attribute') instead of dataset."})
}
}
},
}
}
},
}

View File

@@ -3,9 +3,9 @@ module.exports = {
type: 'suggestion',
docs: {
description: 'disallow creating dynamic script tags',
url: require('../url')(module)
url: require('../url')(module),
},
schema: []
schema: [],
},
create(context) {
@@ -15,15 +15,15 @@ module.exports = {
context.report({
node: node.arguments[0],
message: "Don't create dynamic script tags, add them in the server template instead."
message: "Don't create dynamic script tags, add them in the server template instead.",
})
},
'AssignmentExpression[left.property.name="type"][right.value="text/javascript"]': function (node) {
context.report({
node: node.right,
message: "Don't create dynamic script tags, add them in the server template instead."
message: "Don't create dynamic script tags, add them in the server template instead.",
})
}
},
}
}
},
}

View File

@@ -3,9 +3,9 @@ module.exports = {
type: 'problem',
docs: {
description: 'disallow implicit global variables',
url: require('../url')(module)
url: require('../url')(module),
},
schema: []
schema: [],
},
create(context) {
@@ -29,7 +29,7 @@ module.exports = {
}
}
}
}
},
}
}
},
}

View File

@@ -3,9 +3,9 @@ module.exports = {
type: 'problem',
docs: {
description: 'disallow `Element.prototype.innerHTML` in favor of `Element.prototype.textContent`',
url: require('../url')(module)
url: require('../url')(module),
},
schema: []
schema: [],
},
create(context) {
@@ -13,9 +13,9 @@ module.exports = {
'MemberExpression[property.name=innerHTML]': function (node) {
context.report({
node: node.property,
message: 'Using innerHTML poses a potential security risk and should not be used. Prefer using textContent.'
message: 'Using innerHTML poses a potential security risk and should not be used. Prefer using textContent.',
})
}
},
}
}
},
}

View File

@@ -3,10 +3,10 @@ module.exports = {
type: 'problem',
docs: {
description: 'disallow `Element.prototype.innerText` in favor of `Element.prototype.textContent`',
url: require('../url')(module)
url: require('../url')(module),
},
fixable: 'code',
schema: []
schema: [],
},
create(context) {
@@ -15,16 +15,16 @@ module.exports = {
if (node.property && node.property.name === 'innerText') {
context.report({
meta: {
fixable: 'code'
fixable: 'code',
},
node: node.property,
message: 'Prefer textContent to innerText',
fix(fixer) {
return fixer.replaceText(node.property, 'textContent')
}
},
})
}
}
},
}
}
},
}

View File

@@ -3,9 +3,9 @@ module.exports = {
type: 'suggestion',
docs: {
description: 'enforce using `async/await` syntax over Promises',
url: require('../url')(module)
url: require('../url')(module),
},
schema: []
schema: [],
},
create(context) {
@@ -16,7 +16,7 @@ module.exports = {
} else if (node.property && node.property.name === 'catch') {
context.report({node: node.property, message: 'Prefer async/await to Promise.catch()'})
}
}
},
}
}
},
}

View File

@@ -1,4 +1,12 @@
const passiveEventListenerNames = new Set(['touchstart', 'touchmove', 'wheel', 'mousewheel'])
const passiveEventListenerNames = new Set([
'touchstart',
'touchmove',
'touchenter',
'touchend',
'touchleave',
'wheel',
'mousewheel',
])
const propIsPassiveTrue = prop => prop.key && prop.key.name === 'passive' && prop.value && prop.value.value === true
@@ -7,10 +15,10 @@ module.exports = {
type: 'suggestion',
docs: {
description: 'disallow marking a event handler as passive when it has no effect',
url: require('../url')(module)
url: require('../url')(module),
},
fixable: 'code',
schema: []
schema: [],
},
create(context) {
@@ -42,10 +50,10 @@ module.exports = {
}
}
return removals.map(t => fixer.remove(t))
}
},
})
}
}
},
}
}
},
}

View File

@@ -1,15 +1,15 @@
const observerMap = {
scroll: 'IntersectionObserver',
resize: 'ResizeObserver'
resize: 'ResizeObserver',
}
module.exports = {
meta: {
type: 'suggestion',
docs: {
description: 'disallow poorly performing event listeners',
url: require('../url')(module)
url: require('../url')(module),
},
schema: []
schema: [],
},
create(context) {
@@ -20,9 +20,9 @@ module.exports = {
if (!(name.value in observerMap)) return
context.report({
node,
message: `Avoid using "${name.value}" event listener. Consider using ${observerMap[name.value]} instead`
message: `Avoid using "${name.value}" event listener. Consider using ${observerMap[name.value]} instead`,
})
}
},
}
}
},
}

View File

@@ -1,4 +1,12 @@
const passiveEventListenerNames = new Set(['touchstart', 'touchmove', 'wheel', 'mousewheel'])
const passiveEventListenerNames = new Set([
'touchstart',
'touchmove',
'touchenter',
'touchend',
'touchleave',
'wheel',
'mousewheel',
])
const propIsPassiveTrue = prop => prop.key && prop.key.name === 'passive' && prop.value && prop.value.value === true
@@ -7,9 +15,9 @@ module.exports = {
type: 'suggestion',
docs: {
description: 'enforce marking high frequency event handlers as passive',
url: require('../url')(module)
url: require('../url')(module),
},
schema: []
schema: [],
},
create(context) {
@@ -21,7 +29,7 @@ module.exports = {
if (!passiveEventListenerNames.has(name.value)) return
if (options && options.type === 'ObjectExpression' && options.properties.some(propIsPassiveTrue)) return
context.report({node, message: `High Frequency Events like "${name.value}" should be \`passive: true\``})
}
},
}
}
},
}

View File

@@ -0,0 +1,101 @@
// @ts-check
const {aria, elementRoles, roles} = require('aria-query')
const {getProp, getPropValue, propName} = require('jsx-ast-utils')
const {getElementType} = require('../utils/get-element-type')
const ObjectMap = require('../utils/object-map')
// Clean-up `elementRoles` from `aria-query`
const elementRolesMap = new ObjectMap()
for (const [key, value] of elementRoles.entries()) {
// - Remove unused `constraints` key
delete key.constraints
key.attributes = key.attributes?.filter(attribute => !('constraints' in attribute))
// - Remove empty `attributes` key
if (!key.attributes || key.attributes?.length === 0) {
delete key.attributes
}
elementRolesMap.set(key, value)
}
// - Remove insufficiently-disambiguated `menuitem` entry
elementRolesMap.delete({name: 'menuitem'})
// - Disambiguate `menuitem` and `menu` roles by `type`
elementRolesMap.set({name: 'menuitem', attributes: [{name: 'type', value: 'command'}]}, ['menuitem'])
elementRolesMap.set({name: 'menuitem', attributes: [{name: 'type', value: 'radio'}]}, ['menuitemradio'])
elementRolesMap.set({name: 'menuitem', attributes: [{name: 'type', value: 'toolbar'}]}, ['toolbar'])
elementRolesMap.set({name: 'menu', attributes: [{name: 'type', value: 'toolbar'}]}, ['toolbar'])
module.exports = {
meta: {
docs: {
description:
'Enforce that elements with explicit or implicit roles defined contain only `aria-*` properties supported by that `role`.',
url: require('../url')(module),
},
schema: [],
},
create(context) {
return {
JSXOpeningElement(node) {
// Assemble a key for looking-up the elements role in the `elementRolesMap`
// - Get the elements name
const key = {name: getElementType(context, node)}
// - Get the elements disambiguating attributes
for (const prop of ['aria-expanded', 'type', 'size', 'role', 'href', 'multiple', 'scope']) {
// - Only provide `aria-expanded` when its required for disambiguation
if (prop === 'aria-expanded' && key.name !== 'summary') continue
const value = getPropValue(getProp(node.attributes, prop))
if (value) {
if (!('attributes' in key)) {
key.attributes = []
}
if (prop === 'href') {
key.attributes.push({name: prop})
} else {
key.attributes.push({name: prop, value})
}
}
}
// Get the elements explicit or implicit role
const role = getPropValue(getProp(node.attributes, 'role')) ?? elementRolesMap.get(key)?.[0]
// Return early if role could not be determined
if (!role) return
// Get allowed ARIA attributes:
// - From the role itself
let allowedProps = Object.keys(roles.get(role)?.props || {})
// - From parent roles
for (const parentRole of roles.get(role)?.superClass.flat() ?? []) {
allowedProps = allowedProps.concat(Object.keys(roles.get(parentRole)?.props || {}))
}
// Dedupe, for performance
allowedProps = Array.from(new Set(allowedProps))
// Get prohibited ARIA attributes:
// - From the role itself
let prohibitedProps = roles.get(role)?.prohibitedProps || []
// - From parent roles
for (const parentRole of roles.get(role)?.superClass.flat() ?? []) {
prohibitedProps = prohibitedProps.concat(roles.get(parentRole)?.prohibitedProps || [])
}
// - From comparing allowed vs all ARIA attributes
prohibitedProps = prohibitedProps.concat(aria.keys().filter(x => !allowedProps.includes(x)))
// Dedupe, for performance
prohibitedProps = Array.from(new Set(prohibitedProps))
for (const prop of node.attributes) {
// Return early if prohibited ARIA attribute is set to an ignorable value
if (getPropValue(prop) == null || prop.type === 'JSXSpreadAttribute') return
if (prohibitedProps?.includes(propName(prop))) {
context.report({
node,
message: `The attribute ${propName(prop)} is not supported by the role ${role}.`,
})
}
}
},
}
},
}

View File

@@ -3,9 +3,9 @@ module.exports = {
type: 'problem',
docs: {
description: 'disallow unescaped HTML literals',
url: require('../url')(module)
url: require('../url')(module),
},
schema: []
schema: [],
},
create(context) {
@@ -18,7 +18,7 @@ module.exports = {
context.report({
node,
message
message,
})
},
TemplateLiteral(node) {
@@ -27,10 +27,10 @@ module.exports = {
if (!node.parent.tag || node.parent.tag.name !== 'html') {
context.report({
node,
message
message,
})
}
}
},
}
}
},
}