diff --git a/packages/xarc-app-dev/src/config/eslint/.eslintrc-base b/packages/xarc-app-dev/src/config/eslint/.eslintrc-base index 509fa97d6..b6b0d0b60 100644 --- a/packages/xarc-app-dev/src/config/eslint/.eslintrc-base +++ b/packages/xarc-app-dev/src/config/eslint/.eslintrc-base @@ -1,3 +1,5 @@ --- extends: - "./js/base.js" +rules: + "func-style": ["off"] diff --git a/packages/xarc-app-dev/src/config/eslint/.eslintrc-mocha-test b/packages/xarc-app-dev/src/config/eslint/.eslintrc-mocha-test index 871ed7588..98dc3ab6e 100644 --- a/packages/xarc-app-dev/src/config/eslint/.eslintrc-mocha-test +++ b/packages/xarc-app-dev/src/config/eslint/.eslintrc-mocha-test @@ -13,3 +13,4 @@ rules: "max-statements": "off" "max-nested-callbacks": "off" "no-multi-spaces": "off" + "func-style": ["off"] diff --git a/packages/xarc-app-dev/src/config/eslint/.eslintrc-mocha-test-es6 b/packages/xarc-app-dev/src/config/eslint/.eslintrc-mocha-test-es6 index e1abc9fcf..d152cb0d0 100644 --- a/packages/xarc-app-dev/src/config/eslint/.eslintrc-mocha-test-es6 +++ b/packages/xarc-app-dev/src/config/eslint/.eslintrc-mocha-test-es6 @@ -13,3 +13,4 @@ rules: "max-nested-callbacks": "off" "prefer-arrow-callback": "off" "no-multi-spaces": "off" + "func-style": ["off"] diff --git a/packages/xarc-app-dev/src/config/eslint/.eslintrc-react b/packages/xarc-app-dev/src/config/eslint/.eslintrc-react index 738f58fd5..bbf0ba5d9 100644 --- a/packages/xarc-app-dev/src/config/eslint/.eslintrc-react +++ b/packages/xarc-app-dev/src/config/eslint/.eslintrc-react @@ -1,14 +1,18 @@ --- extends: - "./js/es6-react.js" + - "plugin:react/recommended" globals: window: false document: false ReactElement: false -plugins: [ - "flowtype" -] +env: + mocha: true +plugins: + - flowtype + - react rules: + "maxlen": "off" "react/jsx-boolean-value": "off" "react/jsx-closing-bracket-location": "off" "react/no-string-refs": "off" @@ -20,3 +24,21 @@ rules: "flowtype/define-flow-type": "warn" "flowtype/use-flow-type": "warn" "flowtype/require-valid-file-annotation": "error" + "func-style": ["off"] + + "react/no-render-return-value": "warn" + "react/display-name": "warn" +"settings": + "react": + "createClass": "createReactClass" + "pragma": "React" + "fragment": "Fragment" + "version": "detect" + "flowVersion": "0.53" + "propWrapperFunctions": + - "forbidExtraProps" + - {"property": "freeze", "object": "Object"} + - {"property": "myFavoriteWrapper"} + "linkComponents": + - "Hyperlink" + - {"name": "Link", "linkAttribute": "to"} diff --git a/packages/xarc-app-dev/src/config/eslint/.eslintrc-react-demo b/packages/xarc-app-dev/src/config/eslint/.eslintrc-react-demo index d5f1969d2..b630b00f9 100644 --- a/packages/xarc-app-dev/src/config/eslint/.eslintrc-react-demo +++ b/packages/xarc-app-dev/src/config/eslint/.eslintrc-react-demo @@ -15,3 +15,4 @@ rules: "flowtype/define-flow-type": "warn" "flowtype/use-flow-type": "warn" "flowtype/require-valid-file-annotation": "error" + "func-style": ["off"] diff --git a/packages/xarc-app-dev/src/config/eslint/.eslintrc-react-test b/packages/xarc-app-dev/src/config/eslint/.eslintrc-react-test index da09e408c..c618b0ace 100644 --- a/packages/xarc-app-dev/src/config/eslint/.eslintrc-react-test +++ b/packages/xarc-app-dev/src/config/eslint/.eslintrc-react-test @@ -7,12 +7,14 @@ globals: expect: false sinon: false Element: false -plugins: [ - "flowtype" -] +env: + mocha: true +plugins: + - flowtype + - react rules: "no-unused-expressions": "off" # for `chai.expect` - "max-len": ["error", 100, 2, {ignorePattern: "^\\s*(?:it|describe)\\(.*"}] + "max-len": "off" "max-statements": "off" "max-nested-callbacks": "off" "react/jsx-wrap-multilines": "warn" @@ -21,3 +23,6 @@ rules: "flowtype/define-flow-type": "warn" "flowtype/use-flow-type": "warn" "flowtype/require-valid-file-annotation": "error" + "func-style": ["off"] + "react/no-render-return-value": "warn" + "react/display-name": "warn" diff --git a/packages/xarc-app-dev/src/lib/dev-tasks.ts b/packages/xarc-app-dev/src/lib/dev-tasks.ts index dbdbd189a..6577cc2be 100644 --- a/packages/xarc-app-dev/src/lib/dev-tasks.ts +++ b/packages/xarc-app-dev/src/lib/dev-tasks.ts @@ -228,10 +228,23 @@ export function loadXarcDevTasks(xrun, userOptions: XarcOptions = {}) { { custom: [], archetype: [] } ); + const ignorePattern = options.ignorePatterns + ? options.ignorePatterns.map(p => `--ignore-pattern ${p}`) + : ""; + + const version = require("eslint/package.json") + .version.split(".") + .map(x => parseInt(x)); + const noUnmatchError = + version[0] > 6 && version[1] > 8 ? ` --no-error-on-unmatched-pattern` : ""; + const commands = [ - grouped.custom.length > 0 && `~$eslint${ext} ${grouped.custom.join(" ")}`, + grouped.custom.length > 0 && + `~$eslint${ext}${noUnmatchError} ${grouped.custom.join(" ")} ${ignorePattern}`, grouped.archetype.length > 0 && - `~$eslint${ext} --no-eslintrc -c ${options.config} ${grouped.archetype.join(" ")}` + `~$eslint${ext}${noUnmatchError} --no-eslintrc -c ${ + options.config + } ${grouped.archetype.join(" ")} ${ignorePattern}` ]; return Promise.resolve(commands.filter(x => x)); @@ -1040,50 +1053,78 @@ You only need to run this if you are doing something not through the xarc tasks. } if (xarcOptions.options.eslint) { + const hasTest = Fs.existsSync("test"); + const hasTestServer = Fs.existsSync("test/server"); + // legacy src/client and src/server only setup? + let isLegacySrc = false; + try { + const files = Fs.readdirSync("src").filter(x => !x.startsWith(".")); + isLegacySrc = files.sort().join("") === "clientserver"; + } catch (err) { + // + } + + const lintTasks = [ + "lint-client", + hasTest && "lint-client-test", + "lint-server", + hasTestServer && "lint-server-test" + ].filter(x => x); + Object.assign(tasks, { - lint: xclap2.concurrent( - "lint-client", - "lint-client-test", - "lint-server", - "lint-server-test" - ), + lint: xclap2.concurrent(...lintTasks), + "lint-client": { - desc: "Run eslint on client code in directories client and templates", + desc: + "Run eslint on code in src/client and templates with react rules (ignore src/server)", task: () => lint({ - ext: ".js,.jsx", + ext: ".js,.jsx,.ts,.tsx", config: eslintConfig(".eslintrc-react"), - targets: [AppMode.src.client, "templates"] - }) - }, - "lint-client-test": { - desc: "Run eslint on client test code in directory test/client", - task: () => - lint({ - ext: ".js,.jsx", - config: eslintConfig(".eslintrc-react-test"), - targets: ["test/client", ...jestTestDirectories.map(dir => `${dir}/client`)] + targets: isLegacySrc + ? [AppMode.src.client, "templates"] + : [AppMode.src.dir, "templates"], + ignorePatterns: [AppMode.src.server] }) }, + "lint-server": { - desc: "Run eslint on server code in directory server", + desc: "Run eslint on server code in src/server with node.js rules", task: () => lint({ + ext: ".js,.jsx,.ts,.tsx", config: eslintConfig(".eslintrc-node"), targets: [AppMode.src.server] }) - }, - "lint-server-test": { - desc: "Run eslint on server test code in directories test/server and test/func", + } + }); + + if (hasTest) { + tasks["lint-client-test"] = { + desc: "Run eslint on code in test with react rules (ignore test/server)", + task: () => + lint({ + ext: ".js,.jsx,.ts,.tsx", + config: eslintConfig(".eslintrc-react-test"), + targets: ["test", ...jestTestDirectories.map(dir => `${dir}`)], + ignorePatterns: ["test/server"] + }) + }; + } + + if (hasTestServer) { + tasks["lint-server-test"] = { + desc: "Run eslint on code in in test/server with node.js rules", task: () => lint({ + ext: ".js,.jsx,.ts,.tsx", config: process.env.SERVER_ES6 ? eslintConfig(".eslintrc-mocha-test-es6") : eslintConfig(".eslintrc-mocha-test"), - targets: ["test/server", "test/func"] + targets: ["test/server"] }) - } - }); + }; + } } else { const lintDisabled = () => { logger.info(`eslint tasks are disabled because @xarc/opt-eslint is not installed. diff --git a/samples/stylus-sample/src/client/components/demo-buttons.jsx b/samples/stylus-sample/src/client/components/demo-buttons.jsx index 855a57db3..73e4eb848 100644 --- a/samples/stylus-sample/src/client/components/demo-buttons.jsx +++ b/samples/stylus-sample/src/client/components/demo-buttons.jsx @@ -4,13 +4,15 @@ import React from "react"; * Demostrates a simple pure functional component */ -export const DemoButtons = () => +export const DemoButtons = () => (
demo CSS modules with buttons from skeleton
- Anchor button + + Anchor button + @@ -23,4 +25,5 @@ export const DemoButtons = () =>
-
; + +); diff --git a/samples/stylus-sample/test/client/components/home.spec.jsx b/samples/stylus-sample/test/client/components/home.spec.jsx index 61c8102f1..5b13c3061 100644 --- a/samples/stylus-sample/test/client/components/home.spec.jsx +++ b/samples/stylus-sample/test/client/components/home.spec.jsx @@ -25,7 +25,13 @@ describe("Home", () => { const store = createStore(rootReducer, initialState); - component = ReactDOM.render(, container); + // eslint-disable-next-line react/no-render-return-value + component = ReactDOM.render( + + + , + container + ); expect(component).to.not.be.false; }); diff --git a/samples/universal-react-node/package.json b/samples/universal-react-node/package.json index 4c2839539..40202cc3d 100644 --- a/samples/universal-react-node/package.json +++ b/samples/universal-react-node/package.json @@ -56,11 +56,8 @@ }, "devDependencies": { "@xarc/app-dev": "^7.0.5", - "redux-devtools": "^3.3.1", - "redux-devtools-dock-monitor": "^1.1.1", - "redux-devtools-log-monitor": "^1.0.11", + "@xarc/opt-eslint": "^1.0.0", "electrode-archetype-opt-critical-css": "^1.0.3", - "electrode-archetype-opt-eslint": "^1.0.3", "electrode-archetype-opt-flow": "^1.0.2", "electrode-archetype-opt-jest": "^24.0.0", "electrode-archetype-opt-karma": "^2.0.6", @@ -71,7 +68,10 @@ "electrode-archetype-opt-pwa": "^1.0.6", "electrode-archetype-opt-sinon": "^1.0.3", "electrode-archetype-opt-stylus": "^1.0.2", - "electrode-archetype-opt-typescript": "^1.0.3" + "electrode-archetype-opt-typescript": "^1.0.3", + "redux-devtools": "^3.3.1", + "redux-devtools-dock-monitor": "^1.1.1", + "redux-devtools-log-monitor": "^1.0.11" }, "fyn": { "dependencies": { @@ -81,7 +81,8 @@ "react-vendor-dll": "../react-vendor-dll" }, "devDependencies": { - "@xarc/app-dev": "../../packages/xarc-app-dev" + "@xarc/app-dev": "../../packages/xarc-app-dev", + "@xarc/opt-eslint": "../../packages/xarc-opt-eslint" } }, "optionalDependencies": {} diff --git a/samples/universal-react-node/src/client/components/above-the-fold.jsx b/samples/universal-react-node/src/client/components/above-the-fold.jsx index de9a44cb1..6470817a1 100644 --- a/samples/universal-react-node/src/client/components/above-the-fold.jsx +++ b/samples/universal-react-node/src/client/components/above-the-fold.jsx @@ -30,6 +30,7 @@ export class AboveFold extends React.Component { Read more about this module and see our live demo @@ -53,8 +54,8 @@ export class AboveFold extends React.Component { and it always will be rendered on server side.

- To verify, use your browser's view source to see the original HTML of this page and see - this being part of the SSR content + To verify, use your browser's view source to see the original HTML of this page and + see this being part of the SSR content

You should see this fill up your browser screen to push content below the browser view @@ -70,7 +71,7 @@ export class AboveFold extends React.Component { {this.props.skip ? (

- In the page source you should NOT see any more HTML after this except a few empty{" "} + In the page source you should NOT see any more HTML after this except a few empty divs
) : ( @@ -92,7 +93,7 @@ export class AboveFold extends React.Component { }} >

- This content block is wrapped inside the AboveTheFoldOnlyServerRender{" "} + This content block is wrapped inside the AboveTheFoldOnlyServerRender component, with the skip prop set to {`${this.props.skip}`}.

diff --git a/samples/universal-react-node/src/client/components/home.tsx b/samples/universal-react-node/src/client/components/home.tsx index 056387020..bfb371d18 100644 --- a/samples/universal-react-node/src/client/components/home.tsx +++ b/samples/universal-react-node/src/client/components/home.tsx @@ -4,7 +4,7 @@ import electrodeLogo from "../images/electrode.svg"; import Notifications from "react-notify-toast"; type HomeProps = { - data: string + data: string; }; /* eslint-disable max-len */ @@ -40,14 +40,14 @@ export class Home extends Component {
  • - Above the Fold Render with skip=true - increase your App's performance by using a skip - prop + Above the Fold Render with skip=true - increase your App's performance by using a + skip prop
  • - Above the Fold Render with skip=false - increase your App's performance by using a - skip prop + Above the Fold Render with skip=false - increase your App's performance by using + a skip prop
  • diff --git a/samples/universal-react-node/src/client/devtools/devtools.dev.js b/samples/universal-react-node/src/client/devtools/devtools.dev.js index 4868488ac..dfd3cfe96 100644 --- a/samples/universal-react-node/src/client/devtools/devtools.dev.js +++ b/samples/universal-react-node/src/client/devtools/devtools.dev.js @@ -1,5 +1,7 @@ // @flow +/* eslint-disable react/display-name */ + import React from "react"; import { createDevTools } from "redux-devtools"; import LogMonitor from "redux-devtools-log-monitor"; diff --git a/samples/universal-react-node/src/server/routes/init-top.jsx b/samples/universal-react-node/src/server/routes/init-top.jsx index 401653066..435cb6672 100644 --- a/samples/universal-react-node/src/server/routes/init-top.jsx +++ b/samples/universal-react-node/src/server/routes/init-top.jsx @@ -1,3 +1,5 @@ +/* eslint-disable no-magic-numbers */ + import reducer from "../../client/reducers"; import Promise from "bluebird"; diff --git a/samples/universal-react-node/src/server/routes/ssrcachingsimpletype.jsx b/samples/universal-react-node/src/server/routes/ssrcachingsimpletype.jsx index d57872524..a33fcab4b 100644 --- a/samples/universal-react-node/src/server/routes/ssrcachingsimpletype.jsx +++ b/samples/universal-react-node/src/server/routes/ssrcachingsimpletype.jsx @@ -1,4 +1,4 @@ -export default function(options) { +export default function(/*options*/) { return { reducer: {}, initialState: { diff --git a/samples/universal-react-node/src/server/routes/ssrcachingtemplatetype.jsx b/samples/universal-react-node/src/server/routes/ssrcachingtemplatetype.jsx index d57872524..a33fcab4b 100644 --- a/samples/universal-react-node/src/server/routes/ssrcachingtemplatetype.jsx +++ b/samples/universal-react-node/src/server/routes/ssrcachingtemplatetype.jsx @@ -1,4 +1,4 @@ -export default function(options) { +export default function(/*options*/) { return { reducer: {}, initialState: { diff --git a/samples/universal-react-node/src/server/routes/todo-app.jsx b/samples/universal-react-node/src/server/routes/todo-app.jsx index c44aaf685..fae5a89b9 100644 --- a/samples/universal-react-node/src/server/routes/todo-app.jsx +++ b/samples/universal-react-node/src/server/routes/todo-app.jsx @@ -4,7 +4,7 @@ import path from "path"; const readFile = Promise.promisify(fs.readFile); -export default async function(options) { +export default async function(/*options*/) { let storage; try { diff --git a/samples/universal-react-node/test/client/components/home.spec.jsx b/samples/universal-react-node/test/client/components/home.spec.jsx index 56dc241b0..a00918271 100644 --- a/samples/universal-react-node/test/client/components/home.spec.jsx +++ b/samples/universal-react-node/test/client/components/home.spec.jsx @@ -15,7 +15,7 @@ describe("Home", () => { }); it("has expected content with deep render", () => { - component = ReactDOM.render(, container); + component = ReactDOM.render(, container); // eslint-disable-line react/no-render-return-value expect(component).to.not.be.false; });