1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 | 'use strict';
|
17 |
|
18 | var ReactCurrentOwner = require('./ReactCurrentOwner');
|
19 | var ReactComponentTreeHook = require('./ReactComponentTreeHook');
|
20 | var ReactElement = require('./ReactElement');
|
21 |
|
22 | var checkReactTypeSpec = require('./checkReactTypeSpec');
|
23 |
|
24 | var canDefineProperty = require('./canDefineProperty');
|
25 | var getIteratorFn = require('./getIteratorFn');
|
26 | var warning = require('fbjs/lib/warning');
|
27 | var lowPriorityWarning = require('./lowPriorityWarning');
|
28 |
|
29 | function getDeclarationErrorAddendum() {
|
30 | if (ReactCurrentOwner.current) {
|
31 | var name = ReactCurrentOwner.current.getName();
|
32 | if (name) {
|
33 | return ' Check the render method of `' + name + '`.';
|
34 | }
|
35 | }
|
36 | return '';
|
37 | }
|
38 |
|
39 | function getSourceInfoErrorAddendum(elementProps) {
|
40 | if (elementProps !== null && elementProps !== undefined && elementProps.__source !== undefined) {
|
41 | var source = elementProps.__source;
|
42 | var fileName = source.fileName.replace(/^.*[\\\/]/, '');
|
43 | var lineNumber = source.lineNumber;
|
44 | return ' Check your code at ' + fileName + ':' + lineNumber + '.';
|
45 | }
|
46 | return '';
|
47 | }
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 | var ownerHasKeyUseWarning = {};
|
55 |
|
56 | function getCurrentComponentErrorInfo(parentType) {
|
57 | var info = getDeclarationErrorAddendum();
|
58 |
|
59 | if (!info) {
|
60 | var parentName = typeof parentType === 'string' ? parentType : parentType.displayName || parentType.name;
|
61 | if (parentName) {
|
62 | info = ' Check the top-level render call using <' + parentName + '>.';
|
63 | }
|
64 | }
|
65 | return info;
|
66 | }
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 | function validateExplicitKey(element, parentType) {
|
80 | if (!element._store || element._store.validated || element.key != null) {
|
81 | return;
|
82 | }
|
83 | element._store.validated = true;
|
84 |
|
85 | var memoizer = ownerHasKeyUseWarning.uniqueKey || (ownerHasKeyUseWarning.uniqueKey = {});
|
86 |
|
87 | var currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType);
|
88 | if (memoizer[currentComponentErrorInfo]) {
|
89 | return;
|
90 | }
|
91 | memoizer[currentComponentErrorInfo] = true;
|
92 |
|
93 |
|
94 |
|
95 |
|
96 | var childOwner = '';
|
97 | if (element && element._owner && element._owner !== ReactCurrentOwner.current) {
|
98 |
|
99 | childOwner = ' It was passed a child from ' + element._owner.getName() + '.';
|
100 | }
|
101 |
|
102 | process.env.NODE_ENV !== 'production' ? warning(false, 'Each child in an array or iterator should have a unique "key" prop.' + '%s%s See https://fb.me/react-warning-keys for more information.%s', currentComponentErrorInfo, childOwner, ReactComponentTreeHook.getCurrentStackAddendum(element)) : void 0;
|
103 | }
|
104 |
|
105 |
|
106 |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 | function validateChildKeys(node, parentType) {
|
115 | if (typeof node !== 'object') {
|
116 | return;
|
117 | }
|
118 | if (Array.isArray(node)) {
|
119 | for (var i = 0; i < node.length; i++) {
|
120 | var child = node[i];
|
121 | if (ReactElement.isValidElement(child)) {
|
122 | validateExplicitKey(child, parentType);
|
123 | }
|
124 | }
|
125 | } else if (ReactElement.isValidElement(node)) {
|
126 |
|
127 | if (node._store) {
|
128 | node._store.validated = true;
|
129 | }
|
130 | } else if (node) {
|
131 | var iteratorFn = getIteratorFn(node);
|
132 |
|
133 | if (iteratorFn) {
|
134 | if (iteratorFn !== node.entries) {
|
135 | var iterator = iteratorFn.call(node);
|
136 | var step;
|
137 | while (!(step = iterator.next()).done) {
|
138 | if (ReactElement.isValidElement(step.value)) {
|
139 | validateExplicitKey(step.value, parentType);
|
140 | }
|
141 | }
|
142 | }
|
143 | }
|
144 | }
|
145 | }
|
146 |
|
147 |
|
148 |
|
149 |
|
150 |
|
151 |
|
152 |
|
153 | function validatePropTypes(element) {
|
154 | var componentClass = element.type;
|
155 | if (typeof componentClass !== 'function') {
|
156 | return;
|
157 | }
|
158 | var name = componentClass.displayName || componentClass.name;
|
159 | if (componentClass.propTypes) {
|
160 | checkReactTypeSpec(componentClass.propTypes, element.props, 'prop', name, element, null);
|
161 | }
|
162 | if (typeof componentClass.getDefaultProps === 'function') {
|
163 | process.env.NODE_ENV !== 'production' ? warning(componentClass.getDefaultProps.isReactClassApproved, 'getDefaultProps is only used on classic React.createClass ' + 'definitions. Use a static property named `defaultProps` instead.') : void 0;
|
164 | }
|
165 | }
|
166 |
|
167 | var ReactElementValidator = {
|
168 | createElement: function (type, props, children) {
|
169 | var validType = typeof type === 'string' || typeof type === 'function';
|
170 |
|
171 |
|
172 | if (!validType) {
|
173 | if (typeof type !== 'function' && typeof type !== 'string') {
|
174 | var info = '';
|
175 | if (type === undefined || typeof type === 'object' && type !== null && Object.keys(type).length === 0) {
|
176 | info += ' You likely forgot to export your component from the file ' + "it's defined in.";
|
177 | }
|
178 |
|
179 | var sourceInfo = getSourceInfoErrorAddendum(props);
|
180 | if (sourceInfo) {
|
181 | info += sourceInfo;
|
182 | } else {
|
183 | info += getDeclarationErrorAddendum();
|
184 | }
|
185 |
|
186 | info += ReactComponentTreeHook.getCurrentStackAddendum();
|
187 |
|
188 | var currentSource = props !== null && props !== undefined && props.__source !== undefined ? props.__source : null;
|
189 | ReactComponentTreeHook.pushNonStandardWarningStack(true, currentSource);
|
190 | process.env.NODE_ENV !== 'production' ? warning(false, 'React.createElement: type is invalid -- expected a string (for ' + 'built-in components) or a class/function (for composite ' + 'components) but got: %s.%s', type == null ? type : typeof type, info) : void 0;
|
191 | ReactComponentTreeHook.popNonStandardWarningStack();
|
192 | }
|
193 | }
|
194 |
|
195 | var element = ReactElement.createElement.apply(this, arguments);
|
196 |
|
197 |
|
198 |
|
199 | if (element == null) {
|
200 | return element;
|
201 | }
|
202 |
|
203 |
|
204 |
|
205 |
|
206 |
|
207 |
|
208 | if (validType) {
|
209 | for (var i = 2; i < arguments.length; i++) {
|
210 | validateChildKeys(arguments[i], type);
|
211 | }
|
212 | }
|
213 |
|
214 | validatePropTypes(element);
|
215 |
|
216 | return element;
|
217 | },
|
218 |
|
219 | createFactory: function (type) {
|
220 | var validatedFactory = ReactElementValidator.createElement.bind(null, type);
|
221 |
|
222 | validatedFactory.type = type;
|
223 |
|
224 | if (process.env.NODE_ENV !== 'production') {
|
225 | if (canDefineProperty) {
|
226 | Object.defineProperty(validatedFactory, 'type', {
|
227 | enumerable: false,
|
228 | get: function () {
|
229 | lowPriorityWarning(false, 'Factory.type is deprecated. Access the class directly ' + 'before passing it to createFactory.');
|
230 | Object.defineProperty(this, 'type', {
|
231 | value: type
|
232 | });
|
233 | return type;
|
234 | }
|
235 | });
|
236 | }
|
237 | }
|
238 |
|
239 | return validatedFactory;
|
240 | },
|
241 |
|
242 | cloneElement: function (element, props, children) {
|
243 | var newElement = ReactElement.cloneElement.apply(this, arguments);
|
244 | for (var i = 2; i < arguments.length; i++) {
|
245 | validateChildKeys(arguments[i], newElement.type);
|
246 | }
|
247 | validatePropTypes(newElement);
|
248 | return newElement;
|
249 | }
|
250 | };
|
251 |
|
252 | module.exports = ReactElementValidator; |
\ | No newline at end of file |