@samitouri / QOS-React-2 / commits / b43eec7eaa

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: