@@ -27,7 +27,12 @@ import warning from 'shared/warning';
27
27
import warningWithoutStack from 'shared/warningWithoutStack' ;
28
28
29
29
import ReactCurrentOwner from './ReactCurrentOwner' ;
30
- import { isValidElement , createElement , cloneElement } from './ReactElement' ;
30
+ import {
31
+ isValidElement ,
32
+ createElement ,
33
+ cloneElement ,
34
+ jsxDEV ,
35
+ } from './ReactElement' ;
31
36
import ReactDebugCurrentFrame , {
32
37
setCurrentlyValidatingElement ,
33
38
} from './ReactDebugCurrentFrame' ;
@@ -48,20 +53,22 @@ function getDeclarationErrorAddendum() {
48
53
return '' ;
49
54
}
50
55
51
- function getSourceInfoErrorAddendum ( elementProps ) {
52
- if (
53
- elementProps !== null &&
54
- elementProps !== undefined &&
55
- elementProps . __source !== undefined
56
- ) {
57
- const source = elementProps . __source ;
56
+ function getSourceInfoErrorAddendum ( source ) {
57
+ if ( source !== undefined ) {
58
58
const fileName = source . fileName . replace ( / ^ .* [ \\ \/ ] / , '' ) ;
59
59
const lineNumber = source . lineNumber ;
60
60
return '\n\nCheck your code at ' + fileName + ':' + lineNumber + '.' ;
61
61
}
62
62
return '' ;
63
63
}
64
64
65
+ function getSourceInfoErrorAddendumForProps ( elementProps ) {
66
+ if ( elementProps !== null && elementProps !== undefined ) {
67
+ return getSourceInfoErrorAddendum ( elementProps . __source ) ;
68
+ }
69
+ return '' ;
70
+ }
71
+
65
72
/**
66
73
* Warn if there's no key explicitly set on dynamic arrays of children or
67
74
* object keys are not valid. This allows us to keep track of children between
@@ -259,6 +266,117 @@ function validateFragmentProps(fragment) {
259
266
setCurrentlyValidatingElement ( null ) ;
260
267
}
261
268
269
+ export function jsxWithValidation (
270
+ type ,
271
+ props ,
272
+ key ,
273
+ isStaticChildren ,
274
+ source ,
275
+ self ,
276
+ ) {
277
+ const validType = isValidElementType ( type ) ;
278
+
279
+ // We warn in this case but don't throw. We expect the element creation to
280
+ // succeed and there will likely be errors in render.
281
+ if ( ! validType ) {
282
+ let info = '' ;
283
+ if (
284
+ type === undefined ||
285
+ ( typeof type === 'object' &&
286
+ type !== null &&
287
+ Object . keys ( type ) . length === 0 )
288
+ ) {
289
+ info +=
290
+ ' You likely forgot to export your component from the file ' +
291
+ "it's defined in, or you might have mixed up default and named imports." ;
292
+ }
293
+
294
+ const sourceInfo = getSourceInfoErrorAddendum ( source ) ;
295
+ if ( sourceInfo ) {
296
+ info += sourceInfo ;
297
+ } else {
298
+ info += getDeclarationErrorAddendum ( ) ;
299
+ }
300
+
301
+ let typeString ;
302
+ if ( type === null ) {
303
+ typeString = 'null' ;
304
+ } else if ( Array . isArray ( type ) ) {
305
+ typeString = 'array' ;
306
+ } else if ( type !== undefined && type . $$typeof === REACT_ELEMENT_TYPE ) {
307
+ typeString = `<${ getComponentName ( type . type ) || 'Unknown' } />` ;
308
+ info =
309
+ ' Did you accidentally export a JSX literal instead of a component?' ;
310
+ } else {
311
+ typeString = typeof type ;
312
+ }
313
+
314
+ warning (
315
+ false ,
316
+ 'React.jsx: type is invalid -- expected a string (for ' +
317
+ 'built-in components) or a class/function (for composite ' +
318
+ 'components) but got: %s.%s' ,
319
+ typeString ,
320
+ info ,
321
+ ) ;
322
+ }
323
+
324
+ const element = jsxDEV ( type , props , key , source , self ) ;
325
+
326
+ // The result can be nullish if a mock or a custom function is used.
327
+ // TODO: Drop this when these are no longer allowed as the type argument.
328
+ if ( element == null ) {
329
+ return element ;
330
+ }
331
+
332
+ // Skip key warning if the type isn't valid since our key validation logic
333
+ // doesn't expect a non-string/function type and can throw confusing errors.
334
+ // We don't want exception behavior to differ between dev and prod.
335
+ // (Rendering will throw with a helpful message and as soon as the type is
336
+ // fixed, the key warnings will appear.)
337
+ if ( validType ) {
338
+ const children = props . children ;
339
+ if ( children !== undefined ) {
340
+ if ( isStaticChildren ) {
341
+ for ( let i = 0 ; i < children . length ; i ++ ) {
342
+ validateChildKeys ( children [ i ] , type ) ;
343
+ }
344
+ } else {
345
+ validateChildKeys ( children , type ) ;
346
+ }
347
+ }
348
+ }
349
+
350
+ if ( props . key !== undefined ) {
351
+ warning (
352
+ false ,
353
+ 'React.jsx: Spreading a key to JSX is a deprecated pattern. ' +
354
+ 'Explicitly pass a key after spreading props in your JSX call. ' +
355
+ 'E.g. <ComponentName {...props} key={key} />' ,
356
+ ) ;
357
+ }
358
+
359
+ if ( type === REACT_FRAGMENT_TYPE ) {
360
+ validateFragmentProps ( element ) ;
361
+ } else {
362
+ validatePropTypes ( element ) ;
363
+ }
364
+
365
+ return element ;
366
+ }
367
+
368
+ // These two functions exist to still get child warnings in dev
369
+ // even with the prod transform. This means that jsxDEV is purely
370
+ // opt-in behavior for better messages but that we won't stop
371
+ // giving you warnings if you use production apis.
372
+ export function jsxWithValidationStatic ( type , props , key ) {
373
+ return jsxWithValidation ( type , props , key , true ) ;
374
+ }
375
+
376
+ export function jsxWithValidationDynamic ( type , props , key ) {
377
+ return jsxWithValidation ( type , props , key , false ) ;
378
+ }
379
+
262
380
export function createElementWithValidation ( type , props , children ) {
263
381
const validType = isValidElementType ( type ) ;
264
382
@@ -277,7 +395,7 @@ export function createElementWithValidation(type, props, children) {
277
395
"it's defined in, or you might have mixed up default and named imports." ;
278
396
}
279
397
280
- const sourceInfo = getSourceInfoErrorAddendum ( props ) ;
398
+ const sourceInfo = getSourceInfoErrorAddendumForProps ( props ) ;
281
399
if ( sourceInfo ) {
282
400
info += sourceInfo ;
283
401
} else {
0 commit comments