Repository: facebook/react
Pull request: Combine ReactJSXElementValidator with main module

There are too many layers to the JSX runtime implementation. I think basically everything should be implemented in a single file, so that's what I'm going to do.

As a first step, this deletes ReactJSXElementValidator and moves all the code into ReactJSXElement. I can already see how this will help us remove more indirections in the future.

Next I'm going to do start moving the `createElement` runtime into this module as well, since there's a lot of duplicated code.

Changed files:
filename: packages/react/src/jsx/ReactJSX.js
patch: @@ -8,15 +8,21 @@
  */
 import {REACT_FRAGMENT_TYPE} from 'shared/ReactSymbols';
 import {
-  jsxWithValidationStatic,
-  jsxWithValidationDynamic,
-  jsxWithValidation,
-} from './ReactJSXElementValidator';
-import {jsx as jsxProd} from './ReactJSXElement';
-const jsx: any = __DEV__ ? jsxWithValidationDynamic : jsxProd;
+  jsxProd,
+  jsxProdSignatureRunningInDevWithDynamicChildren,
+  jsxProdSignatureRunningInDevWithStaticChildren,
+  jsxDEV as _jsxDEV,
+} from './ReactJSXElement';
+
+const jsx: any = __DEV__
+  ? jsxProdSignatureRunningInDevWithDynamicChildren
+  : jsxProd;
 // we may want to special case jsxs internally to take advantage of static children.
 // for now we can ship identical prod functions
-const jsxs: any = __DEV__ ? jsxWithValidationStatic : jsxProd;
-const jsxDEV: any = __DEV__ ? jsxWithValidation : undefined;
+const jsxs: any = __DEV__
+  ? jsxProdSignatureRunningInDevWithStaticChildren
+  : jsxProd;
+
+const jsxDEV: any = __DEV__ ? _jsxDEV : undefined;
 
 export {REACT_FRAGMENT_TYPE as Fragment, jsx, jsxs, jsxDEV};

filename: packages/react/src/jsx/ReactJSXElement.js
patch: @@ -8,10 +8,23 @@
 import getComponentNameFromType from 'shared/getComponentNameFromType';
 import ReactSharedInternals from 'shared/ReactSharedInternals';
 import hasOwnProperty from 'shared/hasOwnProperty';
-import {REACT_ELEMENT_TYPE} from 'shared/ReactSymbols';
+import {
+  getIteratorFn,
+  REACT_ELEMENT_TYPE,
+  REACT_FORWARD_REF_TYPE,
+  REACT_MEMO_TYPE,
+  REACT_FRAGMENT_TYPE,
+} from 'shared/ReactSymbols';
 import {checkKeyStringCoercion} from 'shared/CheckStringCoercion';
+import isValidElementType from 'shared/isValidElementType';
+import isArray from 'shared/isArray';
+import {describeUnknownElementTypeFrameInDEV} from 'shared/ReactComponentStackFrame';
+import checkPropTypes from 'shared/checkPropTypes';
 
 const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
+const ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame;
+
+const REACT_CLIENT_REFERENCE = Symbol.for('react.client.reference');
 
 let specialPropKeyWarningShown;
 let specialPropRefWarningShown;
