Replace `wrap-warning-with-env-check` with an eslint plugin (#17540)
* Replace Babel plugin with an ESLint plugin * Fix ESLint rule violations * Move shared conditions higher * Test formatting nits * Tweak ESLint rule * Bugfix: inside else branch, 'if' tests are not satisfactory * Use a stricter check for exactly if (__DEV__) This makes it easier to see what's going on and matches dominant style in the codebase. * Fix remaining files after stricter check
Laura buns committed
Dec 6, 2019 at 18:25 UTC
b43eec7eaad14747d24ef24a06b27cb2a5653bbc
35 files changed
+928
-545
.eslintrc.js
+1
@@ -93,6 +93,7 @@ module.exports = {
93
'react-internal/no-primitive-constructors': ERROR,
94
'react-internal/no-to-warn-dev-within-to-throw': ERROR,
95
'react-internal/warning-and-invariant-args': ERROR,
96
+ 'react-internal/no-production-logging': ERROR,
97
},
98
99
overrides: [
packages/create-subscription/src/createSubscription.js
+10
-8
@@ -36,14 +36,16 @@ export function createSubscription<Property, Value>(
36
}> {
37
const {getCurrentValue, subscribe} = config;
38
39
- warningWithoutStack(
40
- typeof getCurrentValue === 'function',
41
- 'Subscription must specify a getCurrentValue function',
42
- );
43
- warningWithoutStack(
44
- typeof subscribe === 'function',
45
- 'Subscription must specify a subscribe function',
46
- );
39
+ if (__DEV__) {
40
+ warningWithoutStack(
41
+ typeof getCurrentValue === 'function',
42
+ 'Subscription must specify a getCurrentValue function',
43
+ );
44
+ warningWithoutStack(
45
+ typeof subscribe === 'function',
46
+ 'Subscription must specify a subscribe function',
47
+ );
48
+ }
49
50
type Props = {
51
children: (value: Value) => React$Element<any>,
packages/legacy-events/SyntheticEvent.js
+12
-11
@@ -283,17 +283,18 @@ function getPooledWarningPropertyDefinition(propName, getVal) {
283
}
284
285
function warn(action, result) {
286
- const warningCondition = false;
287
- warningWithoutStack(
288
- warningCondition,
289
- "This synthetic event is reused for performance reasons. If you're seeing this, " +
290
- "you're %s `%s` on a released/nullified synthetic event. %s. " +
291
- 'If you must keep the original synthetic event around, use event.persist(). ' +
292
- 'See https://fb.me/react-event-pooling for more information.',
293
- action,
294
- propName,
295
- result,
296
- );
286
+ if (__DEV__) {
287
+ warningWithoutStack(
288
+ false,
289
+ "This synthetic event is reused for performance reasons. If you're seeing this, " +
290
+ "you're %s `%s` on a released/nullified synthetic event. %s. " +
291
+ 'If you must keep the original synthetic event around, use event.persist(). ' +
292
+ 'See https://fb.me/react-event-pooling for more information.',
293
+ action,
294
+ propName,
295
+ result,
296
+ );
297
+ }
298
}
299
}
300
packages/react-dom/src/client/ReactDOM.js
+11
-9
@@ -142,15 +142,17 @@ const ReactDOM: Object = {
142
// Temporary alias since we already shipped React 16 RC with it.
143
// TODO: remove in React 17.
144
unstable_createPortal(...args) {
145
- if (!didWarnAboutUnstableCreatePortal) {
146
- didWarnAboutUnstableCreatePortal = true;
147
- lowPriorityWarningWithoutStack(
148
- false,
149
- 'The ReactDOM.unstable_createPortal() alias has been deprecated, ' +
150
- 'and will be removed in React 17+. Update your code to use ' +
151
- 'ReactDOM.createPortal() instead. It has the exact same API, ' +
152
- 'but without the "unstable_" prefix.',
153
- );
145
+ if (__DEV__) {
146
+ if (!didWarnAboutUnstableCreatePortal) {
147
+ didWarnAboutUnstableCreatePortal = true;
148
+ lowPriorityWarningWithoutStack(
149
+ false,
150
+ 'The ReactDOM.unstable_createPortal() alias has been deprecated, ' +
151
+ 'and will be removed in React 17+. Update your code to use ' +
152
+ 'ReactDOM.createPortal() instead. It has the exact same API, ' +
153
+ 'but without the "unstable_" prefix.',
154
+ );
155
+ }
156
}
157
return createPortal(...args);
158
},
packages/react-dom/src/client/ReactDOMSelect.js
+25
-23
@@ -40,30 +40,32 @@ const valuePropNames = ['value', 'defaultValue'];
40
* Validation function for `value` and `defaultValue`.
41
*/
42
function checkSelectPropTypes(props) {
43
- ReactControlledValuePropTypes.checkPropTypes('select', props);
43
+ if (__DEV__) {
44
+ ReactControlledValuePropTypes.checkPropTypes('select', props);
45
45
- for (let i = 0; i < valuePropNames.length; i++) {
46
- const propName = valuePropNames[i];
47
- if (props[propName] == null) {
48
- continue;
49
- }
50
- const isArray = Array.isArray(props[propName]);
51
- if (props.multiple && !isArray) {
52
- warning(
53
- false,
54
- 'The `%s` prop supplied to <select> must be an array if ' +
55
- '`multiple` is true.%s',
56
- propName,
57
- getDeclarationErrorAddendum(),
58
- );
59
- } else if (!props.multiple && isArray) {
60
- warning(
61
- false,
62
- 'The `%s` prop supplied to <select> must be a scalar ' +
63
- 'value if `multiple` is false.%s',
64
- propName,
65
- getDeclarationErrorAddendum(),
66
- );
46
+ for (let i = 0; i < valuePropNames.length; i++) {
47
+ const propName = valuePropNames[i];
48
+ if (props[propName] == null) {
49
+ continue;
50
+ }
51
+ const isArray = Array.isArray(props[propName]);
52
+ if (props.multiple && !isArray) {
53
+ warning(
54
+ false,
55
+ 'The `%s` prop supplied to <select> must be an array if ' +
56
+ '`multiple` is true.%s',
57
+ propName,
58
+ getDeclarationErrorAddendum(),
59
+ );
60
+ } else if (!props.multiple && isArray) {
61
+ warning(
62
+ false,
63
+ 'The `%s` prop supplied to <select> must be a scalar ' +
64
+ 'value if `multiple` is false.%s',
65
+ propName,
66
+ getDeclarationErrorAddendum(),
67
+ );
68
+ }
69
}
70
}
71
}
packages/react-dom/src/server/ReactPartialRenderer.js
+8
-6
@@ -687,12 +687,14 @@ function resolve(
687
);
688
}
689
} else {
690
- warningWithoutStack(
691
- false,
692
- '%s.getChildContext(): childContextTypes must be defined in order to ' +
693
- 'use getChildContext().',
694
- getComponentName(Component) || 'Unknown',
695
- );
690
+ if (__DEV__) {
691
+ warningWithoutStack(
692
+ false,
693
+ '%s.getChildContext(): childContextTypes must be defined in order to ' +
694
+ 'use getChildContext().',
695
+ getComponentName(Component) || 'Unknown',
696
+ );
697
+ }
698
}
699
}
700
if (childContext) {
packages/react-dom/src/server/ReactPartialRendererHooks.js
+9
-9
@@ -392,16 +392,16 @@ export function useLayoutEffect(
392
) {
393
if (__DEV__) {
394
currentHookNameInDev = 'useLayoutEffect';
395
+ warning(
396
+ false,
397
+ 'useLayoutEffect does nothing on the server, because its effect cannot ' +
398
+ "be encoded into the server renderer's output format. This will lead " +
399
+ 'to a mismatch between the initial, non-hydrated UI and the intended ' +
400
+ 'UI. To avoid this, useLayoutEffect should only be used in ' +
401
+ 'components that render exclusively on the client. ' +
402
+ 'See https://fb.me/react-uselayouteffect-ssr for common fixes.',
403
+ );
404
}
396
- warning(
397
- false,
398
- 'useLayoutEffect does nothing on the server, because its effect cannot ' +
399
- "be encoded into the server renderer's output format. This will lead " +
400
- 'to a mismatch between the initial, non-hydrated UI and the intended ' +
401
- 'UI. To avoid this, useLayoutEffect should only be used in ' +
402
- 'components that render exclusively on the client. ' +
403
- 'See https://fb.me/react-uselayouteffect-ssr for common fixes.',
404
- );
405
}
406
407
function dispatchAction<A>(
packages/react-dom/src/shared/CSSPropertyOperations.js
+30
-28
@@ -128,37 +128,39 @@ export function validateShorthandPropertyCollisionInDev(
128
styleUpdates,
129
nextStyles,
130
) {
131
- if (!warnAboutShorthandPropertyCollision) {
132
- return;
133
- }
131
+ if (__DEV__) {
132
+ if (!warnAboutShorthandPropertyCollision) {
133
+ return;
134
+ }
135
135
- if (!nextStyles) {
136
- return;
137
- }
136
+ if (!nextStyles) {
137
+ return;
138
+ }
139
139
- const expandedUpdates = expandShorthandMap(styleUpdates);
140
- const expandedStyles = expandShorthandMap(nextStyles);
141
- const warnedAbout = {};
142
- for (const key in expandedUpdates) {
143
- const originalKey = expandedUpdates[key];
144
- const correctOriginalKey = expandedStyles[key];
145
- if (correctOriginalKey && originalKey !== correctOriginalKey) {
146
- const warningKey = originalKey + ',' + correctOriginalKey;
147
- if (warnedAbout[warningKey]) {
148
- continue;
140
+ const expandedUpdates = expandShorthandMap(styleUpdates);
141
+ const expandedStyles = expandShorthandMap(nextStyles);
142
+ const warnedAbout = {};
143
+ for (const key in expandedUpdates) {
144
+ const originalKey = expandedUpdates[key];
145
+ const correctOriginalKey = expandedStyles[key];
146
+ if (correctOriginalKey && originalKey !== correctOriginalKey) {
147
+ const warningKey = originalKey + ',' + correctOriginalKey;
148
+ if (warnedAbout[warningKey]) {
149
+ continue;
150
+ }
151
+ warnedAbout[warningKey] = true;
152
+ warning(
153
+ false,
154
+ '%s a style property during rerender (%s) when a ' +
155
+ 'conflicting property is set (%s) can lead to styling bugs. To ' +
156
+ "avoid this, don't mix shorthand and non-shorthand properties " +
157
+ 'for the same value; instead, replace the shorthand with ' +
158
+ 'separate values.',
159
+ isValueEmpty(styleUpdates[originalKey]) ? 'Removing' : 'Updating',
160
+ originalKey,
161
+ correctOriginalKey,
162
+ );
163
}
150
- warnedAbout[warningKey] = true;
151
- warning(
152
- false,
153
- '%s a style property during rerender (%s) when a ' +
154
- 'conflicting property is set (%s) can lead to styling bugs. To ' +
155
- "avoid this, don't mix shorthand and non-shorthand properties " +
156
- 'for the same value; instead, replace the shorthand with ' +
157
- 'separate values.',
158
- isValueEmpty(styleUpdates[originalKey]) ? 'Removing' : 'Updating',
159
- originalKey,
160
- correctOriginalKey,
161
- );
164
}
165
}
166
}
packages/react-dom/src/shared/ReactDOMInvalidARIAHook.js
+80
-76
@@ -18,62 +18,64 @@ const rARIACamel = new RegExp('^(aria)[A-Z][' + ATTRIBUTE_NAME_CHAR + ']*$');
18
const hasOwnProperty = Object.prototype.hasOwnProperty;
19
20
function validateProperty(tagName, name) {
21
- if (hasOwnProperty.call(warnedProperties, name) && warnedProperties[name]) {
22
- return true;
23
- }
24
-
25
- if (rARIACamel.test(name)) {
26
- const ariaName = 'aria-' + name.slice(4).toLowerCase();
27
- const correctName = validAriaProperties.hasOwnProperty(ariaName)
28
- ? ariaName
29
- : null;
30
-
31
- // If this is an aria-* attribute, but is not listed in the known DOM
32
- // DOM properties, then it is an invalid aria-* attribute.
33
- if (correctName == null) {
34
- warning(
35
- false,
36
- 'Invalid ARIA attribute `%s`. ARIA attributes follow the pattern aria-* and must be lowercase.',
37
- name,
38
- );
39
- warnedProperties[name] = true;
21
+ if (__DEV__) {
22
+ if (hasOwnProperty.call(warnedProperties, name) && warnedProperties[name]) {
23
return true;
24
}
42
- // aria-* attributes should be lowercase; suggest the lowercase version.
43
- if (name !== correctName) {
44
- warning(
45
- false,
46
- 'Invalid ARIA attribute `%s`. Did you mean `%s`?',
47
- name,
48
- correctName,
49
- );
50
- warnedProperties[name] = true;
51
- return true;
52
- }
53
- }
25
55
- if (rARIA.test(name)) {
56
- const lowerCasedName = name.toLowerCase();
57
- const standardName = validAriaProperties.hasOwnProperty(lowerCasedName)
58
- ? lowerCasedName
59
- : null;
26
+ if (rARIACamel.test(name)) {
27
+ const ariaName = 'aria-' + name.slice(4).toLowerCase();
28
+ const correctName = validAriaProperties.hasOwnProperty(ariaName)
29
+ ? ariaName
30
+ : null;
31
61
- // If this is an aria-* attribute, but is not listed in the known DOM
62
- // DOM properties, then it is an invalid aria-* attribute.
63
- if (standardName == null) {
64
- warnedProperties[name] = true;
65
- return false;
32
+ // If this is an aria-* attribute, but is not listed in the known DOM
33
+ // DOM properties, then it is an invalid aria-* attribute.
34
+ if (correctName == null) {
35
+ warning(
36
+ false,
37
+ 'Invalid ARIA attribute `%s`. ARIA attributes follow the pattern aria-* and must be lowercase.',
38
+ name,
39
+ );
40
+ warnedProperties[name] = true;
41
+ return true;
42
+ }
43
+ // aria-* attributes should be lowercase; suggest the lowercase version.
44
+ if (name !== correctName) {
45
+ warning(
46
+ false,
47
+ 'Invalid ARIA attribute `%s`. Did you mean `%s`?',
48
+ name,
49
+ correctName,
50
+ );
51
+ warnedProperties[name] = true;
52
+ return true;
53
+ }
54
}
67
- // aria-* attributes should be lowercase; suggest the lowercase version.
68
- if (name !== standardName) {
69
- warning(
70
- false,
71
- 'Unknown ARIA attribute `%s`. Did you mean `%s`?',
72
- name,
73
- standardName,
74
- );
75
- warnedProperties[name] = true;
76
- return true;
55
+
56
+ if (rARIA.test(name)) {
57
+ const lowerCasedName = name.toLowerCase();
58
+ const standardName = validAriaProperties.hasOwnProperty(lowerCasedName)
59
+ ? lowerCasedName
60
+ : null;
61
+
62
+ // If this is an aria-* attribute, but is not listed in the known DOM
63
+ // DOM properties, then it is an invalid aria-* attribute.
64
+ if (standardName == null) {
65
+ warnedProperties[name] = true;
66
+ return false;
67
+ }
68
+ // aria-* attributes should be lowercase; suggest the lowercase version.
69
+ if (name !== standardName) {
70
+ warning(
71
+ false,
72
+ 'Unknown ARIA attribute `%s`. Did you mean `%s`?',
73
+ name,
74
+ standardName,
75
+ );
76
+ warnedProperties[name] = true;
77
+ return true;
78
+ }
79
}
80
}
81
@@ -81,35 +83,37 @@ function validateProperty(tagName, name) {
83
}
84
85
function warnInvalidARIAProps(type, props) {
84
- const invalidProps = [];
86
+ if (__DEV__) {
87
+ const invalidProps = [];
88
86
- for (const key in props) {
87
- const isValid = validateProperty(type, key);
88
- if (!isValid) {
89
- invalidProps.push(key);
89
+ for (const key in props) {
90
+ const isValid = validateProperty(type, key);
91
+ if (!isValid) {
92
+ invalidProps.push(key);
93
+ }
94
}
91
- }
95
93
- const unknownPropString = invalidProps
94
- .map(prop => '`' + prop + '`')
95
- .join(', ');
96
+ const unknownPropString = invalidProps
97
+ .map(prop => '`' + prop + '`')
98
+ .join(', ');
99
97
- if (invalidProps.length === 1) {
98
- warning(
99
- false,
100
- 'Invalid aria prop %s on <%s> tag. ' +
101
- 'For details, see https://fb.me/invalid-aria-prop',
102
- unknownPropString,
103
- type,
104
- );
105
- } else if (invalidProps.length > 1) {
106
- warning(
107
- false,
108
- 'Invalid aria props %s on <%s> tag. ' +
109
- 'For details, see https://fb.me/invalid-aria-prop',
110
- unknownPropString,
111
- type,
112
- );
100
+ if (invalidProps.length === 1) {
101
+ warning(
102
+ false,
103
+ 'Invalid aria prop %s on <%s> tag. ' +
104
+ 'For details, see https://fb.me/invalid-aria-prop',
105
+ unknownPropString,
106
+ type,
107
+ );
108
+ } else if (invalidProps.length > 1) {
109
+ warning(
110
+ false,
111
+ 'Invalid aria props %s on <%s> tag. ' +
112
+ 'For details, see https://fb.me/invalid-aria-prop',
113
+ unknownPropString,
114
+ type,
115
+ );
116
+ }
117
}
118
}
119
packages/react-dom/src/shared/ReactDOMNullInputValuePropHook.js
+23
-21
@@ -10,28 +10,30 @@ import warning from 'shared/warning';
10
let didWarnValueNull = false;
11
12
export function validateProperties(type, props) {
13
- if (type !== 'input' && type !== 'textarea' && type !== 'select') {
14
- return;
15
- }
13
+ if (__DEV__) {
14
+ if (type !== 'input' && type !== 'textarea' && type !== 'select') {
15
+ return;
16
+ }
17
17
- if (props != null && props.value === null && !didWarnValueNull) {
18
- didWarnValueNull = true;
19
- if (type === 'select' && props.multiple) {
20
- warning(
21
- false,
22
- '`value` prop on `%s` should not be null. ' +
23
- 'Consider using an empty array when `multiple` is set to `true` ' +
24
- 'to clear the component or `undefined` for uncontrolled components.',
25
- type,
26
- );
27
- } else {
28
- warning(
29
- false,
30
- '`value` prop on `%s` should not be null. ' +
31
- 'Consider using an empty string to clear the component or `undefined` ' +
32
- 'for uncontrolled components.',
33
- type,
34
- );
18
+ if (props != null && props.value === null && !didWarnValueNull) {
19
+ didWarnValueNull = true;
20
+ if (type === 'select' && props.multiple) {
21
+ warning(
22
+ false,
23
+ '`value` prop on `%s` should not be null. ' +
24
+ 'Consider using an empty array when `multiple` is set to `true` ' +
25
+ 'to clear the component or `undefined` for uncontrolled components.',
26
+ type,
27
+ );
28
+ } else {
29
+ warning(
30
+ false,
31
+ '`value` prop on `%s` should not be null. ' +
32
+ 'Consider using an empty string to clear the component or `undefined` ' +
33
+ 'for uncontrolled components.',
34
+ type,
35
+ );
36
+ }
37
}
38
}
39
}
packages/react-dom/src/shared/ReactDOMUnknownPropertyHook.js
+34
-27
@@ -255,35 +255,42 @@ if (__DEV__) {
255
}
256
257
const warnUnknownProperties = function(type, props, canUseEventSystem) {
258
- const unknownProps = [];
259
- for (const key in props) {
260
- const isValid = validateProperty(type, key, props[key], canUseEventSystem);
261
- if (!isValid) {
262
- unknownProps.push(key);
258
+ if (__DEV__) {
259
+ const unknownProps = [];
260
+ for (const key in props) {
261
+ const isValid = validateProperty(
262
+ type,
263
+ key,
264
+ props[key],
265
+ canUseEventSystem,
266
+ );
267
+ if (!isValid) {
268
+ unknownProps.push(key);
269
+ }
270
}
264
- }
271
266
- const unknownPropString = unknownProps
267
- .map(prop => '`' + prop + '`')
268
- .join(', ');
269
- if (unknownProps.length === 1) {
270
- warning(
271
- false,
272
- 'Invalid value for prop %s on <%s> tag. Either remove it from the element, ' +
273
- 'or pass a string or number value to keep it in the DOM. ' +
274
- 'For details, see https://fb.me/react-attribute-behavior',
275
- unknownPropString,
276
- type,
277
- );
278
- } else if (unknownProps.length > 1) {
279
- warning(
280
- false,
281
- 'Invalid values for props %s on <%s> tag. Either remove them from the element, ' +
282
- 'or pass a string or number value to keep them in the DOM. ' +
283
- 'For details, see https://fb.me/react-attribute-behavior',
284
- unknownPropString,
285
- type,
286
- );
272
+ const unknownPropString = unknownProps
273
+ .map(prop => '`' + prop + '`')
274
+ .join(', ');
275
+ if (unknownProps.length === 1) {
276
+ warning(
277
+ false,
278
+ 'Invalid value for prop %s on <%s> tag. Either remove it from the element, ' +
279
+ 'or pass a string or number value to keep it in the DOM. ' +
280
+ 'For details, see https://fb.me/react-attribute-behavior',
281
+ unknownPropString,
282
+ type,
283
+ );
284
+ } else if (unknownProps.length > 1) {
285
+ warning(
286
+ false,
287
+ 'Invalid values for props %s on <%s> tag. Either remove them from the element, ' +
288
+ 'or pass a string or number value to keep them in the DOM. ' +
289
+ 'For details, see https://fb.me/react-attribute-behavior',
290
+ unknownPropString,
291
+ type,
292
+ );
293
+ }
294
}
295
};
296
packages/react-dom/src/shared/sanitizeURL.js
+11
-9
@@ -38,15 +38,17 @@ function sanitizeURL(url: string) {
38
'React has blocked a javascript: URL as a security precaution.%s',
39
__DEV__ ? ReactDebugCurrentFrame.getStackAddendum() : '',
40
);
41
- } else if (__DEV__ && !didWarn && isJavaScriptProtocol.test(url)) {
42
- didWarn = true;
43
- warning(
44
- false,
45
- 'A future version of React will block javascript: URLs as a security precaution. ' +
46
- 'Use event handlers instead if you can. If you need to generate unsafe HTML try ' +
47
- 'using dangerouslySetInnerHTML instead. React was passed %s.',
48
- JSON.stringify(url),
49
- );
41
+ } else if (__DEV__) {
42
+ if (!didWarn && isJavaScriptProtocol.test(url)) {
43
+ didWarn = true;
44
+ warning(
45
+ false,
46
+ 'A future version of React will block javascript: URLs as a security precaution. ' +
47
+ 'Use event handlers instead if you can. If you need to generate unsafe HTML try ' +
48
+ 'using dangerouslySetInnerHTML instead. React was passed %s.',
49
+ JSON.stringify(url),
50
+ );
51
+ }
52
}
53
}
54
packages/react-dom/src/test-utils/ReactTestUtils.js
+10
-8
@@ -359,14 +359,16 @@ const ReactTestUtils = {
359
* @return {object} the ReactTestUtils object (for chaining)
360
*/
361
mockComponent: function(module, mockTagName) {
362
- if (!hasWarnedAboutDeprecatedMockComponent) {
363
- hasWarnedAboutDeprecatedMockComponent = true;
364
- lowPriorityWarningWithoutStack(
365
- false,
366
- 'ReactTestUtils.mockComponent() is deprecated. ' +
367
- 'Use shallow rendering or jest.mock() instead.\n\n' +
368
- 'See https://fb.me/test-utils-mock-component for more information.',
369
- );
362
+ if (__DEV__) {
363
+ if (!hasWarnedAboutDeprecatedMockComponent) {
364
+ hasWarnedAboutDeprecatedMockComponent = true;
365
+ lowPriorityWarningWithoutStack(
366
+ false,
367
+ 'ReactTestUtils.mockComponent() is deprecated. ' +
368
+ 'Use shallow rendering or jest.mock() instead.\n\n' +
369
+ 'See https://fb.me/test-utils-mock-component for more information.',
370
+ );
371
+ }
372
}
373
374
mockTagName = mockTagName || module.mockTagName || 'div';
packages/react-native-renderer/src/NativeMethodsMixin.js
+20
-14
@@ -179,12 +179,14 @@ export default function(
179
}
180
181
if (maybeInstance.canonical) {
182
- warningWithoutStack(
183
- false,
184
- 'Warning: measureLayout on components using NativeMethodsMixin ' +
185
- 'or ReactNative.NativeComponent is not currently supported in Fabric. ' +
186
- 'measureLayout must be called on a native ref. Consider using forwardRef.',
187
- );
182
+ if (__DEV__) {
183
+ warningWithoutStack(
184
+ false,
185
+ 'Warning: measureLayout on components using NativeMethodsMixin ' +
186
+ 'or ReactNative.NativeComponent is not currently supported in Fabric. ' +
187
+ 'measureLayout must be called on a native ref. Consider using forwardRef.',
188
+ );
189
+ }
190
return;
191
} else {
192
let relativeNode;
@@ -197,10 +199,12 @@ export default function(
199
}
200
201
if (relativeNode == null) {
200
- warningWithoutStack(
201
- false,
202
- 'Warning: ref.measureLayout must be called with a node handle or a ref to a native component.',
203
- );
202
+ if (__DEV__) {
203
+ warningWithoutStack(
204
+ false,
205
+ 'Warning: ref.measureLayout must be called with a node handle or a ref to a native component.',
206
+ );
207
+ }
208
209
return;
210
}
@@ -243,10 +247,12 @@ export default function(
247
}
248
249
if (maybeInstance.canonical) {
246
- warningWithoutStack(
247
- false,
248
- 'Warning: setNativeProps is not currently supported in Fabric',
249
- );
250
+ if (__DEV__) {
251
+ warningWithoutStack(
252
+ false,
253
+ 'Warning: setNativeProps is not currently supported in Fabric',
254
+ );
255
+ }
256
return;
257
}
258
packages/react-native-renderer/src/ReactFabric.js
+7
-5
@@ -165,11 +165,13 @@ const ReactFabric: ReactFabricType = {
165
handle._nativeTag == null || handle._internalInstanceHandle == null;
166
167
if (invalid) {
168
- warningWithoutStack(
169
- !invalid,
170
- "dispatchCommand was called with a ref that isn't a " +
171
- 'native component. Use React.forwardRef to get access to the underlying native component',
172
- );
168
+ if (__DEV__) {
169
+ warningWithoutStack(
170
+ !invalid,
171
+ "dispatchCommand was called with a ref that isn't a " +
172
+ 'native component. Use React.forwardRef to get access to the underlying native component',
173
+ );
174
+ }
175
return;
176
}
177
packages/react-native-renderer/src/ReactFabricHostConfig.js
+12
-8
@@ -159,10 +159,12 @@ class ReactFabricHostComponent {
159
typeof relativeToNativeNode === 'number' ||
160
!(relativeToNativeNode instanceof ReactFabricHostComponent)
161
) {
162
- warningWithoutStack(
163
- false,
164
- 'Warning: ref.measureLayout must be called with a ref to a native component.',
165
- );
162
+ if (__DEV__) {
163
+ warningWithoutStack(
164
+ false,
165
+ 'Warning: ref.measureLayout must be called with a ref to a native component.',
166
+ );
167
+ }
168
169
return;
170
}
@@ -176,10 +178,12 @@ class ReactFabricHostComponent {
178
}
179
180
setNativeProps(nativeProps: Object) {
179
- warningWithoutStack(
180
- false,
181
- 'Warning: setNativeProps is not currently supported in Fabric',
182
- );
181
+ if (__DEV__) {
182
+ warningWithoutStack(
183
+ false,
184
+ 'Warning: setNativeProps is not currently supported in Fabric',
185
+ );
186
+ }
187
188
return;
189
}
packages/react-native-renderer/src/ReactNativeComponent.js
+20
-14
@@ -190,12 +190,14 @@ export default function(
190
}
191
192
if (maybeInstance.canonical) {
193
- warningWithoutStack(
194
- false,
195
- 'Warning: measureLayout on components using NativeMethodsMixin ' +
196
- 'or ReactNative.NativeComponent is not currently supported in Fabric. ' +
197
- 'measureLayout must be called on a native ref. Consider using forwardRef.',
198
- );
193
+ if (__DEV__) {
194
+ warningWithoutStack(
195
+ false,
196
+ 'Warning: measureLayout on components using NativeMethodsMixin ' +
197
+ 'or ReactNative.NativeComponent is not currently supported in Fabric. ' +
198
+ 'measureLayout must be called on a native ref. Consider using forwardRef.',
199
+ );
200
+ }
201
return;
202
} else {
203
let relativeNode;
@@ -208,10 +210,12 @@ export default function(
210
}
211
212
if (relativeNode == null) {
211
- warningWithoutStack(
212
- false,
213
- 'Warning: ref.measureLayout must be called with a node handle or a ref to a native component.',
214
- );
213
+ if (__DEV__) {
214
+ warningWithoutStack(
215
+ false,
216
+ 'Warning: ref.measureLayout must be called with a node handle or a ref to a native component.',
217
+ );
218
+ }
219
220
return;
221
}
@@ -254,10 +258,12 @@ export default function(
258
}
259
260
if (maybeInstance.canonical) {
257
- warningWithoutStack(
258
- false,
259
- 'Warning: setNativeProps is not currently supported in Fabric',
260
- );
261
+ if (__DEV__) {
262
+ warningWithoutStack(
263
+ false,
264
+ 'Warning: setNativeProps is not currently supported in Fabric',
265
+ );
266
+ }
267
return;
268
}
269
packages/react-native-renderer/src/ReactNativeFiberHostComponent.js
+6
-4
@@ -85,10 +85,12 @@ class ReactNativeFiberHostComponent {
85
}
86
87
if (relativeNode == null) {
88
- warningWithoutStack(
89
- false,
90
- 'Warning: ref.measureLayout must be called with a node handle or a ref to a native component.',
91
- );
88
+ if (__DEV__) {
89
+ warningWithoutStack(
90
+ false,
91
+ 'Warning: ref.measureLayout must be called with a node handle or a ref to a native component.',
92
+ );
93
+ }
94
95
return;
96
}
packages/react-native-renderer/src/ReactNativeRenderer.js
+7
-5
@@ -172,11 +172,13 @@ const ReactNativeRenderer: ReactNativeType = {
172
173
dispatchCommand(handle: any, command: string, args: Array<any>) {
174
if (handle._nativeTag == null) {
175
- warningWithoutStack(
176
- handle._nativeTag != null,
177
- "dispatchCommand was called with a ref that isn't a " +
178
- 'native component. Use React.forwardRef to get access to the underlying native component',
179
- );
175
+ if (__DEV__) {
176
+ warningWithoutStack(
177
+ handle._nativeTag != null,
178
+ "dispatchCommand was called with a ref that isn't a " +
179
+ 'native component. Use React.forwardRef to get access to the underlying native component',
180
+ );
181
+ }
182
return;
183
}
184
packages/react-reconciler/src/ReactChildFiber.js
+17
-15
@@ -232,23 +232,25 @@ function throwOnInvalidObjectType(returnFiber: Fiber, newChild: Object) {
232
}
233
234
function warnOnFunctionType() {
235
- const currentComponentErrorInfo =
236
- 'Functions are not valid as a React child. This may happen if ' +
237
- 'you return a Component instead of <Component /> from render. ' +
238
- 'Or maybe you meant to call this function rather than return it.' +
239
- getCurrentFiberStackInDev();
235
+ if (__DEV__) {
236
+ const currentComponentErrorInfo =
237
+ 'Functions are not valid as a React child. This may happen if ' +
238
+ 'you return a Component instead of <Component /> from render. ' +
239
+ 'Or maybe you meant to call this function rather than return it.' +
240
+ getCurrentFiberStackInDev();
241
241
- if (ownerHasFunctionTypeWarning[currentComponentErrorInfo]) {
242
- return;
243
- }
244
- ownerHasFunctionTypeWarning[currentComponentErrorInfo] = true;
242
+ if (ownerHasFunctionTypeWarning[currentComponentErrorInfo]) {
243
+ return;
244
+ }
245
+ ownerHasFunctionTypeWarning[currentComponentErrorInfo] = true;
246
246
- warning(
247
- false,
248
- 'Functions are not valid as a React child. This may happen if ' +
249
- 'you return a Component instead of <Component /> from render. ' +
250
- 'Or maybe you meant to call this function rather than return it.',
251
- );
247
+ warning(
248
+ false,
249
+ 'Functions are not valid as a React child. This may happen if ' +
250
+ 'you return a Component instead of <Component /> from render. ' +
251
+ 'Or maybe you meant to call this function rather than return it.',
252
+ );
253
+ }
254
}
255
256
// This wrapper function exists because I expect to clone the code in each path
packages/react-reconciler/src/ReactFiberBeginWork.js
+65
-63
@@ -1397,80 +1397,82 @@ function mountIndeterminateComponent(
1397
}
1398
1399
function validateFunctionComponentInDev(workInProgress: Fiber, Component: any) {
1400
- if (Component) {
1401
- warningWithoutStack(
1402
- !Component.childContextTypes,
1403
- '%s(...): childContextTypes cannot be defined on a function component.',
1404
- Component.displayName || Component.name || 'Component',
1405
- );
1406
- }
1407
- if (workInProgress.ref !== null) {
1408
- let info = '';
1409
- const ownerName = getCurrentFiberOwnerNameInDevOrNull();
1410
- if (ownerName) {
1411
- info += '\n\nCheck the render method of `' + ownerName + '`.';
1400
+ if (__DEV__) {
1401
+ if (Component) {
1402
+ warningWithoutStack(
1403
+ !Component.childContextTypes,
1404
+ '%s(...): childContextTypes cannot be defined on a function component.',
1405
+ Component.displayName || Component.name || 'Component',
1406
+ );
1407
}
1408
+ if (workInProgress.ref !== null) {
1409
+ let info = '';
1410
+ const ownerName = getCurrentFiberOwnerNameInDevOrNull();
1411
+ if (ownerName) {
1412
+ info += '\n\nCheck the render method of `' + ownerName + '`.';
1413
+ }
1414
1414
- let warningKey = ownerName || workInProgress._debugID || '';
1415
- const debugSource = workInProgress._debugSource;
1416
- if (debugSource) {
1417
- warningKey = debugSource.fileName + ':' + debugSource.lineNumber;
1418
- }
1419
- if (!didWarnAboutFunctionRefs[warningKey]) {
1420
- didWarnAboutFunctionRefs[warningKey] = true;
1421
- warning(
1422
- false,
1423
- 'Function components cannot be given refs. ' +
1424
- 'Attempts to access this ref will fail. ' +
1425
- 'Did you mean to use React.forwardRef()?%s',
1426
- info,
1427
- );
1415
+ let warningKey = ownerName || workInProgress._debugID || '';
1416
+ const debugSource = workInProgress._debugSource;
1417
+ if (debugSource) {
1418
+ warningKey = debugSource.fileName + ':' + debugSource.lineNumber;
1419
+ }
1420
+ if (!didWarnAboutFunctionRefs[warningKey]) {
1421
+ didWarnAboutFunctionRefs[warningKey] = true;
1422
+ warning(
1423
+ false,
1424
+ 'Function components cannot be given refs. ' +
1425
+ 'Attempts to access this ref will fail. ' +
1426
+ 'Did you mean to use React.forwardRef()?%s',
1427
+ info,
1428
+ );
1429
+ }
1430
}
1429
- }
1431
1431
- if (
1432
- warnAboutDefaultPropsOnFunctionComponents &&
1433
- Component.defaultProps !== undefined
1434
- ) {
1435
- const componentName = getComponentName(Component) || 'Unknown';
1432
+ if (
1433
+ warnAboutDefaultPropsOnFunctionComponents &&
1434
+ Component.defaultProps !== undefined
1435
+ ) {
1436
+ const componentName = getComponentName(Component) || 'Unknown';
1437
1437
- if (!didWarnAboutDefaultPropsOnFunctionComponent[componentName]) {
1438
- warningWithoutStack(
1439
- false,
1440
- '%s: Support for defaultProps will be removed from function components ' +
1441
- 'in a future major release. Use JavaScript default parameters instead.',
1442
- componentName,
1443
- );
1444
- didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true;
1438
+ if (!didWarnAboutDefaultPropsOnFunctionComponent[componentName]) {
1439
+ warningWithoutStack(
1440
+ false,
1441
+ '%s: Support for defaultProps will be removed from function components ' +
1442
+ 'in a future major release. Use JavaScript default parameters instead.',
1443
+ componentName,
1444
+ );
1445
+ didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true;
1446
+ }
1447
}
1446
- }
1448
1448
- if (typeof Component.getDerivedStateFromProps === 'function') {
1449
- const componentName = getComponentName(Component) || 'Unknown';
1449
+ if (typeof Component.getDerivedStateFromProps === 'function') {
1450
+ const componentName = getComponentName(Component) || 'Unknown';
1451
1451
- if (!didWarnAboutGetDerivedStateOnFunctionComponent[componentName]) {
1452
- warningWithoutStack(
1453
- false,
1454
- '%s: Function components do not support getDerivedStateFromProps.',
1455
- componentName,
1456
- );
1457
- didWarnAboutGetDerivedStateOnFunctionComponent[componentName] = true;
1452
+ if (!didWarnAboutGetDerivedStateOnFunctionComponent[componentName]) {
1453
+ warningWithoutStack(
1454
+ false,
1455
+ '%s: Function components do not support getDerivedStateFromProps.',
1456
+ componentName,
1457
+ );
1458
+ didWarnAboutGetDerivedStateOnFunctionComponent[componentName] = true;
1459
+ }
1460
}
1459
- }
1461
1461
- if (
1462
- typeof Component.contextType === 'object' &&
1463
- Component.contextType !== null
1464
- ) {
1465
- const componentName = getComponentName(Component) || 'Unknown';
1462
+ if (
1463
+ typeof Component.contextType === 'object' &&
1464
+ Component.contextType !== null
1465
+ ) {
1466
+ const componentName = getComponentName(Component) || 'Unknown';
1467
1467
- if (!didWarnAboutContextTypeOnFunctionComponent[componentName]) {
1468
- warningWithoutStack(
1469
- false,
1470
- '%s: Function components do not support contextType.',
1471
- componentName,
1472
- );
1473
- didWarnAboutContextTypeOnFunctionComponent[componentName] = true;
1468
+ if (!didWarnAboutContextTypeOnFunctionComponent[componentName]) {
1469
+ warningWithoutStack(
1470
+ false,
1471
+ '%s: Function components do not support contextType.',
1472
+ componentName,
1473
+ );
1474
+ didWarnAboutContextTypeOnFunctionComponent[componentName] = true;
1475
+ }
1476
}
1477
}
1478
}
packages/react-reconciler/src/ReactFiberDevToolsHook.js
+18
-14
@@ -89,13 +89,15 @@ export function injectInternals(internals: Object): boolean {
89
hook.onCommitFiberRoot(rendererID, root, undefined, didError);
90
}
91
} catch (err) {
92
- if (__DEV__ && !hasLoggedError) {
93
- hasLoggedError = true;
94
- warningWithoutStack(
95
- false,
96
- 'React instrumentation encountered an error: %s',
97
- err,
98
- );
92
+ if (__DEV__) {
93
+ if (!hasLoggedError) {
94
+ hasLoggedError = true;
95
+ warningWithoutStack(
96
+ false,
97
+ 'React instrumentation encountered an error: %s',
98
+ err,
99
+ );
100
+ }
101
}
102
}
103
};
@@ -103,13 +105,15 @@ export function injectInternals(internals: Object): boolean {
105
try {
106
hook.onCommitFiberUnmount(rendererID, fiber);
107
} catch (err) {
106
- if (__DEV__ && !hasLoggedError) {
107
- hasLoggedError = true;
108
- warningWithoutStack(
109
- false,
110
- 'React instrumentation encountered an error: %s',
111
- err,
112
- );
108
+ if (__DEV__) {
109
+ if (!hasLoggedError) {
110
+ hasLoggedError = true;
111
+ warningWithoutStack(
112
+ false,
113
+ 'React instrumentation encountered an error: %s',
114
+ err,
115
+ );
116
+ }
117
}
118
}
119
};
packages/react-reconciler/src/ReactFiberReconciler.js
+8
-6
@@ -280,12 +280,14 @@ export function updateContainer(
280
281
callback = callback === undefined ? null : callback;
282
if (callback !== null) {
283
- warningWithoutStack(
284
- typeof callback === 'function',
285
- 'render(...): Expected the last optional `callback` argument to be a ' +
286
- 'function. Instead received: %s.',
287
- callback,
288
- );
283
+ if (__DEV__) {
284
+ warningWithoutStack(
285
+ typeof callback === 'function',
286
+ 'render(...): Expected the last optional `callback` argument to be a ' +
287
+ 'function. Instead received: %s.',
288
+ callback,
289
+ );
290
+ }
291
update.callback = callback;
292
}
293
packages/react-reconciler/src/ReactFiberWorkLoop.js
+8
-6
@@ -1089,12 +1089,14 @@ export function flushDiscreteUpdates() {
1089
(executionContext & (BatchedContext | RenderContext | CommitContext)) !==
1090
NoContext
1091
) {
1092
- if (__DEV__ && (executionContext & RenderContext) !== NoContext) {
1093
- warning(
1094
- false,
1095
- 'unstable_flushDiscreteUpdates: Cannot flush updates when React is ' +
1096
- 'already rendering.',
1097
- );
1092
+ if (__DEV__) {
1093
+ if ((executionContext & RenderContext) !== NoContext) {
1094
+ warning(
1095
+ false,
1096
+ 'unstable_flushDiscreteUpdates: Cannot flush updates when React is ' +
1097
+ 'already rendering.',
1098
+ );
1099
+ }
1100
}
1101
// We're already rendering, so we can't synchronously flush pending work.
1102
// This is probably a nested event dispatch triggered by a lifecycle/effect,
packages/react-test-renderer/src/ReactShallowRenderer.js
+24
-20
@@ -61,29 +61,33 @@ function areHookInputsEqual(
61
prevDeps: Array<mixed> | null,
62
) {
63
if (prevDeps === null) {
64
- warning(
65
- false,
66
- '%s received a final argument during this render, but not during ' +
67
- 'the previous render. Even though the final argument is optional, ' +
68
- 'its type cannot change between renders.',
69
- currentHookNameInDev,
70
- );
64
+ if (__DEV__) {
65
+ warning(
66
+ false,
67
+ '%s received a final argument during this render, but not during ' +
68
+ 'the previous render. Even though the final argument is optional, ' +
69
+ 'its type cannot change between renders.',
70
+ currentHookNameInDev,
71
+ );
72
+ }
73
return false;
74
}
75
74
- // Don't bother comparing lengths in prod because these arrays should be
75
- // passed inline.
76
- if (nextDeps.length !== prevDeps.length) {
77
- warning(
78
- false,
79
- 'The final argument passed to %s changed size between renders. The ' +
80
- 'order and size of this array must remain constant.\n\n' +
81
- 'Previous: %s\n' +
82
- 'Incoming: %s',
83
- currentHookNameInDev,
84
- `[${nextDeps.join(', ')}]`,
85
- `[${prevDeps.join(', ')}]`,
86
- );
76
+ if (__DEV__) {
77
+ // Don't bother comparing lengths in prod because these arrays should be
78
+ // passed inline.
79
+ if (nextDeps.length !== prevDeps.length) {
80
+ warning(
81
+ false,
82
+ 'The final argument passed to %s changed size between renders. The ' +
83
+ 'order and size of this array must remain constant.\n\n' +
84
+ 'Previous: %s\n' +
85
+ 'Incoming: %s',
86
+ currentHookNameInDev,
87
+ `[${nextDeps.join(', ')}]`,
88
+ `[${prevDeps.join(', ')}]`,
89
+ );
90
+ }
91
}
92
for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
93
if (is(nextDeps[i], prevDeps[i])) {
packages/react-test-renderer/src/ReactTestHostConfig.js
+9
-7
@@ -214,13 +214,15 @@ export function createTextInstance(
214
hostContext: Object,
215
internalInstanceHandle: Object,
216
): TextInstance {
217
- if (__DEV__ && enableFlareAPI) {
218
- warning(
219
- hostContext !== EVENT_COMPONENT_CONTEXT,
220
- 'validateDOMNesting: React event components cannot have text DOM nodes as children. ' +
221
- 'Wrap the child text "%s" in an element.',
222
- text,
223
- );
217
+ if (__DEV__) {
218
+ if (enableFlareAPI) {
219
+ warning(
220
+ hostContext !== EVENT_COMPONENT_CONTEXT,
221
+ 'validateDOMNesting: React event components cannot have text DOM nodes as children. ' +
222
+ 'Wrap the child text "%s" in an element.',
223
+ text,
224
+ );
225
+ }
226
}
227
return {
228
text,
packages/react/src/ReactElement.js
+24
-20
@@ -48,16 +48,18 @@ function hasValidKey(config) {
48
49
function defineKeyPropWarningGetter(props, displayName) {
50
const warnAboutAccessingKey = function() {
51
- if (!specialPropKeyWarningShown) {
52
- specialPropKeyWarningShown = true;
53
- warningWithoutStack(
54
- false,
55
- '%s: `key` is not a prop. Trying to access it will result ' +
56
- 'in `undefined` being returned. If you need to access the same ' +
57
- 'value within the child component, you should pass it as a different ' +
58
- 'prop. (https://fb.me/react-special-props)',
59
- displayName,
60
- );
51
+ if (__DEV__) {
52
+ if (!specialPropKeyWarningShown) {
53
+ specialPropKeyWarningShown = true;
54
+ warningWithoutStack(
55
+ false,
56
+ '%s: `key` is not a prop. Trying to access it will result ' +
57
+ 'in `undefined` being returned. If you need to access the same ' +
58
+ 'value within the child component, you should pass it as a different ' +
59
+ 'prop. (https://fb.me/react-special-props)',
60
+ displayName,
61
+ );
62
+ }
63
}
64
};
65
warnAboutAccessingKey.isReactWarning = true;
@@ -69,16 +71,18 @@ function defineKeyPropWarningGetter(props, displayName) {
71
72
function defineRefPropWarningGetter(props, displayName) {
73
const warnAboutAccessingRef = function() {
72
- if (!specialPropRefWarningShown) {
73
- specialPropRefWarningShown = true;
74
- warningWithoutStack(
75
- false,
76
- '%s: `ref` is not a prop. Trying to access it will result ' +
77
- 'in `undefined` being returned. If you need to access the same ' +
78
- 'value within the child component, you should pass it as a different ' +
79
- 'prop. (https://fb.me/react-special-props)',
80
- displayName,
81
- );
74
+ if (__DEV__) {
75
+ if (!specialPropRefWarningShown) {
76
+ specialPropRefWarningShown = true;
77
+ warningWithoutStack(
78
+ false,
79
+ '%s: `ref` is not a prop. Trying to access it will result ' +
80
+ 'in `undefined` being returned. If you need to access the same ' +
81
+ 'value within the child component, you should pass it as a different ' +
82
+ 'prop. (https://fb.me/react-special-props)',
83
+ displayName,
84
+ );
85
+ }
86
}
87
};
88
warnAboutAccessingRef.isReactWarning = true;
packages/react/src/ReactElementValidator.js
+100
-88
@@ -194,49 +194,51 @@ function validateChildKeys(node, parentType) {
194
* @param {ReactElement} element
195
*/
196
function validatePropTypes(element) {
197
- const type = element.type;
198
- if (type === null || type === undefined || typeof type === 'string') {
199
- return;
200
- }
201
- const name = getComponentName(type);
202
- let propTypes;
203
- if (typeof type === 'function') {
204
- propTypes = type.propTypes;
205
- } else if (
206
- typeof type === 'object' &&
207
- (type.$$typeof === REACT_FORWARD_REF_TYPE ||
208
- // Note: Memo only checks outer props here.
209
- // Inner props are checked in the reconciler.
210
- type.$$typeof === REACT_MEMO_TYPE)
211
- ) {
212
- propTypes = type.propTypes;
213
- } else {
214
- return;
215
- }
216
- if (propTypes) {
217
- setCurrentlyValidatingElement(element);
218
- checkPropTypes(
219
- propTypes,
220
- element.props,
221
- 'prop',
222
- name,
223
- ReactDebugCurrentFrame.getStackAddendum,
224
- );
225
- setCurrentlyValidatingElement(null);
226
- } else if (type.PropTypes !== undefined && !propTypesMisspellWarningShown) {
227
- propTypesMisspellWarningShown = true;
228
- warningWithoutStack(
229
- false,
230
- 'Component %s declared `PropTypes` instead of `propTypes`. Did you misspell the property assignment?',
231
- name || 'Unknown',
232
- );
233
- }
234
- if (typeof type.getDefaultProps === 'function') {
235
- warningWithoutStack(
236
- type.getDefaultProps.isReactClassApproved,
237
- 'getDefaultProps is only used on classic React.createClass ' +
238
- 'definitions. Use a static property named `defaultProps` instead.',
239
- );
197
+ if (__DEV__) {
198
+ const type = element.type;
199
+ if (type === null || type === undefined || typeof type === 'string') {
200
+ return;
201
+ }
202
+ const name = getComponentName(type);
203
+ let propTypes;
204
+ if (typeof type === 'function') {
205
+ propTypes = type.propTypes;
206
+ } else if (
207
+ typeof type === 'object' &&
208
+ (type.$$typeof === REACT_FORWARD_REF_TYPE ||
209
+ // Note: Memo only checks outer props here.
210
+ // Inner props are checked in the reconciler.
211
+ type.$$typeof === REACT_MEMO_TYPE)
212
+ ) {
213
+ propTypes = type.propTypes;
214
+ } else {
215
+ return;
216
+ }
217
+ if (propTypes) {
218
+ setCurrentlyValidatingElement(element);
219
+ checkPropTypes(
220
+ propTypes,
221
+ element.props,
222
+ 'prop',
223
+ name,
224
+ ReactDebugCurrentFrame.getStackAddendum,
225
+ );
226
+ setCurrentlyValidatingElement(null);
227
+ } else if (type.PropTypes !== undefined && !propTypesMisspellWarningShown) {
228
+ propTypesMisspellWarningShown = true;
229
+ warningWithoutStack(
230
+ false,
231
+ 'Component %s declared `PropTypes` instead of `propTypes`. Did you misspell the property assignment?',
232
+ name || 'Unknown',
233
+ );
234
+ }
235
+ if (typeof type.getDefaultProps === 'function') {
236
+ warningWithoutStack(
237
+ type.getDefaultProps.isReactClassApproved,
238
+ 'getDefaultProps is only used on classic React.createClass ' +
239
+ 'definitions. Use a static property named `defaultProps` instead.',
240
+ );
241
+ }
242
}
243
}
244
@@ -245,27 +247,29 @@ function validatePropTypes(element) {
247
* @param {ReactElement} fragment
248
*/
249
function validateFragmentProps(fragment) {
248
- setCurrentlyValidatingElement(fragment);
250
+ if (__DEV__) {
251
+ setCurrentlyValidatingElement(fragment);
252
250
- const keys = Object.keys(fragment.props);
251
- for (let i = 0; i < keys.length; i++) {
252
- const key = keys[i];
253
- if (key !== 'children' && key !== 'key') {
254
- warning(
255
- false,
256
- 'Invalid prop `%s` supplied to `React.Fragment`. ' +
257
- 'React.Fragment can only have `key` and `children` props.',
258
- key,
259
- );
260
- break;
253
+ const keys = Object.keys(fragment.props);
254
+ for (let i = 0; i < keys.length; i++) {
255
+ const key = keys[i];
256
+ if (key !== 'children' && key !== 'key') {
257
+ warning(
258
+ false,
259
+ 'Invalid prop `%s` supplied to `React.Fragment`. ' +
260
+ 'React.Fragment can only have `key` and `children` props.',
261
+ key,
262
+ );
263
+ break;
264
+ }
265
}
262
- }
266
264
- if (fragment.ref !== null) {
265
- warning(false, 'Invalid attribute `ref` supplied to `React.Fragment`.');
266
- }
267
+ if (fragment.ref !== null) {
268
+ warning(false, 'Invalid attribute `ref` supplied to `React.Fragment`.');
269
+ }
270
268
- setCurrentlyValidatingElement(null);
271
+ setCurrentlyValidatingElement(null);
272
+ }
273
}
274
275
export function jsxWithValidation(
@@ -313,14 +317,16 @@ export function jsxWithValidation(
317
typeString = typeof type;
318
}
319
316
- warning(
317
- false,
318
- 'React.jsx: type is invalid -- expected a string (for ' +
319
- 'built-in components) or a class/function (for composite ' +
320
- 'components) but got: %s.%s',
321
- typeString,
322
- info,
323
- );
320
+ if (__DEV__) {
321
+ warning(
322
+ false,
323
+ 'React.jsx: type is invalid -- expected a string (for ' +
324
+ 'built-in components) or a class/function (for composite ' +
325
+ 'components) but got: %s.%s',
326
+ typeString,
327
+ info,
328
+ );
329
+ }
330
}
331
332
const element = jsxDEV(type, props, key, source, self);
@@ -350,12 +356,14 @@ export function jsxWithValidation(
356
Object.freeze(children);
357
}
358
} else {
353
- warning(
354
- false,
355
- 'React.jsx: Static children should always be an array. ' +
356
- 'You are likely explicitly calling React.jsxs or React.jsxDEV. ' +
357
- 'Use the Babel transform instead.',
358
- );
359
+ if (__DEV__) {
360
+ warning(
361
+ false,
362
+ 'React.jsx: Static children should always be an array. ' +
363
+ 'You are likely explicitly calling React.jsxs or React.jsxDEV. ' +
364
+ 'Use the Babel transform instead.',
365
+ );
366
+ }
367
}
368
} else {
369
validateChildKeys(children, type);
@@ -364,12 +372,14 @@ export function jsxWithValidation(
372
}
373
374
if (hasOwnProperty.call(props, 'key')) {
367
- warning(
368
- false,
369
- 'React.jsx: Spreading a key to JSX is a deprecated pattern. ' +
370
- 'Explicitly pass a key after spreading props in your JSX call. ' +
371
- 'E.g. <ComponentName {...props} key={key} />',
372
- );
375
+ if (__DEV__) {
376
+ warning(
377
+ false,
378
+ 'React.jsx: Spreading a key to JSX is a deprecated pattern. ' +
379
+ 'Explicitly pass a key after spreading props in your JSX call. ' +
380
+ 'E.g. <ComponentName {...props} key={key} />',
381
+ );
382
+ }
383
}
384
385
if (type === REACT_FRAGMENT_TYPE) {
@@ -431,14 +441,16 @@ export function createElementWithValidation(type, props, children) {
441
typeString = typeof type;
442
}
443
434
- warning(
435
- false,
436
- 'React.createElement: type is invalid -- expected a string (for ' +
437
- 'built-in components) or a class/function (for composite ' +
438
- 'components) but got: %s.%s',
439
- typeString,
440
- info,
441
- );
444
+ if (__DEV__) {
445
+ warning(
446
+ false,
447
+ 'React.createElement: type is invalid -- expected a string (for ' +
448
+ 'built-in components) or a class/function (for composite ' +
449
+ 'components) but got: %s.%s',
450
+ typeString,
451
+ info,
452
+ );
453
+ }
454
}
455
456
const element = createElement.apply(this, arguments);
scripts/babel/__tests__/lift-warning-conditional-argument-test.js
renamed
+4
-4
@@ -8,7 +8,7 @@
8
'use strict';
9
10
let babel = require('@babel/core');
11
-let wrapWarningWithEnvCheck = require('../wrap-warning-with-env-check');
11
+let wrapWarningWithEnvCheck = require('../lift-warning-conditional-argument');
12
13
function transform(input) {
14
return babel.transform(input, {
@@ -23,7 +23,7 @@ function compare(input, output) {
23
24
let oldEnv;
25
26
-describe('wrap-warning-with-env-check', () => {
26
+describe('lift-warning-conditional-argument', () => {
27
beforeEach(() => {
28
oldEnv = process.env.NODE_ENV;
29
process.env.NODE_ENV = '';
@@ -36,14 +36,14 @@ describe('wrap-warning-with-env-check', () => {
36
it('should wrap warning calls', () => {
37
compare(
38
"warning(condition, 'a %s b', 'c');",
39
- "__DEV__ ? !condition ? warning(false, 'a %s b', 'c') : void 0 : void 0;"
39
+ "!condition ? warning(false, 'a %s b', 'c') : void 0;"
40
);
41
});
42
43
it('should wrap warningWithoutStack calls', () => {
44
compare(
45
"warningWithoutStack(condition, 'a %s b', 'c');",
46
- "__DEV__ ? !condition ? warningWithoutStack(false, 'a %s b', 'c') : void 0 : void 0;"
46
+ "!condition ? warningWithoutStack(false, 'a %s b', 'c') : void 0;"
47
);
48
});
49
scripts/babel/lift-warning-conditional-argument.js
renamed
+4
-13
@@ -9,8 +9,6 @@
9
module.exports = function(babel, options) {
10
const t = babel.types;
11
12
- const DEV_EXPRESSION = t.identifier('__DEV__');
13
-
12
const SEEN_SYMBOL = Symbol('expression.seen');
13
14
return {
@@ -34,10 +32,8 @@ module.exports = function(babel, options) {
32
//
33
// into this:
34
//
37
- // if (__DEV__) {
38
- // if (!condition) {
39
- // warning(false, argument, argument);
40
- // }
35
+ // if (!condition) {
36
+ // warning(false, argument, argument);
37
// }
38
//
39
// The goal is to strip out warning calls entirely in production
@@ -50,13 +46,8 @@ module.exports = function(babel, options) {
46
newNode[SEEN_SYMBOL] = true;
47
path.replaceWith(
48
t.ifStatement(
53
- DEV_EXPRESSION,
54
- t.blockStatement([
55
- t.ifStatement(
56
- t.unaryExpression('!', condition),
57
- t.expressionStatement(newNode)
58
- ),
59
- ])
49
+ t.unaryExpression('!', condition),
50
+ t.expressionStatement(newNode)
51
)
52
);
53
}
scripts/eslint-rules/__tests__/no-production-logging-test.internal.js
new
+234
@@ -0,0 +1,234 @@
1
+/**
2
+ * Copyright (c) Facebook, Inc. and its 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
+ * @emails react-core
8
+ */
9
+
10
+'use strict';
11
+
12
+const rule = require('../no-production-logging');
13
+const RuleTester = require('eslint').RuleTester;
14
+const ruleTester = new RuleTester();
15
+
16
+ruleTester.run('no-production-logging', rule, {
17
+ valid: [
18
+ {
19
+ code: `
20
+ if (__DEV__) {
21
+ warning(test, 'Oh no');
22
+ }
23
+ `,
24
+ },
25
+ {
26
+ code: `
27
+ if (__DEV__) {
28
+ warningWithoutStack(test, 'Oh no');
29
+ }
30
+ `,
31
+ },
32
+ {
33
+ code: `
34
+ if (__DEV__) {
35
+ lowPriorityWarning(test, 'Oh no');
36
+ }
37
+ `,
38
+ },
39
+ {
40
+ code: `
41
+ if (__DEV__) {
42
+ lowPriorityWarningWithoutStack(test, 'Oh no');
43
+ }
44
+ `,
45
+ },
46
+ // This is OK too because it's wrapped outside:
47
+ {
48
+ code: `
49
+ if (__DEV__) {
50
+ if (potato) {
51
+ while (true) {
52
+ warning(test, 'Oh no');
53
+ }
54
+ }
55
+ }`,
56
+ },
57
+ {
58
+ code: `
59
+ var f;
60
+ if (__DEV__) {
61
+ f = function() {
62
+ if (potato) {
63
+ while (true) {
64
+ warning(test, 'Oh no');
65
+ }
66
+ }
67
+ };
68
+ }`,
69
+ },
70
+ // Don't do anything with these:
71
+ {
72
+ code: 'normalFunctionCall(test);',
73
+ },
74
+ {
75
+ code: 'invariant(test);',
76
+ },
77
+ {
78
+ code: `
79
+ if (__DEV__) {
80
+ normalFunctionCall(test);
81
+ }
82
+ `,
83
+ },
84
+ // This is OK because of the outer if.
85
+ {
86
+ code: `
87
+ if (__DEV__) {
88
+ if (foo) {
89
+ if (__DEV__) {
90
+ } else {
91
+ warning(test, 'Oh no');
92
+ }
93
+ }
94
+ }`,
95
+ },
96
+ ],
97
+ invalid: [
98
+ {
99
+ code: 'warning(test);',
100
+ errors: [
101
+ {
102
+ message: `Wrap warning() in an "if (__DEV__) {}" check`,
103
+ },
104
+ ],
105
+ },
106
+ {
107
+ code: 'warningWithoutStack(test)',
108
+ errors: [
109
+ {
110
+ message: `Wrap warningWithoutStack() in an "if (__DEV__) {}" check`,
111
+ },
112
+ ],
113
+ },
114
+ {
115
+ code: `
116
+ if (potato) {
117
+ warningWithoutStack(test);
118
+ }
119
+ `,
120
+ errors: [
121
+ {
122
+ message: `Wrap warningWithoutStack() in an "if (__DEV__) {}" check`,
123
+ },
124
+ ],
125
+ },
126
+ {
127
+ code: 'lowPriorityWarning(test);',
128
+ errors: [
129
+ {
130
+ message: `Wrap lowPriorityWarning() in an "if (__DEV__) {}" check`,
131
+ },
132
+ ],
133
+ },
134
+ {
135
+ code: 'lowPriorityWarningWithoutStack(test)',
136
+ errors: [
137
+ {
138
+ message: `Wrap lowPriorityWarningWithoutStack() in an "if (__DEV__) {}" check`,
139
+ },
140
+ ],
141
+ },
142
+ {
143
+ code: `
144
+ if (potato) {
145
+ lowPriorityWarningWithoutStack(test);
146
+ }
147
+ `,
148
+ errors: [
149
+ {
150
+ message: `Wrap lowPriorityWarningWithoutStack() in an "if (__DEV__) {}" check`,
151
+ },
152
+ ],
153
+ },
154
+ {
155
+ code: `
156
+ if (__DEV__ || potato && true) {
157
+ warning(test);
158
+ }
159
+ `,
160
+ errors: [
161
+ {
162
+ message: `Wrap warning() in an "if (__DEV__) {}" check`,
163
+ },
164
+ ],
165
+ },
166
+ {
167
+ code: `
168
+ if (banana && __DEV__ && potato && kitten) {
169
+ warning(test);
170
+ }
171
+ `,
172
+ // Technically this code is valid but we prefer
173
+ // explicit standalone __DEV__ blocks that stand out.
174
+ errors: [
175
+ {
176
+ message: `Wrap warning() in an "if (__DEV__) {}" check`,
177
+ },
178
+ ],
179
+ },
180
+ {
181
+ code: `
182
+ if (!__DEV__) {
183
+ warning(test);
184
+ }
185
+ `,
186
+ errors: [
187
+ {
188
+ message: `Wrap warning() in an "if (__DEV__) {}" check`,
189
+ },
190
+ ],
191
+ },
192
+ {
193
+ code: `
194
+ if (foo || x && __DEV__) {
195
+ warning(test);
196
+ }
197
+ `,
198
+ errors: [
199
+ {
200
+ message: `Wrap warning() in an "if (__DEV__) {}" check`,
201
+ },
202
+ ],
203
+ },
204
+ {
205
+ code: `
206
+ if (__DEV__) {
207
+ } else {
208
+ warning(test);
209
+ }
210
+ `,
211
+ errors: [
212
+ {
213
+ message: `Wrap warning() in an "if (__DEV__) {}" check`,
214
+ },
215
+ ],
216
+ },
217
+ {
218
+ code: `
219
+ if (__DEV__) {
220
+ } else {
221
+ if (__DEV__) {
222
+ } else {
223
+ warning(test);
224
+ }
225
+ }
226
+ `,
227
+ errors: [
228
+ {
229
+ message: `Wrap warning() in an "if (__DEV__) {}" check`,
230
+ },
231
+ ],
232
+ },
233
+ ],
234
+});
scripts/eslint-rules/index.js
+1
@@ -5,5 +5,6 @@ module.exports = {
5
'no-primitive-constructors': require('./no-primitive-constructors'),
6
'no-to-warn-dev-within-to-throw': require('./no-to-warn-dev-within-to-throw'),
7
'warning-and-invariant-args': require('./warning-and-invariant-args'),
8
+ 'no-production-logging': require('./no-production-logging'),
9
},
10
};
scripts/eslint-rules/no-production-logging.js
new
+72
@@ -0,0 +1,72 @@
1
+/**
2
+ * Copyright (c) Facebook, Inc. and its 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
+ * @emails react-core
8
+ */
9
+
10
+'use strict';
11
+
12
+const LOGGER_FN_NAMES = [
13
+ 'warning',
14
+ 'warningWithoutStack',
15
+ 'lowPriorityWarning',
16
+ 'lowPriorityWarningWithoutStack',
17
+];
18
+
19
+module.exports = function(context) {
20
+ function isInDEVBlock(node) {
21
+ let done = false;
22
+ while (!done) {
23
+ let parent = node.parent;
24
+ if (!parent) {
25
+ return false;
26
+ }
27
+ if (
28
+ parent.type === 'IfStatement' &&
29
+ node === parent.consequent &&
30
+ parent.test.type === 'Identifier' &&
31
+ // This is intentionally strict so we can
32
+ // see blocks of DEV-only code at once.
33
+ parent.test.name === '__DEV__'
34
+ ) {
35
+ return true;
36
+ }
37
+ node = parent;
38
+ }
39
+ }
40
+
41
+ function report(node) {
42
+ context.report({
43
+ node: node,
44
+ message: `Wrap {{identifier}}() in an "if (__DEV__) {}" check`,
45
+ data: {
46
+ identifier: node.callee.name,
47
+ },
48
+ fix: function(fixer) {
49
+ return [
50
+ fixer.insertTextBefore(node.parent, `if (__DEV__) {`),
51
+ fixer.insertTextAfter(node.parent, '}'),
52
+ ];
53
+ },
54
+ });
55
+ }
56
+
57
+ const isLoggerFunctionName = name => LOGGER_FN_NAMES.includes(name);
58
+
59
+ return {
60
+ meta: {
61
+ fixable: 'code',
62
+ },
63
+ CallExpression: function(node) {
64
+ if (!isLoggerFunctionName(node.callee.name)) {
65
+ return;
66
+ }
67
+ if (!isInDEVBlock(node)) {
68
+ report(node);
69
+ }
70
+ },
71
+ };
72
+};
scripts/jest/preprocessor.js
+1
-1
@@ -17,7 +17,7 @@ const pathToBabelPluginDevWithCode = require.resolve(
17
'../error-codes/transform-error-messages'
18
);
19
const pathToBabelPluginWrapWarning = require.resolve(
20
- '../babel/wrap-warning-with-env-check'
20
+ '../babel/lift-warning-conditional-argument'
21
);
22
const pathToBabelPluginAsyncToGenerator = require.resolve(
23
'@babel/plugin-transform-async-to-generator'
scripts/rollup/build.js
+3
-3
@@ -125,7 +125,7 @@ function getBabelConfig(updateBabelOptions, bundleType, filename) {
125
// Minify invariant messages
126
require('../error-codes/transform-error-messages'),
127
// Wrap warning() calls in a __DEV__ check so they are stripped from production.
128
- require('../babel/wrap-warning-with-env-check'),
128
+ require('../babel/lift-warning-conditional-argument'),
129
]),
130
});
131
case RN_OSS_DEV:
@@ -142,7 +142,7 @@ function getBabelConfig(updateBabelOptions, bundleType, filename) {
142
{noMinify: true},
143
],
144
// Wrap warning() calls in a __DEV__ check so they are stripped from production.
145
- require('../babel/wrap-warning-with-env-check'),
145
+ require('../babel/lift-warning-conditional-argument'),
146
]),
147
});
148
case UMD_DEV:
@@ -158,7 +158,7 @@ function getBabelConfig(updateBabelOptions, bundleType, filename) {
158
// Minify invariant messages
159
require('../error-codes/transform-error-messages'),
160
// Wrap warning() calls in a __DEV__ check so they are stripped from production.
161
- require('../babel/wrap-warning-with-env-check'),
161
+ require('../babel/lift-warning-conditional-argument'),
162
]),
163
});
164
default: