From 4c7e7815c12a797587bb8e3cdced7f3003848964 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Tue, 9 Jan 2024 10:28:06 -0800 Subject: [PATCH] [Robustness] use `safe-regex-test` --- package.json | 1 + src/rules/accessible-emoji.js | 5 ++++- src/rules/anchor-is-valid.js | 5 ++++- src/rules/img-redundant-alt.js | 6 ++++-- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 6497a872a..a045cb3a0 100644 --- a/package.json +++ b/package.json @@ -89,6 +89,7 @@ "minimatch": "^3.1.2", "object.entries": "^1.1.7", "object.fromentries": "^2.0.7", + "safe-regex-test": "^1.0.1", "string.prototype.includes": "^2.0.0" }, "peerDependencies": { diff --git a/src/rules/accessible-emoji.js b/src/rules/accessible-emoji.js index 53eb89993..794353647 100644 --- a/src/rules/accessible-emoji.js +++ b/src/rules/accessible-emoji.js @@ -9,6 +9,7 @@ import emojiRegex from 'emoji-regex'; import { getProp, getLiteralPropValue } from 'jsx-ast-utils'; +import safeRegexTest from 'safe-regex-test'; import { generateObjSchema } from '../util/schemas'; import getElementType from '../util/getElementType'; import isHiddenFromScreenReader from '../util/isHiddenFromScreenReader'; @@ -29,11 +30,13 @@ export default { create: (context) => { const elementType = getElementType(context); + + const testEmoji = safeRegexTest(emojiRegex()); return { JSXOpeningElement: (node) => { const literalChildValue = node.parent.children.find((child) => child.type === 'Literal' || child.type === 'JSXText'); - if (literalChildValue && emojiRegex().test(literalChildValue.value)) { + if (literalChildValue && testEmoji(literalChildValue.value)) { const elementIsHidden = isHiddenFromScreenReader(elementType(node), node.attributes); if (elementIsHidden) { return; // emoji is decorative diff --git a/src/rules/anchor-is-valid.js b/src/rules/anchor-is-valid.js index 7972db758..2d518c355 100644 --- a/src/rules/anchor-is-valid.js +++ b/src/rules/anchor-is-valid.js @@ -10,6 +10,7 @@ import { getProp, getPropValue } from 'jsx-ast-utils'; import type { JSXOpeningElement } from 'ast-types-flow'; +import safeRegexTest from 'safe-regex-test'; import type { ESLintConfig, ESLintContext, ESLintVisitorSelectorConfig } from '../../flow/eslint'; import { generateObjSchema, arraySchema, enumArraySchema } from '../util/schemas'; import getElementType from '../util/getElementType'; @@ -39,6 +40,8 @@ export default ({ create: (context: ESLintContext): ESLintVisitorSelectorConfig => { const elementType = getElementType(context); + const testJShref = safeRegexTest(/^\W*?javascript:/); + return { JSXOpeningElement: (node: JSXOpeningElement): void => { const { attributes } = node; @@ -98,7 +101,7 @@ export default ({ .filter((value) => ( value != null && (typeof value === 'string' && ( - !value.length || value === '#' || /^\W*?javascript:/.test(value) + !value.length || value === '#' || testJShref(value) )) )); if (invalidHrefValues.length !== 0) { diff --git a/src/rules/img-redundant-alt.js b/src/rules/img-redundant-alt.js index 7d3e913b8..2046d83da 100644 --- a/src/rules/img-redundant-alt.js +++ b/src/rules/img-redundant-alt.js @@ -10,6 +10,7 @@ import { getProp, getLiteralPropValue } from 'jsx-ast-utils'; import includes from 'array-includes'; import stringIncludes from 'string.prototype.includes'; +import safeRegexTest from 'safe-regex-test'; import { generateObjSchema, arraySchema } from '../util/schemas'; import getElementType from '../util/getElementType'; import isHiddenFromScreenReader from '../util/isHiddenFromScreenReader'; @@ -27,11 +28,12 @@ const schema = generateObjSchema({ words: arraySchema, }); +const isASCII = safeRegexTest(/[\x20-\x7F]+/); + function containsRedundantWord(value, redundantWords) { const lowercaseRedundantWords = redundantWords.map((redundantWord) => redundantWord.toLowerCase()); - const isASCII = /[\x20-\x7F]+/.test(value); - if (isASCII) { + if (isASCII(value)) { return value.split(/\s+/).some((valueWord) => includes(lowercaseRedundantWords, valueWord.toLowerCase())); } return lowercaseRedundantWords.some((redundantWord) => stringIncludes(value.toLowerCase(), redundantWord));