diff --git a/.travis.yml b/.travis.yml index df4ad7cf56..b43ee559d0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ install: - 'if [ -n "${PACKAGE-}" ]; then cd "packages/${PACKAGE}"; fi' - 'if [ "${TRAVIS_NODE_VERSION}" = "0.6" ] || [ "${TRAVIS_NODE_VERSION}" = "0.9" ]; then nvm install --latest-npm 0.8 && npm install && nvm use "${TRAVIS_NODE_VERSION}"; else npm install; fi;' - 'if [ -n "${ESLINT}" ]; then npm install --no-save "eslint@${ESLINT}"; fi' + - 'if [ -n "${REACT_HOOKS}" ]; then npm install --no-save "eslint-plugin-react-hooks@${REACT_HOOKS}"; fi' script: - 'if [ -n "${PREPUBLISH-}" ]; then npm run pretravis && npm run prepublish && npm run posttravis; elif [ -n "${LINT-}" ]; then npm run lint; else npm run travis; fi' sudo: false @@ -18,8 +19,10 @@ env: matrix: - 'TEST=true ESLINT=6 PACKAGE=eslint-config-airbnb-base' - 'TEST=true ESLINT=6 PACKAGE=eslint-config-airbnb' + - 'TEST=true ESLINT=6 REACT_HOOKS=1.7 PACKAGE=eslint-config-airbnb' - 'TEST=true ESLINT=5 PACKAGE=eslint-config-airbnb-base' - 'TEST=true ESLINT=5 PACKAGE=eslint-config-airbnb' + - 'TEST=true ESLINT=5 REACT_HOOKS=1.7 PACKAGE=eslint-config-airbnb' matrix: fast_finish: true include: @@ -27,20 +30,28 @@ matrix: env: PREPUBLISH=true ESLINT=6 PACKAGE=eslint-config-airbnb-base - node_js: "lts/*" env: PREPUBLISH=true ESLINT=6 PACKAGE=eslint-config-airbnb + - node_js: "lts/*" + env: PREPUBLISH=true ESLINT=6 REACT_HOOKS=1.7 PACKAGE=eslint-config-airbnb - node_js: "lts/*" env: PREPUBLISH=true ESLINT=5 PACKAGE=eslint-config-airbnb-base - node_js: "lts/*" env: PREPUBLISH=true ESLINT=5 PACKAGE=eslint-config-airbnb + - node_js: "lts/*" + env: PREPUBLISH=true ESLINT=5 REACT_HOOKS=1.7 PACKAGE=eslint-config-airbnb - node_js: "lts/*" env: LINT=true - node_js: "7" env: TEST=true ESLINT=5 PACKAGE=eslint-config-airbnb-base - node_js: "7" env: TEST=true ESLINT=5 PACKAGE=eslint-config-airbnb + - node_js: "7" + env: TEST=true ESLINT=5 REACT_HOOKS=1.7 PACKAGE=eslint-config-airbnb - node_js: "6" env: TEST=true ESLINT=5 PACKAGE=eslint-config-airbnb-base - node_js: "6" env: TEST=true ESLINT=5 PACKAGE=eslint-config-airbnb + - node_js: "6" + env: TEST=true ESLINT=5 REACT_HOOKS=1.7 PACKAGE=eslint-config-airbnb exclude: allow_failures: - node_js: "11" diff --git a/README.md b/README.md index 73371e6b44..ed145f3f17 100644 --- a/README.md +++ b/README.md @@ -1590,6 +1590,7 @@ Other Style Guides const isJedi = getProp('jedi'); ``` + - [12.3](#es2016-properties--exponentiation-operator) Use exponentiation operator `**` when calculating exponentiations. eslint: [`no-restricted-properties`](https://eslint.org/docs/rules/no-restricted-properties). @@ -1703,6 +1704,7 @@ Other Style Guides return name; } ``` + - [13.5](#variables--no-chain-assignment) Don’t chain variable assignments. eslint: [`no-multi-assign`](https://eslint.org/docs/rules/no-multi-assign) diff --git a/linters/.markdownlint.json b/linters/.markdownlint.json index 594886042d..118b8a6ec6 100644 --- a/linters/.markdownlint.json +++ b/linters/.markdownlint.json @@ -26,7 +26,8 @@ "comment": "MD007: Unordered list indentation: 2 spaces.", "ul-indent": { - "indent": 2 + "indent": 2, + "start_indented": true }, "comment": "MD009: Disallow trailing spaces!", diff --git a/package.json b/package.json index 581c94f612..36b4e19fab 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "A mostly reasonable approach to JavaScript.", "scripts": { "preinstall": "npm run install:config && npm run install:config:base", + "postinstall": "rm -rf node_modules/markdownlint-cli/node_modules/markdownlint", "install:config": "cd packages/eslint-config-airbnb && npm prune && npm install", "install:config:base": "cd packages/eslint-config-airbnb-base && npm prune && npm install", "lint": "markdownlint --config linters/.markdownlint.json README.md */README.md", @@ -39,6 +40,7 @@ }, "homepage": "https://github.com/airbnb/javascript", "devDependencies": { - "markdownlint-cli": "^0.13.0" + "markdownlint": "^0.19.0", + "markdownlint-cli": "^0.21.0" } } diff --git a/packages/eslint-config-airbnb/package.json b/packages/eslint-config-airbnb/package.json index c58f98a902..74a699a34c 100644 --- a/packages/eslint-config-airbnb/package.json +++ b/packages/eslint-config-airbnb/package.json @@ -68,7 +68,7 @@ "eslint-plugin-import": "^2.20.1", "eslint-plugin-jsx-a11y": "^6.2.3", "eslint-plugin-react": "^7.18.3", - "eslint-plugin-react-hooks": "^1.7.0", + "eslint-plugin-react-hooks": "^2.0.0 || ^1.7.0", "in-publish": "^2.0.0", "react": ">= 0.13.0", "safe-publish-latest": "^1.1.4", @@ -79,7 +79,7 @@ "eslint-plugin-import": "^2.20.1", "eslint-plugin-jsx-a11y": "^6.2.3", "eslint-plugin-react": "^7.18.3", - "eslint-plugin-react-hooks": "^1.7.0" + "eslint-plugin-react-hooks": "^2.0.0 || ^1.7.0" }, "engines": { "node": ">= 6" diff --git a/packages/eslint-config-airbnb/rules/react.js b/packages/eslint-config-airbnb/rules/react.js index fc1a3a90a9..e712f0d77f 100644 --- a/packages/eslint-config-airbnb/rules/react.js +++ b/packages/eslint-config-airbnb/rules/react.js @@ -500,6 +500,35 @@ module.exports = { // Enforce that props are read-only // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-read-only-props.md 'react/prefer-read-only-props': 'off', + + // Prevent usage of `javascript:` URLs + // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-script-url.md + // TODO: enable, semver-major + 'react/jsx-no-script-url': ['off', [ + { + name: 'Link', + props: ['to'], + }, + ]], + + // Disallow unnecessary fragments + // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-useless-fragment.md + // TODO: enable, semver-major + 'react/jsx-no-useless-fragment': 'off', + + // Prevent adjacent inline elements not separated by whitespace + // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-adjacent-inline-elements.md + // TODO: enable? semver-major + 'react/no-adjacent-inline-elements': 'off', + + // Enforce a specific function type for function components + // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/function-component-definition.md + // TODO: enable! semver-minor, but do it in a major to be safe + // TODO: investigate if setting namedComponents to expression vs declaration is problematic + 'react/function-component-definition': ['off', { + namedComponents: 'function-expression', + unnamedComponents: 'function-expression', + }], }, settings: { diff --git a/react/README.md b/react/README.md index a17cdf7a5b..af8c13d720 100644 --- a/react/README.md +++ b/react/README.md @@ -111,6 +111,7 @@ This style guide is mostly based on the standards that are currently prevalent i // good import Footer from './Footer'; ``` + - **Higher-order Component Naming**: Use a composite of the higher-order component’s name and the passed-in component’s name as the `displayName` on the generated component. For example, the higher-order component `withFoo()`, when passed a component `Bar` should produce a component with a `displayName` of `withFoo(Bar)`. > Why? A component’s `displayName` may be used by developer tools or in error messages, and having a value that clearly expresses this relationship helps people understand what is happening.