Skip to content

Commit

Permalink
Simplify to enumerables + symbols and inherit statics (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
mridgway authored Jun 23, 2017
1 parent 75b47f6 commit 8e1959c
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 35 deletions.
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
sudo: false
language: node_js
node_js:
- "8"
- "6"
- "4"
- "0.12"
- "0.10"
after_success:
- "npm run cover"
- "cat artifacts/lcov.info | ./node_modules/coveralls/bin/coveralls.js"
51 changes: 31 additions & 20 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,35 +15,46 @@ var REACT_STATICS = {
type: true
};

var KNOWN_STATICS = {
name: true,
length: true,
prototype: true,
caller: true,
arguments: true,
arity: true
};

var isGetOwnPropertySymbolsAvailable = typeof Object.getOwnPropertySymbols === 'function';
var getOwnPropertySymbols = Object.getOwnPropertySymbols;
var hasOwnProperty = Object.prototype.hasOwnProperty;
var propIsEnumerable = Object.prototype.propertyIsEnumerable;
var getPrototypeOf = Object.getPrototypeOf;
var objectPrototype = getPrototypeOf && getPrototypeOf(Object);

module.exports = function hoistNonReactStatics(targetComponent, sourceComponent, customStatics) {
module.exports = function hoistNonReactStatics(targetComponent, sourceComponent, blacklist) {
if (typeof sourceComponent !== 'string') { // don't hoist over string (html) components
var keys = Object.getOwnPropertyNames(sourceComponent);

/* istanbul ignore else */
if (isGetOwnPropertySymbolsAvailable) {
keys = keys.concat(Object.getOwnPropertySymbols(sourceComponent));
if (objectPrototype) {
var inheritedComponent = getPrototypeOf(sourceComponent);
if (inheritedComponent && inheritedComponent !== objectPrototype) {
hoistNonReactStatics(targetComponent, inheritedComponent, blacklist);
}
}

for (var i = 0; i < keys.length; ++i) {
if (!REACT_STATICS[keys[i]] && !KNOWN_STATICS[keys[i]] && (!customStatics || !customStatics[keys[i]])) {
try {
targetComponent[keys[i]] = sourceComponent[keys[i]];
} catch (error) {
for (var key in sourceComponent) {
if (!REACT_STATICS[key] && (!blacklist || !blacklist[key])) {
if (hasOwnProperty.call(sourceComponent, key)) {
try { // Avoid failures from read-only properties
targetComponent[key] = sourceComponent[key];
} catch (e) {}
}
}
}

if (getOwnPropertySymbols) {
var symbols = getOwnPropertySymbols(sourceComponent);
for (var i = 0; i < symbols.length; i++) {
if (!REACT_STATICS[symbols[i]] && (!blacklist || !blacklist[symbols[i]])) {
if (propIsEnumerable.call(sourceComponent, symbols[i])) {
try { // Avoid failures from read-only properties
targetComponent[symbols[i]] = sourceComponent[symbols[i]];
} catch(e) {}
}
}
}
}

return targetComponent;
}

return targetComponent;
Expand Down
18 changes: 13 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,25 @@
"scripts": {
"cover": "node node_modules/istanbul/lib/cli.js cover --dir artifacts -- ./node_modules/mocha/bin/_mocha tests/unit/ --recursive --compilers js:babel/register --reporter spec",
"lint": "eslint ./index.js",
"test": "mocha tests/unit/ --recursive --compilers js:babel/register --reporter spec"
"test": "mocha tests/unit/ --recursive --compilers js:babel-register --reporter spec"
},
"author": "Michael Ridgway <[email protected]>",
"license": "BSD-3-Clause",
"devDependencies": {
"babel": "^5.0.7",
"chai": "^3.0.0",
"babel": "^6.23.0",
"babel-cli": "^6.24.1",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-react-jsx-source": "^6.22.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-es2016": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-register": "^6.24.1",
"chai": "^4.0.1",
"coveralls": "^2.11.1",
"create-react-class": "^15.5.3",
"eslint": "^3.8.0",
"istanbul": "^0.3.2",
"mocha": "^2.0.1",
"istanbul": "^0.4.5",
"mocha": "^3.4.2",
"pre-commit": "^1.0.7",
"react": "^15.0.0"
},
Expand Down
6 changes: 6 additions & 0 deletions tests/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"presets": ["es2015", "es2016", "react"],
"plugins": [
"transform-class-properties"
]
}
40 changes: 32 additions & 8 deletions tests/unit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@

var expect = require('chai').expect;
var React = require('react');
var createReactClass = require('create-react-class');
var hoistNonReactStatics = require('../../index');

describe('hoist-non-react-statics', function () {

it('should hoist non react statics', function () {
var Component = React.createClass({
var Component = createReactClass({
displayName: 'Foo',
statics: {
foo: 'bar'
Expand All @@ -18,7 +19,7 @@ describe('hoist-non-react-statics', function () {
}
});

var Wrapper = React.createClass({
var Wrapper = createReactClass({
displayName: 'Bar',
render: function () {
return <Component />;
Expand All @@ -32,7 +33,7 @@ describe('hoist-non-react-statics', function () {
});

it('should not hoist custom statics', function () {
var Component = React.createClass({
var Component = createReactClass({
displayName: 'Foo',
statics: {
foo: 'bar'
Expand All @@ -42,7 +43,7 @@ describe('hoist-non-react-statics', function () {
}
});

var Wrapper = React.createClass({
var Wrapper = createReactClass({
displayName: 'Bar',
render: function () {
return <Component />;
Expand All @@ -55,7 +56,7 @@ describe('hoist-non-react-statics', function () {

it('should not hoist statics from strings', function() {
var Component = 'input';
var Wrapper = React.createClass({
var Wrapper = createReactClass({
render: function() {
return <Component />;
}
Expand All @@ -68,17 +69,17 @@ describe('hoist-non-react-statics', function () {
it('should hoist symbols', function() {
var foo = Symbol('foo');

var Component = React.createClass({
var Component = createReactClass({
render: function() {
return null;
}
});

// Manually set static property using Symbol
// since React.createClass doesn't handle symbols passed to static
// since createReactClass doesn't handle symbols passed to static
Component[foo] = 'bar';

var Wrapper = React.createClass({
var Wrapper = createReactClass({
render: function() {
return <Component />;
}
Expand All @@ -89,4 +90,27 @@ describe('hoist-non-react-statics', function () {
expect(Wrapper[foo]).to.equal('bar');
});

it('should inherit class properties', () => {
class A extends React.Component {
static test3 = 'A';
static test4 = 'D';
test5 = 'foo';
}
class B extends A {
static test2 = 'B';
static test4 = 'DD';
}
class C {
static test1 = 'C';
}
const D = hoistNonReactStatics(C, B);


expect(D.test1).to.equal('C');
expect(D.test2).to.equal('B');
expect(D.test3).to.equal('A');
expect(D.test4).to.equal('DD');
expect(D.test5).to.equal(undefined);
});

});

0 comments on commit 8e1959c

Please sign in to comment.