@@ -192,7 +205,7 @@ function ReactElement(type, key, ref, self, source, owner, props) {
  * @param {object} props
  * @param {string} key
  */
-export function jsx(type, config, maybeKey) {
+export function jsxProd(type, config, maybeKey) {
   let propName;
 
   // Reserved names are extracted
@@ -259,14 +272,157 @@ export function jsx(type, config, maybeKey) {
   );
 }
 
+// While `jsxDEV` should never be called when running in production, we do
+// support `jsx` and `jsxs` when running in development. This supports the case
+// where a third-party dependency ships code that was compiled for production;
+// we want to still provide warnings in development.
+//
+// So these functions are the _dev_ implementations of the _production_
+// API signatures.
+//
+// Since these functions are dev-only, it's ok to add an indirection here. They
+// only exist to provide different versions of `isStaticChildren`. (We shouldn't
+// use this pattern for the prod versions, though, because it will add an call
+// frame.)
+export function jsxProdSignatureRunningInDevWithDynamicChildren(
+  type,
+  config,
+  maybeKey,
+  source,
+  self,
+) {
+  if (__DEV__) {
+    const isStaticChildren = false;
+    return jsxDEV(type, config, maybeKey, isStaticChildren, source, self);
+  }
+}
+
+export function jsxProdSignatureRunningInDevWithStaticChildren(
+  type,
+  config,
+  maybeKey,
+  source,
+  self,
+) {
+  if (__DEV__) {
+    const isStaticChildren = true;
+    return jsxDEV(type, config, maybeKey, isStaticChildren, source, self);
+  }
+}
+
+const didWarnAboutKeySpread = {};
+
 /**
  * https://github.com/reactjs/rfcs/pull/107
  * @param {*} type
  * @param {object} props
  * @param {string} key
  */
-export function jsxDEV(type, config, maybeKey, source, self) {
+export function jsxDEV(type, config, maybeKey, isStaticChildren, source, self) {
   if (__DEV__) {
+    if (!isValidElementType(type)) {
+      // This is an invalid element type.
+      //
+      // We warn in this case but don't throw. We expect the element creation to
+      // succeed and there will likely be errors in render.
+      let info = '';
+      if (
+        type === undefined ||
+        (typeof type === 'object' &&
+          type !== null &&
+          Object.keys(type).length === 0)
+      ) {
+        info +=
+          ' You likely forgot to export your component from the file ' +
+          "it's defined in, or you might have mixed up default and named imports.";
+      }
+
+      const sourceInfo = getSourceInfoErrorAddendum(source);
+      if (sourceInfo) {
+        info += sourceInfo;
+      } else {
+        info += getDeclarationErrorAddendum();
+      }
+
+      let typeString;
+      if (type === null) {
+        typeString = 'null';
+      } else if (isArray(type)) {
+        typeString = 'array';
+      } else if (type !== undefined && type.$$typeof === REACT_ELEMENT_TYPE) {
+        typeString = `<${getComponentNameFromType(type.type) || 'Unknown'} />`;
+        info =
+          ' Did you accidentally export a JSX literal instead of a component?';
+      } else {
+        typeString = typeof type;
+      }
+
+      console.error(
+        'React.jsx: type is invalid -- expected a string (for ' +
+          'built-in components) or a class/function (for composite ' +
+          'components) but got: %s.%s',
+        typeString,
+        info,
+      );
+    } else {
+      // This is a valid element type.
+
+      // Skip key warning if the type isn't valid since our key validation logic
+      // doesn't expect a non-string/function type and can throw confusing
+      // errors. We don't want exception behavior to differ between dev and
+      // prod. (Rendering will throw with a helpful message and as soon as the
+      // type is fixed, the key warnings will appear.)
+      const children = config.children;
+      if (children !== undefined) {
+        if (isStaticChildren) {
+          if (isArray(children)) {
+            for (let i = 0; i < children.length; i++) {
+              validateChildKeys(children[i], type);
+            }
+
+            if (Object.freeze) {
+              Object.freeze(children);
+            }
+          } else {
+            console.error(
+              'React.jsx: Static children should always be an array. ' +
+                'You are likely explicitly calling React.jsxs or React.jsxDEV. ' +
+                'Use the Babel transform instead.',
+            );
+          }
+        } else {
+          validateChildKeys(children, type);
+        }
+      }
+    }
+
+    // Warn about key spread regardless of whether the type is valid.
+    if (hasOwnProperty.call(config, 'key')) {
+      const componentName = getComponentNameFromType(type);
+      const keys = Object.keys(config).filter(k => k !== 'key');
+      const beforeExample =
+        keys.length > 0
+          ? '{key: someKey, ' + keys.join(': ..., ') + ': ...}'
+          : '{key: someKey}';
+      if (!didWarnAboutKeySpread[componentName + beforeExample]) {
+        const afterExample =
+          keys.length > 0 ? '{' + keys.join(': ..., ') + ': ...}' : '{}';
+        console.error(
+          'A props object containing a "key" prop is being spread into JSX:\n' +
+            '  let props = %s;\n' +
+            '  <%s {...props} />\n' +
+            'React keys must be passed directly to JSX without using spread:\n' +
+            '  let props = %s;\n' +
+            '  <%s key={someKey} {...props} />',
+          beforeExample,
+          componentName,
+          afterExample,
+          componentName,
+        );
+        didWarnAboutKeySpread[componentName + beforeExample] = true;
+      }
+    }
+
     let propName;
 
     // Reserved names are extracted
@@ -336,7 +492,7 @@ export function jsxDEV(type, config, maybeKey, source, self) {
       }
     }
 
-    return ReactElement(
+    const element = ReactElement(
       type,
       key,
       ref,
@@ -345,5 +501,266 @@ export function jsxDEV(type, config, maybeKey, source, self) {
       ReactCurrentOwner.current,
       props,
     );
+
+    if (type === REACT_FRAGMENT_TYPE) {
+      validateFragmentProps(element);
+    } else {
+      validatePropTypes(element);
+    }
+
+    return element;
+  }
+}
+
+function getDeclarationErrorAddendum() {
+  if (__DEV__) {
+    if (ReactCurrentOwner.current) {
+      const name = getComponentNameFromType(ReactCurrentOwner.current.type);
+      if (name) {
+        return '\n\nCheck the render method of `' + name + '`.';
+      }
+    }
+    return '';
+  }
+}
+
+function getSourceInfoErrorAddendum(source) {
+  if (__DEV__) {
+    if (source !== undefined) {
+      const fileName = source.fileName.replace(/^.*[\\\/]/, '');
+      const lineNumber = source.lineNumber;
+      return '\n\nCheck your code at ' + fileName + ':' + lineNumber + '.';
+    }
+    return '';
+  }
+}
+
+/**
+ * Ensure that every element either is passed in a static location, in an
+ * array with an explicit keys property defined, or in an object literal
+ * with valid key property.
+ *
+ * @internal
+ * @param {ReactNode} node Statically passed child of any type.
+ * @param {*} parentType node's parent's type.
+ */
+function validateChildKeys(node, parentType) {
+  if (__DEV__) {
+    if (typeof node !== 'object' || !node) {
+      return;
+    }
+    if (node.$$typeof === REACT_CLIENT_REFERENCE) {
+      // This is a reference to a client component so it's unknown.
+    } else if (isArray(node)) {
+      for (let i = 0; i < node.length; i++) {
+        const child = node[i];
+        if (isValidElement(child)) {
+          validateExplicitKey(child, parentType);
+        }
+      }
+    } else if (isValidElement(node)) {
+      // This element was passed in a valid location.
+      if (node._store) {
+        node._store.validated = true;
+      }
+    } else {
+      const iteratorFn = getIteratorFn(node);
+      if (typeof iteratorFn === 'function') {
+        // Entry iterators used to provide implicit keys,
+        // but now we print a separate warning for them later.
+        if (iteratorFn !== node.entries) {
+          const iterator = iteratorFn.call(node);
+          let step;
+          while (!(step = iterator.next()).done) {
+            if (isValidElement(step.value)) {
+              validateExplicitKey(step.value, parentType);
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Verifies the object is a ReactElement.
+ * See https://reactjs.org/docs/react-api.html#isvalidelement
+ * @param {?object} object
+ * @return {boolean} True if `object` is a ReactElement.
+ * @final
+ */
+export function isValidElement(object) {
+  if (__DEV__) {
+    return (
+      typeof object === 'object' &&
+      object !== null &&
+      object.$$typeof === REACT_ELEMENT_TYPE
+    );
+  }
+}
+
+const ownerHasKeyUseWarning = {};
+
+/**
+ * Warn if the element doesn't have an explicit key assigned to it.
+ * This element is in an array. The array could grow and shrink or be
+ * reordered. All children that haven't already been validated are required to
+ * have a "key" property assigned to it. Error statuses are cached so a warning
+ * will only be shown once.
+ *
+ * @internal
+ * @param {ReactElement} element Element that requires a key.
+ * @param {*} parentType element's parent's type.
+ */
+function validateExplicitKey(element, parentType) {
+  if (__DEV__) {
+    if (!element._store || element._store.validated || element.key != null) {
+      return;
+    }
+    element._store.validated = true;
+
+    const currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType);
+    if (ownerHasKeyUseWarning[currentComponentErrorInfo]) {
+      return;
+    }
+    ownerHasKeyUseWarning[currentComponentErrorInfo] = true;
+
+    // Usually the current owner is the offender, but if it accepts children as a
+    // property, it may be the creator of the child that's responsible for
+    // assigning it a key.
+    let childOwner = '';
+    if (
+      element &&
+      element._owner &&
+      element._owner !== ReactCurrentOwner.current
+    ) {
+      // Give the component that originally created this child.
+      childOwner = ` It was passed a child from ${getComponentNameFromType(
+        element._owner.type,
+      )}.`;
+    }
+
+    setCurrentlyValidatingElement(element);
+    console.error(
+      'Each child in a list should have a unique "key" prop.' +
+        '%s%s See https://reactjs.org/link/warning-keys for more information.',
+      currentComponentErrorInfo,
+      childOwner,
+    );
+    setCurrentlyValidatingElement(null);
+  }
+}
+
+function setCurrentlyValidatingElement(element) {
+  if (__DEV__) {
+    if (element) {
+      const owner = element._owner;
+      const stack = describeUnknownElementTypeFrameInDEV(
+        element.type,
+        owner ? owner.type : null,
+      );
+      ReactDebugCurrentFrame.setExtraStackFrame(stack);
+    } else {
+      ReactDebugCurrentFrame.setExtraStackFrame(null);
+    }
+  }
+}
+
+function getCurrentComponentErrorInfo(parentType) {
+  if (__DEV__) {
+    let info = getDeclarationErrorAddendum();
+
+    if (!info) {
+      const parentName = getComponentNameFromType(parentType);
+      if (parentName) {
+        info = `\n\nCheck the top-level render call using <${parentName}>.`;
+      }
+    }
+    return info;
+  }
+}
+
+/**
+ * Given a fragment, validate that it can only be provided with fragment props
+ * @param {ReactElement} fragment
+ */
+function validateFragmentProps(fragment) {
+  if (__DEV__) {
+    const keys = Object.keys(fragment.props);
+    for (let i = 0; i < keys.length; i++) {
+      const key = keys[i];
+      if (key !== 'children' && key !== 'key') {
+        setCurrentlyValidatingElement(fragment);
+        console.error(
+          'Invalid prop `%s` supplied to `React.Fragment`. ' +
+            'React.Fragment can only have `key` and `children` props.',
+          key,
+        );
+        setCurrentlyValidatingElement(null);
+        break;
+      }
+    }
+
+    if (fragment.ref !== null) {
+      setCurrentlyValidatingElement(fragment);
+      console.error('Invalid attribute `ref` supplied to `React.Fragment`.');
+      setCurrentlyValidatingElement(null);
+    }
+  }
+}
+
+let propTypesMisspellWarningShown = false;
+
+/**
+ * Given an element, validate that its props follow the propTypes definition,
+ * provided by the type.
+ *
+ * @param {ReactElement} element
+ */
+function validatePropTypes(element) {
+  if (__DEV__) {
+    const type = element.type;
+    if (type === null || type === undefined || typeof type === 'string') {
+      return;
+    }
+    if (type.$$typeof === REACT_CLIENT_REFERENCE) {
+      return;
+    }
+    let propTypes;
+    if (typeof type === 'function') {
+      propTypes = type.propTypes;
+    } else if (
+      typeof type === 'object' &&
+      (type.$$typeof === REACT_FORWARD_REF_TYPE ||
+        // Note: Memo only checks outer props here.
+        // Inner props are checked in the reconciler.
+        type.$$typeof === REACT_MEMO_TYPE)
+    ) {
+      propTypes = type.propTypes;
+    } else {
+      return;
+    }
+    if (propTypes) {
+      // Intentionally inside to avoid triggering lazy initializers:
+      const name = getComponentNameFromType(type);
+      checkPropTypes(propTypes, element.props, 'prop', name, element);
+    } else if (type.PropTypes !== undefined && !propTypesMisspellWarningShown) {
+      propTypesMisspellWarningShown = true;
+      // Intentionally inside to avoid triggering lazy initializers:
+      const name = getComponentNameFromType(type);
+      console.error(
+        'Component %s declared `PropTypes` instead of `propTypes`. Did you misspell the property assignment?',
+        name || 'Unknown',
+      );
+    }
+    if (
+      typeof type.getDefaultProps === 'function' &&
+      !type.getDefaultProps.isReactClassApproved
+    ) {
+      console.error(
+        'getDefaultProps is only used on classic React.createClass ' +
+          'definitions. Use a static property named `defaultProps` instead.',
+      );
+    }
   }
 }

filename: packages/react/src/jsx/ReactJSXElementValidator.js
patch: @@ -1,445 +0,0 @@
-/**
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-/**
- * ReactElementValidator provides a wrapper around a element factory
- * which validates the props passed to the element. This is intended to be
- * used only in DEV and could be replaced by a static type checker for languages
- * that support it.
- */
-import isValidElementType from 'shared/isValidElementType';
-import getComponentNameFromType from 'shared/getComponentNameFromType';
-import checkPropTypes from 'shared/checkPropTypes';
-import {
-  getIteratorFn,
-  REACT_FORWARD_REF_TYPE,
-  REACT_MEMO_TYPE,
-  REACT_FRAGMENT_TYPE,
-  REACT_ELEMENT_TYPE,
-} from 'shared/ReactSymbols';
-import hasOwnProperty from 'shared/hasOwnProperty';
-import isArray from 'shared/isArray';
-import {jsxDEV} from './ReactJSXElement';
-
-import {describeUnknownElementTypeFrameInDEV} from 'shared/ReactComponentStackFrame';
-
-import ReactSharedInternals from 'shared/ReactSharedInternals';
-
-const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
-const ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame;
-
-const REACT_CLIENT_REFERENCE = Symbol.for('react.client.reference');
-
-function setCurrentlyValidatingElement(element) {
-  if (__DEV__) {
-    if (element) {
-      const owner = element._owner;
-      const stack = describeUnknownElementTypeFrameInDEV(
-        element.type,
-        owner ? owner.type : null,
-      );
-      ReactDebugCurrentFrame.setExtraStackFrame(stack);
-    } else {
-      ReactDebugCurrentFrame.setExtraStackFrame(null);
-    }
-  }
-}
-
-let propTypesMisspellWarningShown;
-
-if (__DEV__) {
-  propTypesMisspellWarningShown = false;
-}
-
-/**
- * Verifies the object is a ReactElement.
- * See https://reactjs.org/docs/react-api.html#isvalidelement
- * @param {?object} object
- * @return {boolean} True if `object` is a ReactElement.
- * @final
- */
-export function isValidElement(object) {
-  if (__DEV__) {
-    return (
-      typeof object === 'object' &&
-      object !== null &&
-      object.$$typeof === REACT_ELEMENT_TYPE
-    );
-  }
-}
-
-function getDeclarationErrorAddendum() {
-  if (__DEV__) {
-    if (ReactCurrentOwner.current) {
-      const name = getComponentNameFromType(ReactCurrentOwner.current.type);
-      if (name) {
-        return '\n\nCheck the render method of `' + name + '`.';
-      }
-    }
-    return '';
-  }
-}
-
-function getSourceInfoErrorAddendum(source) {
-  if (__DEV__) {
-    if (source !== undefined) {
-      const fileName = source.fileName.replace(/^.*[\\\/]/, '');
-      const lineNumber = source.lineNumber;
-      return '\n\nCheck your code at ' + fileName + ':' + lineNumber + '.';
-    }
-    return '';
-  }
-}
-
-/**
- * Warn if there's no key explicitly set on dynamic arrays of children or
- * object keys are not valid. This allows us to keep track of children between
- * updates.
- */
-const ownerHasKeyUseWarning = {};
-
-function getCurrentComponentErrorInfo(parentType) {
-  if (__DEV__) {
-    let info = getDeclarationErrorAddendum();
-
-    if (!info) {
-      const parentName = getComponentNameFromType(parentType);
-      if (parentName) {
-        info = `\n\nCheck the top-level render call using <${parentName}>.`;
-      }
-    }
-    return info;
-  }
-}
-
-/**
- * Warn if the element doesn't have an explicit key assigned to it.
- * This element is in an array. The array could grow and shrink or be
- * reordered. All children that haven't already been validated are required to
- * have a "key" property assigned to it. Error statuses are cached so a warning
- * will only be shown once.
- *
- * @internal
- * @param {ReactElement} element Element that requires a key.
- * @param {*} parentType element's parent's type.
- */
-function validateExplicitKey(element, parentType) {
-  if (__DEV__) {
-    if (!element._store || element._store.validated || element.key != null) {
-      return;
-    }
-    element._store.validated = true;
-
-    const currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType);
-    if (ownerHasKeyUseWarning[currentComponentErrorInfo]) {
-      return;
-    }
-    ownerHasKeyUseWarning[currentComponentErrorInfo] = true;
-
-    // Usually the current owner is the offender, but if it accepts children as a
-    // property, it may be the creator of the child that's responsible for
-    // assigning it a key.
-    let childOwner = '';
-    if (
-      element &&
-      element._owner &&
-      element._owner !== ReactCurrentOwner.current
-    ) {
-      // Give the component that originally created this child.
-      childOwner = ` It was passed a child from ${getComponentNameFromType(
-        element._owner.type,
-      )}.`;
-    }
-
-    setCurrentlyValidatingElement(element);
-    console.error(
-      'Each child in a list should have a unique "key" prop.' +
-        '%s%s See https://reactjs.org/link/warning-keys for more information.',
-      currentComponentErrorInfo,
-      childOwner,
-    );
-    setCurrentlyValidatingElement(null);
-  }
-}
-
-/**
- * Ensure that every element either is passed in a static location, in an
- * array with an explicit keys property defined, or in an object literal
- * with valid key property.
- *
- * @internal
- * @param {ReactNode} node Statically passed child of any type.
- * @param {*} parentType node's parent's type.
- */
-function validateChildKeys(node, parentType) {
-  if (__DEV__) {
-    if (typeof node !== 'object' || !node) {
-      return;
-    }
-    if (node.$$typeof === REACT_CLIENT_REFERENCE) {
-      // This is a reference to a client component so it's unknown.
-    } else if (isArray(node)) {
-      for (let i = 0; i < node.length; i++) {
-        const child = node[i];
-        if (isValidElement(child)) {
-          validateExplicitKey(child, parentType);
-        }
-      }
-    } else if (isValidElement(node)) {
-      // This element was passed in a valid location.
-      if (node._store) {
-        node._store.validated = true;
-      }
-    } else {
-      const iteratorFn = getIteratorFn(node);
-      if (typeof iteratorFn === 'function') {
-        // Entry iterators used to provide implicit keys,
-        // but now we print a separate warning for them later.
-        if (iteratorFn !== node.entries) {
-          const iterator = iteratorFn.call(node);
-          let step;
-          while (!(step = iterator.next()).done) {
-            if (isValidElement(step.value)) {
-              validateExplicitKey(step.value, parentType);
-            }
-          }
-        }
-      }
-    }
-  }
-}
-
-/**
- * Given an element, validate that its props follow the propTypes definition,
- * provided by the type.
- *
- * @param {ReactElement} element
- */
-function validatePropTypes(element) {
-  if (__DEV__) {
-    const type = element.type;
-    if (type === null || type === undefined || typeof type === 'string') {
-      return;
-    }
-    if (type.$$typeof === REACT_CLIENT_REFERENCE) {
-      return;
-    }
-    let propTypes;
-    if (typeof type === 'function') {
-      propTypes = type.propTypes;
-    } else if (
-      typeof type === 'object' &&
-      (type.$$typeof === REACT_FORWARD_REF_TYPE ||
-        // Note: Memo only checks outer props here.
-        // Inner props are checked in the reconciler.
-        type.$$typeof === REACT_MEMO_TYPE)
-    ) {
-      propTypes = type.propTypes;
-    } else {
-      return;
-    }
-    if (propTypes) {
-      // Intentionally inside to avoid triggering lazy initializers:
-      const name = getComponentNameFromType(type);
-      checkPropTypes(propTypes, element.props, 'prop', name, element);
-    } else if (type.PropTypes !== undefined && !propTypesMisspellWarningShown) {
-      propTypesMisspellWarningShown = true;
-      // Intentionally inside to avoid triggering lazy initializers:
-      const name = getComponentNameFromType(type);
-      console.error(
-        'Component %s declared `PropTypes` instead of `propTypes`. Did you misspell the property assignment?',
-        name || 'Unknown',
-      );
-    }
-    if (
-      typeof type.getDefaultProps === 'function' &&
-      !type.getDefaultProps.isReactClassApproved
-    ) {
-      console.error(
-        'getDefaultProps is only used on classic React.createClass ' +
-          'definitions. Use a static property named `defaultProps` instead.',
-      );
-    }
-  }
-}
-
-/**
- * Given a fragment, validate that it can only be provided with fragment props
- * @param {ReactElement} fragment
- */
-function validateFragmentProps(fragment) {
-  if (__DEV__) {
-    const keys = Object.keys(fragment.props);
-    for (let i = 0; i < keys.length; i++) {
-      const key = keys[i];
-      if (key !== 'children' && key !== 'key') {
-        setCurrentlyValidatingElement(fragment);
-        console.error(
-          'Invalid prop `%s` supplied to `React.Fragment`. ' +
-            'React.Fragment can only have `key` and `children` props.',
-          key,
-        );
-        setCurrentlyValidatingElement(null);
-        break;
-      }
-    }
-
-    if (fragment.ref !== null) {
-      setCurrentlyValidatingElement(fragment);
-      console.error('Invalid attribute `ref` supplied to `React.Fragment`.');
-      setCurrentlyValidatingElement(null);
-    }
-  }
-}
-
-const didWarnAboutKeySpread = {};
-
-export function jsxWithValidation(
-  type,
-  props,
-  key,
-  isStaticChildren,
-  source,
-  self,
-) {
-  if (__DEV__) {
-    const validType = isValidElementType(type);
-
-    // We warn in this case but don't throw. We expect the element creation to
-    // succeed and there will likely be errors in render.
-    if (!validType) {
-      let info = '';
-      if (
-        type === undefined ||
-        (typeof type === 'object' &&
-          type !== null &&
-          Object.keys(type).length === 0)
-      ) {
-        info +=
-          ' You likely forgot to export your component from the file ' +
-          "it's defined in, or you might have mixed up default and named imports.";
-      }
-
-      const sourceInfo = getSourceInfoErrorAddendum(source);
-      if (sourceInfo) {
-        info += sourceInfo;
-      } else {
-        info += getDeclarationErrorAddendum();
-      }
-
-      let typeString;
-      if (type === null) {
-        typeString = 'null';
-      } else if (isArray(type)) {
-        typeString = 'array';
-      } else if (type !== undefined && type.$$typeof === REACT_ELEMENT_TYPE) {
-        typeString = `<${getComponentNameFromType(type.type) || 'Unknown'} />`;
-        info =
-          ' Did you accidentally export a JSX literal instead of a component?';
-      } else {
-        typeString = typeof type;
-      }
-
-      console.error(
-        'React.jsx: type is invalid -- expected a string (for ' +
-          'built-in components) or a class/function (for composite ' +
-          'components) but got: %s.%s',
-        typeString,
-        info,
-      );
-    }
-
-    const element = jsxDEV(type, props, key, source, self);
-
-    // The result can be nullish if a mock or a custom function is used.
-    // TODO: Drop this when these are no longer allowed as the type argument.
-    if (element == null) {
-      return element;
-    }
-
-    // Skip key warning if the type isn't valid since our key validation logic
-    // doesn't expect a non-string/function type and can throw confusing errors.
-    // We don't want exception behavior to differ between dev and prod.
-    // (Rendering will throw with a helpful message and as soon as the type is
-    // fixed, the key warnings will appear.)
-
-    if (validType) {
-      const children = props.children;
-      if (children !== undefined) {
-        if (isStaticChildren) {
-          if (isArray(children)) {
-            for (let i = 0; i < children.length; i++) {
-              validateChildKeys(children[i], type);
-            }
-
-            if (Object.freeze) {
-              Object.freeze(children);
-            }
-          } else {
-            console.error(
-              'React.jsx: Static children should always be an array. ' +
-                'You are likely explicitly calling React.jsxs or React.jsxDEV. ' +
-                'Use the Babel transform instead.',
-            );
-          }
-        } else {
-          validateChildKeys(children, type);
-        }
-      }
-    }
-
-    if (hasOwnProperty.call(props, 'key')) {
-      const componentName = getComponentNameFromType(type);
-      const keys = Object.keys(props).filter(k => k !== 'key');
-      const beforeExample =
-        keys.length > 0
-          ? '{key: someKey, ' + keys.join(': ..., ') + ': ...}'
-          : '{key: someKey}';
-      if (!didWarnAboutKeySpread[componentName + beforeExample]) {
-        const afterExample =
-          keys.length > 0 ? '{' + keys.join(': ..., ') + ': ...}' : '{}';
-        console.error(
-          'A props object containing a "key" prop is being spread into JSX:\n' +
-            '  let props = %s;\n' +
-            '  <%s {...props} />\n' +
-            'React keys must be passed directly to JSX without using spread:\n' +
-            '  let props = %s;\n' +
-            '  <%s key={someKey} {...props} />',
-          beforeExample,
-          componentName,
-          afterExample,
-          componentName,
-        );
-        didWarnAboutKeySpread[componentName + beforeExample] = true;
-      }
-    }
-
-    if (type === REACT_FRAGMENT_TYPE) {
-      validateFragmentProps(element);
-    } else {
-      validatePropTypes(element);
-    }
-
-    return element;
-  }
-}
-
-// These two functions exist to still get child warnings in dev
-// even with the prod transform. This means that jsxDEV is purely
-// opt-in behavior for better messages but that we won't stop
-// giving you warnings if you use production apis.
-export function jsxWithValidationStatic(type, props, key) {
-  if (__DEV__) {
-    return jsxWithValidation(type, props, key, true);
-  }
-}
-
-export function jsxWithValidationDynamic(type, props, key) {
-  if (__DEV__) {
-    return jsxWithValidation(type, props, key, false);
-  }
-}

filename: packages/react/src/jsx/ReactJSXServer.js
patch: @@ -6,17 +6,23 @@
  *
  * @flow
  */
-
-// These are implementations of the jsx APIs for React Server runtimes.
 import {REACT_FRAGMENT_TYPE} from 'shared/ReactSymbols';
 import {
-  jsxWithValidationStatic,
-  jsxWithValidationDynamic,
-} from './ReactJSXElementValidator';
-import {jsx as jsxProd} from './ReactJSXElement';
-const jsx: any = __DEV__ ? jsxWithValidationDynamic : jsxProd;
+  jsxProd,
+  jsxProdSignatureRunningInDevWithDynamicChildren,
+  jsxProdSignatureRunningInDevWithStaticChildren,
+  jsxDEV as _jsxDEV,
+} from './ReactJSXElement';
+
+const jsx: any = __DEV__
+  ? jsxProdSignatureRunningInDevWithDynamicChildren
+  : jsxProd;
 // we may want to special case jsxs internally to take advantage of static children.
 // for now we can ship identical prod functions
-const jsxs: any = __DEV__ ? jsxWithValidationStatic : jsxProd;
+const jsxs: any = __DEV__
+  ? jsxProdSignatureRunningInDevWithStaticChildren
+  : jsxProd;
+
+const jsxDEV: any = __DEV__ ? _jsxDEV : undefined;
 
-export {REACT_FRAGMENT_TYPE as Fragment, jsx, jsxs};
+export {REACT_FRAGMENT_TYPE as Fragment, jsx, jsxs, jsxDEV};