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
+ * @flow
8
+ */
9
+
10
+import type {Source} from 'shared/ReactElementType';
11
+import type {LazyComponent} from 'react/src/ReactLazy';
12
+
13
+import {
14
+ REACT_SUSPENSE_TYPE,
15
+ REACT_SUSPENSE_LIST_TYPE,
16
+ REACT_FORWARD_REF_TYPE,
17
+ REACT_MEMO_TYPE,
18
+ REACT_BLOCK_TYPE,
19
+ REACT_LAZY_TYPE,
20
+} from 'shared/ReactSymbols';
21
+
22
+const BEFORE_SLASH_RE = /^(.*)[\\\/]/;
23
+
24
+function describeComponentFrame(
25
+ name: null | string,
26
+ source: void | null | Source,
27
+ ownerName: null | string,
28
+) {
29
+ let sourceInfo = '';
30
+ if (__DEV__ && source) {
31
+ const path = source.fileName;
32
+ let fileName = path.replace(BEFORE_SLASH_RE, '');
33
+ // In DEV, include code for a common special case:
34
+ // prefer "folder/index.js" instead of just "index.js".
35
+ if (/^index\./.test(fileName)) {
36
+ const match = path.match(BEFORE_SLASH_RE);
37
+ if (match) {
38
+ const pathBeforeSlash = match[1];
39
+ if (pathBeforeSlash) {
40
+ const folderName = pathBeforeSlash.replace(BEFORE_SLASH_RE, '');
41
+ fileName = folderName + '/' + fileName;
42
+ }
43
+ }
44
+ }
45
+ sourceInfo = ' (at ' + fileName + ':' + source.lineNumber + ')';
46
+ } else if (ownerName) {
47
+ sourceInfo = ' (created by ' + ownerName + ')';
48
+ }
49
+ return '\n in ' + (name || 'Unknown') + sourceInfo;
50
+}
51
+
52
+export function describeBuiltInComponentFrame(
53
+ name: string,
54
+ source: void | null | Source,
55
+ ownerFn: void | null | Function,
56
+): string {
57
+ let ownerName = null;
58
+ if (__DEV__ && ownerFn) {
59
+ ownerName = ownerFn.displayName || ownerFn.name || null;
60
+ }
61
+ return describeComponentFrame(name, source, ownerName);
62
+}
63
+
64
+export function describeClassComponentFrame(
65
+ ctor: Function,
66
+ source: void | null | Source,
67
+ ownerFn: void | null | Function,
68
+): string {
69
+ return describeFunctionComponentFrame(ctor, source, ownerFn);
70
+}
71
+
72
+export function describeFunctionComponentFrame(
73
+ fn: Function,
74
+ source: void | null | Source,
75
+ ownerFn: void | null | Function,
76
+): string {
77
+ if (!fn) {
78
+ return '';
79
+ }
80
+ const name = fn.displayName || fn.name || null;
81
+ let ownerName = null;
82
+ if (__DEV__ && ownerFn) {
83
+ ownerName = ownerFn.displayName || ownerFn.name || null;
84
+ }
85
+ return describeComponentFrame(name, source, ownerName);
86
+}
87
+
88
+function shouldConstruct(Component: Function) {
89
+ const prototype = Component.prototype;
90
+ return !!(prototype && prototype.isReactComponent);
91
+}
92
+
93
+export function describeUnknownElementTypeFrameInDEV(
94
+ type: any,
95
+ source: void | null | Source,
96
+ ownerFn: void | null | Function,
97
+): string {
98
+ if (!__DEV__) {
99
+ return '';
100
+ }
101
+ if (type == null) {
102
+ return '';
103
+ }
104
+ if (typeof type === 'function') {
105
+ if (shouldConstruct(type)) {
106
+ return describeClassComponentFrame(type, source, ownerFn);
107
+ }
108
+ return describeFunctionComponentFrame(type, source, ownerFn);
109
+ }
110
+ if (typeof type === 'string') {
111
+ return describeBuiltInComponentFrame(type, source, ownerFn);
112
+ }
113
+ switch (type) {
114
+ case REACT_SUSPENSE_TYPE:
115
+ return describeBuiltInComponentFrame('Suspense', source, ownerFn);
116
+ case REACT_SUSPENSE_LIST_TYPE:
117
+ return describeBuiltInComponentFrame('SuspenseList', source, ownerFn);
118
+ }
119
+ if (typeof type === 'object') {
120
+ switch (type.$$typeof) {
121
+ case REACT_FORWARD_REF_TYPE:
122
+ return describeFunctionComponentFrame(type.render, source, ownerFn);
123
+ case REACT_MEMO_TYPE:
124
+ return describeFunctionComponentFrame(type.type, source, ownerFn);
125
+ case REACT_BLOCK_TYPE:
126
+ return describeFunctionComponentFrame(type._render, source, ownerFn);
127
+ case REACT_LAZY_TYPE: {
128
+ const lazyComponent: LazyComponent<any, any> = (type: any);
129
+ const payload = lazyComponent._payload;
130
+ const init = lazyComponent._init;
131
+ try {
132
+ return describeUnknownElementTypeFrameInDEV(
133
+ init(payload),
134
+ source,
135
+ ownerFn,
136
+ );
137
+ } catch (x) {}
138
+ }
139
+ }
140
+ }
141
+ return '';
142
+}