From f44a0778e384927d6724650deb8558bf4b53d5e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20O=E2=80=99Shannessy?= Date: Mon, 23 Nov 2015 15:33:34 -0800 Subject: [PATCH] Don't use `key` when defined on String, Number prototypes --- .../__tests__/traverseAllChildren-test.js | 33 +++++++++++++++++++ src/shared/utils/traverseAllChildren.js | 4 ++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/shared/utils/__tests__/traverseAllChildren-test.js b/src/shared/utils/__tests__/traverseAllChildren-test.js index a4c8954db5..d981bb93f0 100644 --- a/src/shared/utils/__tests__/traverseAllChildren-test.js +++ b/src/shared/utils/__tests__/traverseAllChildren-test.js @@ -476,6 +476,39 @@ describe('traverseAllChildren', function() { } }); + it('should allow extension of native prototypes', function() { + /*eslint-disable no-extend-native */ + String.prototype.key = 'react'; + Number.prototype.key = 'rocks'; + /*eslint-enable no-extend-native */ + + var instance = ( +
+ {'a'} + {13} +
+ ); + + var traverseFn = jasmine.createSpy(); + + traverseAllChildren(instance.props.children, traverseFn, null); + expect(traverseFn.calls.length).toBe(2); + + expect(traverseFn).toHaveBeenCalledWith( + null, + 'a', + '.0' + ); + expect(traverseFn).toHaveBeenCalledWith( + null, + 13, + '.1' + ); + + delete String.prototype.key; + delete Number.prototype.key; + }); + it('should throw on object', function() { expect(function() { traverseAllChildren({a: 1, b: 2}, function() {}, null); diff --git a/src/shared/utils/traverseAllChildren.js b/src/shared/utils/traverseAllChildren.js index f7f7e878eb..62146c7431 100644 --- a/src/shared/utils/traverseAllChildren.js +++ b/src/shared/utils/traverseAllChildren.js @@ -47,7 +47,9 @@ function userProvidedKeyEscaper(match) { * @return {string} */ function getComponentKey(component, index) { - if (component && component.key != null) { + // Do some typechecking here since we call this blindly. We want to ensure + // that we don't block potential future ES APIs. + if (component && typeof component === 'object' && component.key != null) { // Explicit key return wrapUserProvidedKey(component.key); }