react 0.14.0-alpha1 → 0.14.0-alpha2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/JSXTransformer.js +1 -1
- package/dist/react-with-addons.js +1041 -861
- package/dist/react-with-addons.min.js +6 -6
- package/dist/react.js +985 -805
- package/dist/react.min.js +5 -5
- package/lib/DOMProperty.js +0 -2
- package/lib/Danger.js +0 -2
- package/lib/HTMLDOMPropertyConfig.js +1 -2
- package/lib/React.js +8 -110
- package/lib/ReactChildren.js +15 -13
- package/lib/ReactClass.js +3 -3
- package/lib/ReactComponentBrowserEnvironment.js +0 -2
- package/lib/ReactDOMClient.js +85 -0
- package/lib/ReactDOMComponent.js +7 -7
- package/lib/ReactDOMIDOperations.js +0 -2
- package/lib/ReactDOMOption.js +17 -1
- package/lib/ReactDOMServer.js +24 -0
- package/lib/ReactDOMTextComponent.js +2 -2
- package/lib/ReactDefaultInjection.js +10 -0
- package/lib/ReactElement.js +18 -14
- package/lib/ReactElementValidator.js +5 -13
- package/lib/ReactIsomorphic.js +70 -0
- package/lib/ReactMount.js +2 -1
- package/lib/ReactPropTypes.js +26 -25
- package/lib/SVGDOMPropertyConfig.js +0 -2
- package/lib/adler32.js +0 -2
- package/lib/containsNode.js +1 -1
- package/lib/traverseAllChildren.js +9 -13
- package/lib/validateDOMNesting.js +188 -97
- package/package.json +1 -1
|
@@ -81,13 +81,12 @@ function wrapUserProvidedKey(key) {
|
|
|
81
81
|
/**
|
|
82
82
|
* @param {?*} children Children tree container.
|
|
83
83
|
* @param {!string} nameSoFar Name of the key path so far.
|
|
84
|
-
* @param {!number} indexSoFar Number of children encountered until this point.
|
|
85
84
|
* @param {!function} callback Callback to invoke with each child found.
|
|
86
85
|
* @param {?*} traverseContext Used to pass information throughout the traversal
|
|
87
86
|
* process.
|
|
88
87
|
* @return {!number} The number of children in this subtree.
|
|
89
88
|
*/
|
|
90
|
-
function traverseAllChildrenImpl(children, nameSoFar,
|
|
89
|
+
function traverseAllChildrenImpl(children, nameSoFar, callback, traverseContext) {
|
|
91
90
|
var type = typeof children;
|
|
92
91
|
|
|
93
92
|
if (type === 'undefined' || type === 'boolean') {
|
|
@@ -99,19 +98,19 @@ function traverseAllChildrenImpl(children, nameSoFar, indexSoFar, callback, trav
|
|
|
99
98
|
callback(traverseContext, children,
|
|
100
99
|
// If it's the only child, treat the name as if it was wrapped in an array
|
|
101
100
|
// so that it's consistent if the number of children grows.
|
|
102
|
-
nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar
|
|
101
|
+
nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar);
|
|
103
102
|
return 1;
|
|
104
103
|
}
|
|
105
104
|
|
|
106
|
-
var child
|
|
105
|
+
var child;
|
|
106
|
+
var nextName;
|
|
107
107
|
var subtreeCount = 0; // Count of children found in the current subtree.
|
|
108
108
|
|
|
109
109
|
if (Array.isArray(children)) {
|
|
110
110
|
for (var i = 0; i < children.length; i++) {
|
|
111
111
|
child = children[i];
|
|
112
112
|
nextName = (nameSoFar !== '' ? nameSoFar + SUBSEPARATOR : SEPARATOR) + getComponentKey(child, i);
|
|
113
|
-
|
|
114
|
-
subtreeCount += traverseAllChildrenImpl(child, nextName, nextIndex, callback, traverseContext);
|
|
113
|
+
subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext);
|
|
115
114
|
}
|
|
116
115
|
} else {
|
|
117
116
|
var iteratorFn = getIteratorFn(children);
|
|
@@ -123,8 +122,7 @@ function traverseAllChildrenImpl(children, nameSoFar, indexSoFar, callback, trav
|
|
|
123
122
|
while (!(step = iterator.next()).done) {
|
|
124
123
|
child = step.value;
|
|
125
124
|
nextName = (nameSoFar !== '' ? nameSoFar + SUBSEPARATOR : SEPARATOR) + getComponentKey(child, ii++);
|
|
126
|
-
|
|
127
|
-
subtreeCount += traverseAllChildrenImpl(child, nextName, nextIndex, callback, traverseContext);
|
|
125
|
+
subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext);
|
|
128
126
|
}
|
|
129
127
|
} else {
|
|
130
128
|
if ('production' !== process.env.NODE_ENV) {
|
|
@@ -137,8 +135,7 @@ function traverseAllChildrenImpl(children, nameSoFar, indexSoFar, callback, trav
|
|
|
137
135
|
if (entry) {
|
|
138
136
|
child = entry[1];
|
|
139
137
|
nextName = (nameSoFar !== '' ? nameSoFar + SUBSEPARATOR : SEPARATOR) + wrapUserProvidedKey(entry[0]) + SUBSEPARATOR + getComponentKey(child, 0);
|
|
140
|
-
|
|
141
|
-
subtreeCount += traverseAllChildrenImpl(child, nextName, nextIndex, callback, traverseContext);
|
|
138
|
+
subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext);
|
|
142
139
|
}
|
|
143
140
|
}
|
|
144
141
|
}
|
|
@@ -149,8 +146,7 @@ function traverseAllChildrenImpl(children, nameSoFar, indexSoFar, callback, trav
|
|
|
149
146
|
if (fragment.hasOwnProperty(key)) {
|
|
150
147
|
child = fragment[key];
|
|
151
148
|
nextName = (nameSoFar !== '' ? nameSoFar + SUBSEPARATOR : SEPARATOR) + wrapUserProvidedKey(key) + SUBSEPARATOR + getComponentKey(child, 0);
|
|
152
|
-
|
|
153
|
-
subtreeCount += traverseAllChildrenImpl(child, nextName, nextIndex, callback, traverseContext);
|
|
149
|
+
subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext);
|
|
154
150
|
}
|
|
155
151
|
}
|
|
156
152
|
}
|
|
@@ -180,7 +176,7 @@ function traverseAllChildren(children, callback, traverseContext) {
|
|
|
180
176
|
return 0;
|
|
181
177
|
}
|
|
182
178
|
|
|
183
|
-
return traverseAllChildrenImpl(children, '',
|
|
179
|
+
return traverseAllChildrenImpl(children, '', callback, traverseContext);
|
|
184
180
|
}
|
|
185
181
|
|
|
186
182
|
module.exports = traverseAllChildren;
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
'use strict';
|
|
13
13
|
|
|
14
|
+
var assign = require("./Object.assign");
|
|
14
15
|
var emptyFunction = require("./emptyFunction");
|
|
15
16
|
var warning = require("./warning");
|
|
16
17
|
|
|
@@ -31,81 +32,86 @@ if ('production' !== process.env.NODE_ENV) {
|
|
|
31
32
|
// https://html.spec.whatwg.org/multipage/syntax.html#special
|
|
32
33
|
var specialTags = ['address', 'applet', 'area', 'article', 'aside', 'base', 'basefont', 'bgsound', 'blockquote', 'body', 'br', 'button', 'caption', 'center', 'col', 'colgroup', 'dd', 'details', 'dir', 'div', 'dl', 'dt', 'embed', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'iframe', 'img', 'input', 'isindex', 'li', 'link', 'listing', 'main', 'marquee', 'menu', 'menuitem', 'meta', 'nav', 'noembed', 'noframes', 'noscript', 'object', 'ol', 'p', 'param', 'plaintext', 'pre', 'script', 'section', 'select', 'source', 'style', 'summary', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'title', 'tr', 'track', 'ul', 'wbr', 'xmp'];
|
|
33
34
|
|
|
34
|
-
/**
|
|
35
|
-
* Return whether `stack` contains `tag` and the last occurrence of `tag` is
|
|
36
|
-
* deeper than any element in the `scope` array.
|
|
37
|
-
*
|
|
38
|
-
* https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-the-specific-scope
|
|
39
|
-
*
|
|
40
|
-
* Examples:
|
|
41
|
-
* stackHasTagInSpecificScope(['p', 'quote'], 'p', ['button']) is true
|
|
42
|
-
* stackHasTagInSpecificScope(['p', 'button'], 'p', ['button']) is false
|
|
43
|
-
*
|
|
44
|
-
* @param {Array<string>} stack
|
|
45
|
-
* @param {string} tag
|
|
46
|
-
* @param {Array<string>} scope
|
|
47
|
-
*/
|
|
48
|
-
var stackHasTagInSpecificScope = function (stack, tag, scope) {
|
|
49
|
-
for (var i = stack.length - 1; i >= 0; i--) {
|
|
50
|
-
if (stack[i] === tag) {
|
|
51
|
-
return true;
|
|
52
|
-
}
|
|
53
|
-
if (scope.indexOf(stack[i]) !== -1) {
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
return false;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
35
|
// https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-scope
|
|
61
36
|
var inScopeTags = ['applet', 'caption', 'html', 'table', 'td', 'th', 'marquee', 'object', 'template',
|
|
62
37
|
|
|
63
38
|
// https://html.spec.whatwg.org/multipage/syntax.html#html-integration-point
|
|
64
|
-
// TODO: Distinguish by namespace here
|
|
39
|
+
// TODO: Distinguish by namespace here -- for <title>, including it here
|
|
40
|
+
// errs on the side of fewer warnings
|
|
65
41
|
'foreignObject', 'desc', 'title'];
|
|
66
|
-
var stackHasTagInScope = function (stack, tag) {
|
|
67
|
-
return stackHasTagInSpecificScope(stack, tag, inScopeTags);
|
|
68
|
-
};
|
|
69
42
|
|
|
70
43
|
// https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-button-scope
|
|
71
44
|
var buttonScopeTags = inScopeTags.concat(['button']);
|
|
72
|
-
|
|
73
|
-
|
|
45
|
+
|
|
46
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#generate-implied-end-tags
|
|
47
|
+
var impliedEndTags = ['dd', 'dt', 'li', 'option', 'optgroup', 'p', 'rp', 'rt'];
|
|
48
|
+
|
|
49
|
+
var emptyAncestorInfo = {
|
|
50
|
+
parentTag: null,
|
|
51
|
+
|
|
52
|
+
formTag: null,
|
|
53
|
+
aTagInScope: null,
|
|
54
|
+
buttonTagInScope: null,
|
|
55
|
+
nobrTagInScope: null,
|
|
56
|
+
pTagInButtonScope: null,
|
|
57
|
+
|
|
58
|
+
listItemTagAutoclosing: null,
|
|
59
|
+
dlItemTagAutoclosing: null
|
|
74
60
|
};
|
|
75
61
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
62
|
+
var updatedAncestorInfo = function (oldInfo, tag, instance) {
|
|
63
|
+
var ancestorInfo = assign({}, oldInfo || emptyAncestorInfo);
|
|
64
|
+
var info = { tag: tag, instance: instance };
|
|
65
|
+
|
|
66
|
+
if (inScopeTags.indexOf(tag) !== -1) {
|
|
67
|
+
ancestorInfo.aTagInScope = null;
|
|
68
|
+
ancestorInfo.buttonTagInScope = null;
|
|
69
|
+
ancestorInfo.nobrTagInScope = null;
|
|
70
|
+
}
|
|
71
|
+
if (buttonScopeTags.indexOf(tag) !== -1) {
|
|
72
|
+
ancestorInfo.pTagInButtonScope = null;
|
|
86
73
|
}
|
|
87
|
-
return true;
|
|
88
|
-
};
|
|
89
74
|
|
|
90
|
-
|
|
91
|
-
|
|
75
|
+
// See rules for 'li', 'dd', 'dt' start tags in
|
|
76
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inbody
|
|
77
|
+
if (specialTags.indexOf(tag) !== -1 && tag !== 'address' && tag !== 'div' && tag !== 'p') {
|
|
78
|
+
ancestorInfo.listItemTagAutoclosing = null;
|
|
79
|
+
ancestorInfo.dlItemTagAutoclosing = null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
ancestorInfo.parentTag = info;
|
|
83
|
+
|
|
84
|
+
if (tag === 'form') {
|
|
85
|
+
ancestorInfo.formTag = info;
|
|
86
|
+
}
|
|
87
|
+
if (tag === 'a') {
|
|
88
|
+
ancestorInfo.aTagInScope = info;
|
|
89
|
+
}
|
|
90
|
+
if (tag === 'button') {
|
|
91
|
+
ancestorInfo.buttonTagInScope = info;
|
|
92
|
+
}
|
|
93
|
+
if (tag === 'nobr') {
|
|
94
|
+
ancestorInfo.nobrTagInScope = info;
|
|
95
|
+
}
|
|
96
|
+
if (tag === 'p') {
|
|
97
|
+
ancestorInfo.pTagInButtonScope = info;
|
|
98
|
+
}
|
|
99
|
+
if (tag === 'li') {
|
|
100
|
+
ancestorInfo.listItemTagAutoclosing = info;
|
|
101
|
+
}
|
|
102
|
+
if (tag === 'dd' || tag === 'dt') {
|
|
103
|
+
ancestorInfo.dlItemTagAutoclosing = info;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return ancestorInfo;
|
|
107
|
+
};
|
|
92
108
|
|
|
93
109
|
/**
|
|
94
|
-
* Returns whether
|
|
95
|
-
* of open tags is `openTagStack`.
|
|
96
|
-
*
|
|
97
|
-
* Examples:
|
|
98
|
-
* isTagValidInContext('tr', [..., 'table', 'tbody']) is true
|
|
99
|
-
* isTagValidInContext('tr', [..., 'table']) is false
|
|
100
|
-
*
|
|
101
|
-
* @param {string} tag Lowercase HTML tag name or node name like '#text'
|
|
102
|
-
* @param {Array<string>} openTagStack
|
|
110
|
+
* Returns whether
|
|
103
111
|
*/
|
|
104
|
-
var
|
|
105
|
-
var currentTag = openTagStack[openTagStack.length - 1];
|
|
106
|
-
|
|
112
|
+
var isTagValidWithParent = function (tag, parentTag) {
|
|
107
113
|
// First, let's check if we're in an unusual parsing mode...
|
|
108
|
-
switch (
|
|
114
|
+
switch (parentTag) {
|
|
109
115
|
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inselect
|
|
110
116
|
case 'select':
|
|
111
117
|
return tag === 'option' || tag === 'optgroup' || tag === '#text';
|
|
@@ -151,6 +157,44 @@ if ('production' !== process.env.NODE_ENV) {
|
|
|
151
157
|
// Probably in the "in body" parsing mode, so we outlaw only tag combos
|
|
152
158
|
// where the parsing rules cause implicit opens or closes to be added.
|
|
153
159
|
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inbody
|
|
160
|
+
switch (tag) {
|
|
161
|
+
case 'h1':
|
|
162
|
+
case 'h2':
|
|
163
|
+
case 'h3':
|
|
164
|
+
case 'h4':
|
|
165
|
+
case 'h5':
|
|
166
|
+
case 'h6':
|
|
167
|
+
return parentTag !== 'h1' && parentTag !== 'h2' && parentTag !== 'h3' && parentTag !== 'h4' && parentTag !== 'h5' && parentTag !== 'h6';
|
|
168
|
+
|
|
169
|
+
case 'rp':
|
|
170
|
+
case 'rt':
|
|
171
|
+
return impliedEndTags.indexOf(parentTag) === -1;
|
|
172
|
+
|
|
173
|
+
case 'caption':
|
|
174
|
+
case 'col':
|
|
175
|
+
case 'colgroup':
|
|
176
|
+
case 'frame':
|
|
177
|
+
case 'head':
|
|
178
|
+
case 'tbody':
|
|
179
|
+
case 'td':
|
|
180
|
+
case 'tfoot':
|
|
181
|
+
case 'th':
|
|
182
|
+
case 'thead':
|
|
183
|
+
case 'tr':
|
|
184
|
+
// These tags are only valid with a few parents that have special child
|
|
185
|
+
// parsing rules -- if we're down here, then none of those matched and
|
|
186
|
+
// so we allow it only if we don't know what the parent is, as all other
|
|
187
|
+
// cases are invalid.
|
|
188
|
+
return parentTag == null;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return true;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Returns whether
|
|
196
|
+
*/
|
|
197
|
+
var findInvalidAncestorForTag = function (tag, ancestorInfo) {
|
|
154
198
|
switch (tag) {
|
|
155
199
|
case 'address':
|
|
156
200
|
case 'article':
|
|
@@ -185,7 +229,6 @@ if ('production' !== process.env.NODE_ENV) {
|
|
|
185
229
|
case 'hr':
|
|
186
230
|
|
|
187
231
|
case 'xmp':
|
|
188
|
-
return !stackHasTagInButtonScope(openTagStack, 'p');
|
|
189
232
|
|
|
190
233
|
case 'h1':
|
|
191
234
|
case 'h2':
|
|
@@ -193,72 +236,120 @@ if ('production' !== process.env.NODE_ENV) {
|
|
|
193
236
|
case 'h4':
|
|
194
237
|
case 'h5':
|
|
195
238
|
case 'h6':
|
|
196
|
-
return
|
|
239
|
+
return ancestorInfo.pTagInButtonScope;
|
|
197
240
|
|
|
198
241
|
case 'form':
|
|
199
|
-
return
|
|
242
|
+
return ancestorInfo.formTag || ancestorInfo.pTagInButtonScope;
|
|
200
243
|
|
|
201
244
|
case 'li':
|
|
202
|
-
return
|
|
245
|
+
return ancestorInfo.listItemTagAutoclosing;
|
|
203
246
|
|
|
204
247
|
case 'dd':
|
|
205
248
|
case 'dt':
|
|
206
|
-
return
|
|
249
|
+
return ancestorInfo.dlItemTagAutoclosing;
|
|
207
250
|
|
|
208
251
|
case 'button':
|
|
209
|
-
return
|
|
252
|
+
return ancestorInfo.buttonTagInScope;
|
|
210
253
|
|
|
211
254
|
case 'a':
|
|
212
255
|
// Spec says something about storing a list of markers, but it sounds
|
|
213
256
|
// equivalent to this check.
|
|
214
|
-
return
|
|
257
|
+
return ancestorInfo.aTagInScope;
|
|
215
258
|
|
|
216
259
|
case 'nobr':
|
|
217
|
-
return
|
|
260
|
+
return ancestorInfo.nobrTagInScope;
|
|
261
|
+
}
|
|
218
262
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
return impliedEndTags.indexOf(currentTag) === -1;
|
|
263
|
+
return null;
|
|
264
|
+
};
|
|
222
265
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
case 'tfoot':
|
|
231
|
-
case 'th':
|
|
232
|
-
case 'thead':
|
|
233
|
-
case 'tr':
|
|
234
|
-
return currentTag === undefined;
|
|
266
|
+
/**
|
|
267
|
+
* Given a ReactCompositeComponent instance, return a list of its recursive
|
|
268
|
+
* owners, starting at the root and ending with the instance itself.
|
|
269
|
+
*/
|
|
270
|
+
var findOwnerStack = function (instance) {
|
|
271
|
+
if (!instance) {
|
|
272
|
+
return [];
|
|
235
273
|
}
|
|
236
274
|
|
|
237
|
-
|
|
275
|
+
var stack = [];
|
|
276
|
+
/*eslint-disable space-after-keywords */
|
|
277
|
+
do {
|
|
278
|
+
/*eslint-enable space-after-keywords */
|
|
279
|
+
stack.push(instance);
|
|
280
|
+
} while (instance = instance._currentElement._owner);
|
|
281
|
+
stack.reverse();
|
|
282
|
+
return stack;
|
|
238
283
|
};
|
|
239
284
|
|
|
240
|
-
validateDOMNesting = function (
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
285
|
+
validateDOMNesting = function (childTag, childInstance, ancestorInfo) {
|
|
286
|
+
ancestorInfo = ancestorInfo || emptyAncestorInfo;
|
|
287
|
+
var parentInfo = ancestorInfo.parentTag;
|
|
288
|
+
var parentTag = parentInfo && parentInfo.tag;
|
|
289
|
+
|
|
290
|
+
var invalidParent = isTagValidWithParent(childTag, parentTag) ? null : parentInfo;
|
|
291
|
+
var invalidAncestor = invalidParent ? null : findInvalidAncestorForTag(childTag, ancestorInfo);
|
|
292
|
+
var problematic = invalidParent || invalidAncestor;
|
|
293
|
+
|
|
294
|
+
if (problematic) {
|
|
295
|
+
var ancestorTag = problematic.tag;
|
|
296
|
+
var ancestorInstance = problematic.instance;
|
|
297
|
+
|
|
298
|
+
var childOwner = childInstance && childInstance._currentElement._owner;
|
|
299
|
+
var ancestorOwner = ancestorInstance && ancestorInstance._currentElement._owner;
|
|
300
|
+
|
|
301
|
+
var childOwners = findOwnerStack(childOwner);
|
|
302
|
+
var ancestorOwners = findOwnerStack(ancestorOwner);
|
|
303
|
+
|
|
304
|
+
var minStackLen = Math.min(childOwners.length, ancestorOwners.length);
|
|
305
|
+
var i;
|
|
306
|
+
|
|
307
|
+
var deepestCommon = -1;
|
|
308
|
+
for (i = 0; i < minStackLen; i++) {
|
|
309
|
+
if (childOwners[i] === ancestorOwners[i]) {
|
|
310
|
+
deepestCommon = i;
|
|
311
|
+
} else {
|
|
312
|
+
break;
|
|
251
313
|
}
|
|
252
314
|
}
|
|
253
315
|
|
|
254
|
-
|
|
316
|
+
var UNKNOWN = '(unknown)';
|
|
317
|
+
var childOwnerNames = childOwners.slice(deepestCommon + 1).map(function (inst) {
|
|
318
|
+
return inst.getName() || UNKNOWN;
|
|
319
|
+
});
|
|
320
|
+
var ancestorOwnerNames = ancestorOwners.slice(deepestCommon + 1).map(function (inst) {
|
|
321
|
+
return inst.getName() || UNKNOWN;
|
|
322
|
+
});
|
|
323
|
+
var ownerInfo = [].concat(
|
|
324
|
+
// If the parent and child instances have a common owner ancestor, start
|
|
325
|
+
// with that -- otherwise we just start with the parent's owners.
|
|
326
|
+
deepestCommon !== -1 ? childOwners[deepestCommon].getName() || UNKNOWN : [], ancestorOwnerNames, ancestorTag,
|
|
327
|
+
// If we're warning about an invalid (non-parent) ancestry, add '...'
|
|
328
|
+
invalidAncestor ? ['...'] : [], childOwnerNames, childTag).join(' > ');
|
|
329
|
+
|
|
330
|
+
if (invalidParent) {
|
|
331
|
+
var info = '';
|
|
332
|
+
if (ancestorTag === 'table' && childTag === 'tr') {
|
|
333
|
+
info += ' Add a <tbody> to your code to match the DOM tree generated by ' + 'the browser.';
|
|
334
|
+
}
|
|
335
|
+
'production' !== process.env.NODE_ENV ? warning(false, 'validateDOMNesting(...): <%s> cannot appear as a child of <%s>. ' + 'See %s.%s', childTag, ancestorTag, ownerInfo, info) : null;
|
|
336
|
+
} else {
|
|
337
|
+
'production' !== process.env.NODE_ENV ? warning(false, 'validateDOMNesting(...): <%s> cannot appear as a descendant of ' + '<%s>. See %s.', childTag, ancestorTag, ownerInfo) : null;
|
|
338
|
+
}
|
|
255
339
|
}
|
|
256
340
|
};
|
|
257
341
|
|
|
258
|
-
validateDOMNesting.
|
|
342
|
+
validateDOMNesting.ancestorInfoContextKey = '__validateDOMNesting_ancestorInfo$' + Math.random().toString(36).slice(2);
|
|
343
|
+
|
|
344
|
+
validateDOMNesting.updatedAncestorInfo = updatedAncestorInfo;
|
|
259
345
|
|
|
260
346
|
// For testing
|
|
261
|
-
validateDOMNesting.isTagValidInContext =
|
|
347
|
+
validateDOMNesting.isTagValidInContext = function (tag, ancestorInfo) {
|
|
348
|
+
ancestorInfo = ancestorInfo || emptyAncestorInfo;
|
|
349
|
+
var parentInfo = ancestorInfo.parentTag;
|
|
350
|
+
var parentTag = parentInfo && parentInfo.tag;
|
|
351
|
+
return isTagValidWithParent(tag, parentTag) && !findInvalidAncestorForTag(tag, ancestorInfo);
|
|
352
|
+
};
|
|
262
353
|
}
|
|
263
354
|
|
|
264
355
|
module.exports = validateDOMNesting;
|