diff --git a/__tests__/src/rules/anchor-ambiguous-text-test.js b/__tests__/src/rules/anchor-ambiguous-text-test.js
index 7706bb44c..da57274cd 100644
--- a/__tests__/src/rules/anchor-ambiguous-text-test.js
+++ b/__tests__/src/rules/anchor-ambiguous-text-test.js
@@ -75,6 +75,13 @@ ruleTester.run('anchor-ambiguous-text', rule, {
{ code: 'HERE;', errors: [expectedError] },
{ code: 'click here;', errors: [expectedError] },
{ code: 'learn more;', errors: [expectedError] },
+ { code: 'learn more;', errors: [expectedError] },
+ { code: 'learn more.;', errors: [expectedError] },
+ { code: 'learn more?;', errors: [expectedError] },
+ { code: 'learn more,;', errors: [expectedError] },
+ { code: 'learn more!;', errors: [expectedError] },
+ { code: 'learn more;;', errors: [expectedError] },
+ { code: 'learn more:;', errors: [expectedError] },
{ code: 'link;', errors: [expectedError] },
{ code: 'a link;', errors: [expectedError] },
{ code: 'something;', errors: [expectedError] },
diff --git a/__tests__/src/util/getAccessibleChildText-test.js b/__tests__/src/util/getAccessibleChildText-test.js
index 6b67db4e0..a77d9d270 100644
--- a/__tests__/src/util/getAccessibleChildText-test.js
+++ b/__tests__/src/util/getAccessibleChildText-test.js
@@ -64,6 +64,30 @@ describe('getAccessibleChildText', () => {
), elementType)).toBe('bar');
});
+ it('returns trimmed literal value for JSXText child', () => {
+ expect(getAccessibleChildText(JSXElementMock(
+ 'a',
+ [],
+ [{ type: 'Literal', value: ' bar ' }],
+ ), elementType)).toBe('bar');
+ });
+
+ it('returns space-collapsed literal value for JSXText child', () => {
+ expect(getAccessibleChildText(JSXElementMock(
+ 'a',
+ [],
+ [{ type: 'Literal', value: 'foo bar' }],
+ ), elementType)).toBe('foo bar');
+ });
+
+ it('returns punctuation-stripped literal value for JSXText child', () => {
+ expect(getAccessibleChildText(JSXElementMock(
+ 'a',
+ [],
+ [{ type: 'Literal', value: 'foo, bar. baz? foo; bar:' }],
+ ), elementType)).toBe('foo bar baz foo bar');
+ });
+
it('returns recursive value for JSXElement child', () => {
expect(getAccessibleChildText(JSXElementMock(
'a',
diff --git a/docs/rules/anchor-ambiguous-text.md b/docs/rules/anchor-ambiguous-text.md
index d9888a462..0a14fb45c 100644
--- a/docs/rules/anchor-ambiguous-text.md
+++ b/docs/rules/anchor-ambiguous-text.md
@@ -30,7 +30,7 @@ The logic to calculate the inner text of an anchor is as follows:
Note that this rule still disallows ambiguous `aria-label` or `alt` values.
-Note that this rule is case-insensitive and trims whitespace. It only looks for **exact matches**.
+Note that this rule is case-insensitive, trims whitespace, and ignores certain punctuation (`[,.?¿!‽¡;:]`). It only looks for **exact matches**.
### Succeed
```jsx
@@ -43,8 +43,15 @@ Note that this rule is case-insensitive and trims whitespace. It only looks for
```jsx
here
HERE
-click here
link
+click here
+learn more
+learn more.
+learn more,
+learn more?
+learn more!
+learn more:
+learn more;
a link
a link
click here // goes through element children
diff --git a/src/util/getAccessibleChildText.js b/src/util/getAccessibleChildText.js
index b25fd6139..093bab474 100644
--- a/src/util/getAccessibleChildText.js
+++ b/src/util/getAccessibleChildText.js
@@ -10,10 +10,14 @@ import isHiddenFromScreenReader from './isHiddenFromScreenReader';
* Returns a new "standardized" string: all whitespace is collapsed to one space,
* and the string is lowercase
* @param {string} input
- * @returns lowercase, single-spaced, trimmed string
+ * @returns lowercase, single-spaced, punctuation-stripped, trimmed string
*/
function standardizeSpaceAndCase(input: string): string {
- return input.trim().replace(/\s\s+/g, ' ').toLowerCase();
+ return input
+ .trim()
+ .replace(/[,.?¿!‽¡;:]/g, '') // strip punctuation
+ .replace(/\s\s+/g, ' ') // collapse spaces
+ .toLowerCase();
}
/**