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,
element._source,
owner ? owner.type : null,
);
ReactDebugCurrentFrame.setExtraStackFrame(stack);
} else {
ReactDebugCurrentFrame.setExtraStackFrame(null);
}
}
}
let propTypesMisspellWarningShown;
if (__DEV__) {
propTypesMisspellWarningShown = false;
}
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 '';
}
}
const ownerHasKeyUseWarning = {};
function getCurrentComponentErrorInfo(parentType) {
if (__DEV__) {
let info = getDeclarationErrorAddendum();
if (!info) {
const parentName =
typeof parentType === 'string'
? parentType
: parentType.displayName || parentType.name;
if (parentName) {
info = `\n\nCheck the top-level render call using <${parentName}>.`;
}
}
return info;
}
}
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;
let childOwner = '';
if (
element &&
element._owner &&
element._owner !== ReactCurrentOwner.current
) {
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 validateChildKeys(node, parentType) {
if (__DEV__) {
if (typeof node !== 'object' || !node) {
return;
}
if (node.$$typeof === REACT_CLIENT_REFERENCE) {
} 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)) {
if (node._store) {
node._store.validated = true;
}
} else {
const iteratorFn = getIteratorFn(node);
if (typeof iteratorFn === 'function') {
if (iteratorFn !== node.entries) {
const iterator = iteratorFn.call(node);
let step;
while (!(step = iterator.next()).done) {
if (isValidElement(step.value)) {
validateExplicitKey(step.value, parentType);
}
}
}
}
}
}
}
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 ||
type.$$typeof === REACT_MEMO_TYPE)
) {
propTypes = type.propTypes;
} else {
return;
}
if (propTypes) {
const name = getComponentNameFromType(type);
checkPropTypes(propTypes, element.props, 'prop', name, element);
} else if (type.PropTypes !== undefined && !propTypesMisspellWarningShown) {
propTypesMisspellWarningShown = true;
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.',
);
}
}
}
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);
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);
if (element == null) {
return element;
}
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;
}
}
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);
}
}