diff --git a/.eslintrc.js b/.eslintrc.js index c7bb16a4607b..9cc7d1d024b9 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -5,32 +5,27 @@ const OFF = 0; const ERROR = 2; module.exports = { - parser: 'babel-eslint', - - extends: './node_modules/fbjs-scripts/eslint/.eslintrc.js', + extends: 'fbjs', plugins: [ 'react', 'react-internal', ], - ecmaFeatures: { - modules: false, - }, - // We're stricter than the default config, mostly. We'll override a few rules // and then enable some React specific ones. rules: { 'accessor-pairs': OFF, 'brace-style': [ERROR, '1tbs'], 'comma-dangle': [ERROR, 'always-multiline'], - 'consistent-return': ERROR, + 'consistent-return': OFF, 'dot-location': [ERROR, 'property'], 'dot-notation': ERROR, 'eol-last': ERROR, 'eqeqeq': [ERROR, 'allow-null'], 'indent': [ERROR, 2, {SwitchCase: 1}], 'jsx-quotes': [ERROR, 'prefer-double'], + 'keyword-spacing': [ERROR, {after: true, before: true}], 'no-bitwise': OFF, 'no-inner-declarations': [ERROR, 'functions'], 'no-multi-spaces': ERROR, @@ -38,36 +33,23 @@ module.exports = { 'no-shadow': ERROR, 'no-unused-expressions': ERROR, 'no-unused-vars': [ERROR, {args: 'none'}], - 'quotes': [ERROR, 'single', 'avoid-escape'], - 'space-after-keywords': ERROR, + 'quotes': [ERROR, 'single', {avoidEscape: true, allowTemplateLiterals: true }], 'space-before-blocks': ERROR, 'space-before-function-paren': [ERROR, {anonymous: 'never', named: 'never'}], - 'space-before-keywords': ERROR, - 'strict': [ERROR, 'global'], // React & JSX // Our transforms set this automatically - 'react/display-name': OFF, 'react/jsx-boolean-value': [ERROR, 'always'], 'react/jsx-no-undef': ERROR, // We don't care to do this 'react/jsx-sort-prop-types': OFF, - 'react/jsx-sort-props': OFF, 'react/jsx-uses-react': ERROR, - 'react/jsx-uses-vars': ERROR, - // It's easier to test some things this way - 'react/no-did-mount-set-state': OFF, - 'react/no-did-update-set-state': OFF, - // We define multiple components in test files - 'react/no-multi-comp': OFF, - 'react/no-unknown-property': OFF, + 'react/no-is-mounted': OFF, // This isn't useful in our test code - 'react/prop-types': OFF, 'react/react-in-jsx-scope': ERROR, 'react/self-closing-comp': ERROR, // We don't care to do this - 'react/sort-comp': OFF, - 'react/wrap-multilines': [ERROR, {declaration: false, assignment: false}], + 'react/jsx-wrap-multilines': [ERROR, {declaration: false, assignment: false}], // CUSTOM RULES // the second argument of warning/invariant should be a literal string diff --git a/.travis.yml b/.travis.yml index 59a259805c68..ad5fe0139cd4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,13 +3,14 @@ sudo: required dist: trusty language: node_js node_js: -- 4 +- 6 rvm: - 2.2.3 cache: directories: - docs/vendor/bundle - node_modules + - $HOME/.yarn-cache before_install: - | if [ "$TEST_TYPE" != build_website ] && \ @@ -18,8 +19,15 @@ before_install: echo "Only docs were updated, stopping build process." exit fi - npm install -g npm@latest-2 - npm --version + + sudo apt-key adv --fetch-keys http://dl.yarnpkg.com/debian/pubkey.gpg + echo "deb http://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list + sudo apt-get update -qq + sudo apt-get install -y -qq yarn + yarn --version +install: +- | + yarn install script: - | if [ "$TEST_TYPE" = build_website ]; then diff --git a/package.json b/package.json index 895123ebedfa..d87967b0c82e 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "async": "^1.5.0", "babel-cli": "^6.6.5", "babel-core": "^6.0.0", - "babel-eslint": "^5.0.0", + "babel-eslint": "^7.1.0", "babel-plugin-check-es2015-constants": "^6.5.0", "babel-plugin-syntax-trailing-function-commas": "^6.5.0", "babel-plugin-transform-class-properties": "^6.11.5", @@ -40,8 +40,11 @@ "coveralls": "^2.11.6", "del": "^2.0.2", "derequire": "^2.0.3", - "eslint": "1.10.3", - "eslint-plugin-react": "4.1.0", + "eslint": "^3.10.2", + "eslint-config-fbjs": "^1.1.1", + "eslint-plugin-babel": "^3.3.0", + "eslint-plugin-flowtype": "^2.25.0", + "eslint-plugin-react": "^6.7.1", "eslint-plugin-react-internal": "file:eslint-rules", "fbjs": "^0.8.5", "fbjs-scripts": "^0.6.0", diff --git a/scripts/facts-tracker/index.js b/scripts/facts-tracker/index.js index 70fa9e20061d..4bb6c42f1e3e 100644 --- a/scripts/facts-tracker/index.js +++ b/scripts/facts-tracker/index.js @@ -160,7 +160,7 @@ for (var i = 2; i < process.argv.length; i += 2) { fs.appendFileSync( path.resolve(cwd, filename), currentCommitHash + '\t' + currentTimestamp + '\t' + value + '\n' - ); + ); } console.log(name); diff --git a/src/addons/__tests__/renderSubtreeIntoContainer-test.js b/src/addons/__tests__/renderSubtreeIntoContainer-test.js index 7e7d12c7a62d..1ee3bd6a939b 100644 --- a/src/addons/__tests__/renderSubtreeIntoContainer-test.js +++ b/src/addons/__tests__/renderSubtreeIntoContainer-test.js @@ -70,6 +70,9 @@ describe('renderSubtreeIntoContainer', () => { } } + // ESLint is confused here and thinks Parent is unused, presumably because + // it is only used inside of the class body? + // eslint-disable-next-line no-unused-vars class Parent extends React.Component { static childContextTypes = { foo: React.PropTypes.string.isRequired, diff --git a/src/isomorphic/children/__tests__/ReactChildren-test.js b/src/isomorphic/children/__tests__/ReactChildren-test.js index 17dab948599c..6eb4c89e2d12 100644 --- a/src/isomorphic/children/__tests__/ReactChildren-test.js +++ b/src/isomorphic/children/__tests__/ReactChildren-test.js @@ -399,16 +399,14 @@ describe('ReactChildren', () => { // 2. If grouped in an Array, the `key` prop, falling back to array index var instance = ( -
{ - [ - ReactFragment.create({ - firstHalfKey: [zero, one, two], - secondHalfKey: [three, four], - keyFive: five, - }), - null, - ] - }
+
{[ + ReactFragment.create({ + firstHalfKey: [zero, one, two], + secondHalfKey: [three, four], + keyFive: five, + }), + null, + ]}
); var numberOfChildren = ReactChildren.count(instance.props.children); expect(numberOfChildren).toBe(5); diff --git a/src/isomorphic/classic/class/__tests__/ReactClassMixin-test.js b/src/isomorphic/classic/class/__tests__/ReactClassMixin-test.js index df17f8c370a1..971f19199d1e 100644 --- a/src/isomorphic/classic/class/__tests__/ReactClassMixin-test.js +++ b/src/isomorphic/classic/class/__tests__/ReactClassMixin-test.js @@ -124,7 +124,7 @@ describe('ReactClass-mixin', () => { it('should support chaining delegate functions', () => { var listener = jest.fn(); var instance = ; - instance = ReactTestUtils.renderIntoDocument(instance); + ReactTestUtils.renderIntoDocument(instance); expect(listener.mock.calls).toEqual([ ['MixinA didMount'], @@ -137,7 +137,7 @@ describe('ReactClass-mixin', () => { it('should chain functions regardless of spec property order', () => { var listener = jest.fn(); var instance = ; - instance = ReactTestUtils.renderIntoDocument(instance); + ReactTestUtils.renderIntoDocument(instance); expect(listener.mock.calls).toEqual([ ['MixinA didMount'], @@ -181,8 +181,7 @@ describe('ReactClass-mixin', () => { return ; }, }); - var instance = ; - instance = ReactTestUtils.renderIntoDocument(instance); + var instance = ReactTestUtils.renderIntoDocument(); expect(instance.state.component).toBe(true); expect(instance.state.mixin).toBe(true); }); @@ -202,9 +201,8 @@ describe('ReactClass-mixin', () => { return ; }, }); - var instance = ; expect(function() { - instance = ReactTestUtils.renderIntoDocument(instance); + ReactTestUtils.renderIntoDocument(); }).toThrowError( 'mergeIntoWithNoDuplicateKeys(): Tried to merge two objects with the ' + 'same key: `x`. This conflict may be due to a mixin; in particular, ' + @@ -450,8 +448,7 @@ describe('ReactClass-mixin', () => { return ; }, }); - var instance = ; - instance = ReactTestUtils.renderIntoDocument(instance); + ReactTestUtils.renderIntoDocument(); }); it('should include the mixin keys in even if their values are falsy', () => { @@ -470,8 +467,7 @@ describe('ReactClass-mixin', () => { return ; }, }); - var instance = ; - instance = ReactTestUtils.renderIntoDocument(instance); + ReactTestUtils.renderIntoDocument(); }); it('should work with a null getInitialState return value and a mixin', () => { @@ -496,8 +492,7 @@ describe('ReactClass-mixin', () => { () => ReactTestUtils.renderIntoDocument() ).not.toThrow(); - instance = ; - instance = ReactTestUtils.renderIntoDocument(instance); + instance = ReactTestUtils.renderIntoDocument(); expect(instance.state).toEqual({foo: 'bar'}); // Also the other way round should work @@ -519,8 +514,7 @@ describe('ReactClass-mixin', () => { () => ReactTestUtils.renderIntoDocument() ).not.toThrow(); - instance = ; - instance = ReactTestUtils.renderIntoDocument(instance); + instance = ReactTestUtils.renderIntoDocument(); expect(instance.state).toEqual({foo: 'bar'}); // Multiple mixins should be fine too @@ -537,8 +531,7 @@ describe('ReactClass-mixin', () => { () => ReactTestUtils.renderIntoDocument() ).not.toThrow(); - instance = ; - instance = ReactTestUtils.renderIntoDocument(instance); + instance = ReactTestUtils.renderIntoDocument(); expect(instance.state).toEqual({foo: 'bar', x: true}); }); diff --git a/src/isomorphic/classic/types/ReactPropTypes.js b/src/isomorphic/classic/types/ReactPropTypes.js index 15fad747700f..944546b0a119 100644 --- a/src/isomorphic/classic/types/ReactPropTypes.js +++ b/src/isomorphic/classic/types/ReactPropTypes.js @@ -68,9 +68,11 @@ var warning = require('warning'); var ANONYMOUS = '<>'; +var ReactPropTypes; + if (__DEV__) { // Keep in sync with production version below - var ReactPropTypes = { + ReactPropTypes = { array: createPrimitiveTypeChecker('array'), bool: createPrimitiveTypeChecker('boolean'), func: createPrimitiveTypeChecker('function'), @@ -99,7 +101,7 @@ if (__DEV__) { productionTypeChecker.isRequired = productionTypeChecker; var getProductionTypeChecker = () => productionTypeChecker; // Keep in sync with development version above - var ReactPropTypes = { + ReactPropTypes = { array: productionTypeChecker, bool: productionTypeChecker, func: productionTypeChecker, diff --git a/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js b/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js index 18a57c7be154..dde0583931a1 100644 --- a/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js +++ b/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js @@ -308,7 +308,7 @@ describe('ReactPropTypes', () => { spyOn(console, 'error'); var instance = } />; - instance = ReactTestUtils.renderIntoDocument(instance); + ReactTestUtils.renderIntoDocument(instance); expectDev(console.error.calls.count()).toBe(0); }); @@ -317,7 +317,7 @@ describe('ReactPropTypes', () => { spyOn(console, 'error'); var instance = ; - instance = ReactTestUtils.renderIntoDocument(instance); + ReactTestUtils.renderIntoDocument(instance); expectDev(console.error.calls.count()).toBe(1); }); @@ -851,7 +851,7 @@ describe('ReactPropTypes', () => { }; var instance = ; - instance = ReactTestUtils.renderIntoDocument(instance); + ReactTestUtils.renderIntoDocument(instance); expect(spy.calls.count()).toBe(1); expect(spy.calls.argsFor(0)[1]).toBe('num'); @@ -868,7 +868,7 @@ describe('ReactPropTypes', () => { }; var instance = ; - instance = ReactTestUtils.renderIntoDocument(instance); + ReactTestUtils.renderIntoDocument(instance); expect(spy.calls.count()).toBe(1); expect(spy.calls.argsFor(0)[1]).toBe('num'); @@ -892,7 +892,7 @@ describe('ReactPropTypes', () => { }; var instance = ; - instance = ReactTestUtils.renderIntoDocument(instance); + ReactTestUtils.renderIntoDocument(instance); expectDev(console.error.calls.count()).toBe(1); expect( console.error.calls.argsFor(0)[0].replace(/\(at .+?:\d+\)/g, '(at **)') @@ -919,7 +919,7 @@ describe('ReactPropTypes', () => { }; var instance = ; - instance = ReactTestUtils.renderIntoDocument(instance); + ReactTestUtils.renderIntoDocument(instance); expectDev(console.error.calls.count()).toBe(0); } ); diff --git a/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js b/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js index 9615613e3f3c..0c42b4c46746 100644 --- a/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js +++ b/src/isomorphic/classic/types/__tests__/ReactPropTypesProduction-test.js @@ -212,7 +212,7 @@ describe('ReactPropTypesProduction', function() { }); var instance = ; - instance = ReactTestUtils.renderIntoDocument(instance); + ReactTestUtils.renderIntoDocument(instance); expect(spy).not.toBeCalled(); }); diff --git a/src/isomorphic/hooks/ReactComponentTreeHook.js b/src/isomorphic/hooks/ReactComponentTreeHook.js index 75292cbfebb7..a5fdd85a58cb 100644 --- a/src/isomorphic/hooks/ReactComponentTreeHook.js +++ b/src/isomorphic/hooks/ReactComponentTreeHook.js @@ -63,30 +63,38 @@ var canUseCollections = ( isNative(Set.prototype.keys) ); +var setItem; +var getItem; +var removeItem; +var getItemIDs; +var addRoot; +var removeRoot; +var getRootIDs; + if (canUseCollections) { var itemMap = new Map(); var rootIDSet = new Set(); - var setItem = function(id, item) { + setItem = function(id, item) { itemMap.set(id, item); }; - var getItem = function(id) { + getItem = function(id) { return itemMap.get(id); }; - var removeItem = function(id) { + removeItem = function(id) { itemMap.delete(id); }; - var getItemIDs = function() { + getItemIDs = function() { return Array.from(itemMap.keys()); }; - var addRoot = function(id) { + addRoot = function(id) { rootIDSet.add(id); }; - var removeRoot = function(id) { + removeRoot = function(id) { rootIDSet.delete(id); }; - var getRootIDs = function() { + getRootIDs = function() { return Array.from(rootIDSet.keys()); }; @@ -103,31 +111,31 @@ if (canUseCollections) { return parseInt(key.substr(1), 10); }; - var setItem = function(id, item) { + setItem = function(id, item) { var key = getKeyFromID(id); itemByKey[key] = item; }; - var getItem = function(id) { + getItem = function(id) { var key = getKeyFromID(id); return itemByKey[key]; }; - var removeItem = function(id) { + removeItem = function(id) { var key = getKeyFromID(id); delete itemByKey[key]; }; - var getItemIDs = function() { + getItemIDs = function() { return Object.keys(itemByKey).map(getIDFromKey); }; - var addRoot = function(id) { + addRoot = function(id) { var key = getKeyFromID(id); rootByKey[key] = true; }; - var removeRoot = function(id) { + removeRoot = function(id) { var key = getKeyFromID(id); delete rootByKey[key]; }; - var getRootIDs = function() { + getRootIDs = function() { return Object.keys(rootByKey).map(getIDFromKey); }; } diff --git a/src/isomorphic/modern/element/__tests__/ReactJSXElement-test.js b/src/isomorphic/modern/element/__tests__/ReactJSXElement-test.js index 84970acf8cfd..585a3ca0ba8a 100644 --- a/src/isomorphic/modern/element/__tests__/ReactJSXElement-test.js +++ b/src/isomorphic/modern/element/__tests__/ReactJSXElement-test.js @@ -147,7 +147,7 @@ describe('ReactJSXElement', () => { return 'someReturnValue'; } render() { - return
; + return
; } } diff --git a/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js b/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js index 9705a69f1306..c3be319d548f 100644 --- a/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js +++ b/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js @@ -146,9 +146,9 @@ describe('ReactDOMComponent', () => { style = {background: 'red'}; var div = document.createElement('div'); - ReactDOM.render(, div); + ReactDOM.render(, div); style.background = 'blue'; - ReactDOM.render(, div); + ReactDOM.render(, div); expectDev(console.error.calls.count()).toBe(2); }); @@ -202,8 +202,8 @@ describe('ReactDOMComponent', () => { var style = {fontSize: NaN}; var div = document.createElement('div'); - ReactDOM.render(, div); - ReactDOM.render(, div); + ReactDOM.render(, div); + ReactDOM.render(, div); expectDev(console.error.calls.count()).toBe(1); expectDev(console.error.calls.argsFor(0)[0]).toEqual( @@ -250,7 +250,7 @@ describe('ReactDOMComponent', () => { ReactDOM.render( - + , container @@ -1033,11 +1033,11 @@ describe('ReactDOMComponent', () => { }); it('should validate against multiple children props', () => { - ReactDOM.render(
, container); + ReactDOM.render(
, container); expect(function() { ReactDOM.render( -
, +
, container ); }).toThrowError( @@ -1056,10 +1056,10 @@ describe('ReactDOMComponent', () => { }); it('should validate against invalid styles', () => { - ReactDOM.render(
, container); + ReactDOM.render(
, container); expect(function() { - ReactDOM.render(
, container); + ReactDOM.render(
, container); }).toThrowError( 'The `style` prop expects a mapping from style properties to values, ' + 'not a string. For example, style={{marginRight: spacing + \'em\'}} ' + @@ -1070,7 +1070,7 @@ describe('ReactDOMComponent', () => { it('should report component containing invalid styles', () => { class Animal extends React.Component { render() { - return
; + return
; } } diff --git a/src/renderers/dom/shared/__tests__/inputValueTracking-test.js b/src/renderers/dom/shared/__tests__/inputValueTracking-test.js index 9be2c5eca47c..311caeefa35c 100644 --- a/src/renderers/dom/shared/__tests__/inputValueTracking-test.js +++ b/src/renderers/dom/shared/__tests__/inputValueTracking-test.js @@ -49,7 +49,7 @@ describe('inputValueTracking', () => { }); it('should initialize with the current value', () => { - input.value ='foo'; + input.value = 'foo'; inputValueTracking.track(mockComponent); @@ -69,13 +69,13 @@ describe('inputValueTracking', () => { }); it('should track value changes', () => { - input.value ='foo'; + input.value = 'foo'; inputValueTracking.track(mockComponent); var tracker = mockComponent._wrapperState.valueTracker; - input.value ='bar'; + input.value = 'bar'; expect(tracker.getValue()).toEqual('bar'); }); @@ -91,7 +91,7 @@ describe('inputValueTracking', () => { }); it('should update value manually', () => { - input.value ='foo'; + input.value = 'foo'; inputValueTracking.track(mockComponent); var tracker = mockComponent._wrapperState.valueTracker; @@ -101,7 +101,7 @@ describe('inputValueTracking', () => { }); it('should coerce value to a string', () => { - input.value ='foo'; + input.value = 'foo'; inputValueTracking.track(mockComponent); var tracker = mockComponent._wrapperState.valueTracker; @@ -112,7 +112,7 @@ describe('inputValueTracking', () => { it('should update value if it changed and return result', () => { inputValueTracking.track(mockComponent); - input.value ='foo'; + input.value = 'foo'; var tracker = mockComponent._wrapperState.valueTracker; @@ -130,7 +130,7 @@ describe('inputValueTracking', () => { }); it('should track value and return true when updating untracked instance', () => { - input.value ='foo'; + input.value = 'foo'; expect( inputValueTracking.updateValueIfChanged(mockComponent) diff --git a/src/renderers/dom/shared/dangerousStyleValue.js b/src/renderers/dom/shared/dangerousStyleValue.js index 3cc041fe5af1..32fb68a02870 100644 --- a/src/renderers/dom/shared/dangerousStyleValue.js +++ b/src/renderers/dom/shared/dangerousStyleValue.js @@ -43,7 +43,7 @@ function dangerousStyleValue(name, value, component) { if (typeof value === 'number' && value !== 0 && !(isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name])) { - return value+'px'; // Presumes implicit 'px' suffix for unitless numbers + return value + 'px'; // Presumes implicit 'px' suffix for unitless numbers } return ('' + value).trim(); diff --git a/src/renderers/dom/shared/eventPlugins/__tests__/SelectEventPlugin-test.js b/src/renderers/dom/shared/eventPlugins/__tests__/SelectEventPlugin-test.js index 083dd1446e04..1f6464b6f429 100644 --- a/src/renderers/dom/shared/eventPlugins/__tests__/SelectEventPlugin-test.js +++ b/src/renderers/dom/shared/eventPlugins/__tests__/SelectEventPlugin-test.js @@ -48,7 +48,7 @@ describe('SelectEventPlugin', () => { // It seems that .focus() isn't triggering this event in our test // environment so we need to ensure it gets set for this test to be valid. - var fakeNativeEvent = new function() {}; + var fakeNativeEvent = function() {}; fakeNativeEvent.target = node; ReactTestUtils.simulateNativeEventOnNode( 'topFocus', diff --git a/src/renderers/dom/shared/eventPlugins/__tests__/SimpleEventPlugin-test.js b/src/renderers/dom/shared/eventPlugins/__tests__/SimpleEventPlugin-test.js index d8f30633d10b..9aa5670e448e 100644 --- a/src/renderers/dom/shared/eventPlugins/__tests__/SimpleEventPlugin-test.js +++ b/src/renderers/dom/shared/eventPlugins/__tests__/SimpleEventPlugin-test.js @@ -131,7 +131,7 @@ describe('SimpleEventPlugin', function() { it('does not add a local click to interactive elements', function() { var container = document.createElement('div'); - ReactDOM.render(, container); + ReactDOM.render(