main
js 109 lines 3.16 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 import {ATTRIBUTE_NAME_CHAR} from './isAttributeNameSafe';
9 import validAriaProperties from './validAriaProperties';
10 import hasOwnProperty from 'shared/hasOwnProperty';
11
12 const warnedProperties = {};
13 const rARIA = new RegExp('^(aria)-[' + ATTRIBUTE_NAME_CHAR + ']*$');
14 const rARIACamel = new RegExp('^(aria)[A-Z][' + ATTRIBUTE_NAME_CHAR + ']*$');
15
16 function validateProperty(tagName, name) {
17 if (__DEV__) {
18 if (hasOwnProperty.call(warnedProperties, name) && warnedProperties[name]) {
19 return true;
20 }
21
22 if (rARIACamel.test(name)) {
23 const ariaName = 'aria-' + name.slice(4).toLowerCase();
24 const correctName = validAriaProperties.hasOwnProperty(ariaName)
25 ? ariaName
26 : null;
27
28 // If this is an aria-* attribute, but is not listed in the known DOM
29 // DOM properties, then it is an invalid aria-* attribute.
30 if (correctName == null) {
31 console.error(
32 'Invalid ARIA attribute `%s`. ARIA attributes follow the pattern aria-* and must be lowercase.',
33 name,
34 );
35 warnedProperties[name] = true;
36 return true;
37 }
38 // aria-* attributes should be lowercase; suggest the lowercase version.
39 if (name !== correctName) {
40 console.error(
41 'Invalid ARIA attribute `%s`. Did you mean `%s`?',
42 name,
43 correctName,
44 );
45 warnedProperties[name] = true;
46 return true;
47 }
48 }
49
50 if (rARIA.test(name)) {
51 const lowerCasedName = name.toLowerCase();
52 const standardName = validAriaProperties.hasOwnProperty(lowerCasedName)
53 ? lowerCasedName
54 : null;
55
56 // If this is an aria-* attribute, but is not listed in the known DOM
57 // DOM properties, then it is an invalid aria-* attribute.
58 if (standardName == null) {
59 warnedProperties[name] = true;
60 return false;
61 }
62 // aria-* attributes should be lowercase; suggest the lowercase version.
63 if (name !== standardName) {
64 console.error(
65 'Unknown ARIA attribute `%s`. Did you mean `%s`?',
66 name,
67 standardName,
68 );
69 warnedProperties[name] = true;
70 return true;
71 }
72 }
73 }
74
75 return true;
76 }
77
78 export function validateProperties(type, props) {
79 if (__DEV__) {
80 const invalidProps = [];
81
82 for (const key in props) {
83 const isValid = validateProperty(type, key);
84 if (!isValid) {
85 invalidProps.push(key);
86 }
87 }
88
89 const unknownPropString = invalidProps
90 .map(prop => '`' + prop + '`')
91 .join(', ');
92
93 if (invalidProps.length === 1) {
94 console.error(
95 'Invalid aria prop %s on <%s> tag. ' +
96 'For details, see https://react.dev/link/invalid-aria-props',
97 unknownPropString,
98 type,
99 );
100 } else if (invalidProps.length > 1) {
101 console.error(
102 'Invalid aria props %s on <%s> tag. ' +
103 'For details, see https://react.dev/link/invalid-aria-props',
104 unknownPropString,
105 type,
106 );
107 }
108 }
109 }