diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000000..583ce5e958 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,44 @@ +{ + "root": true, + "plugins": ["@typescript-eslint", "react-hooks", "jest"], + "extends": [ + "airbnb", + "plugin:@typescript-eslint/recommended", + "plugin:jest/recommended", + "prettier/@typescript-eslint" + ], + "env": { + "browser": true + }, + "settings": { + "import/resolver": { + "typescript": {} + } + }, + "rules": { + "react-hooks/rules-of-hooks": "error", + "react-hooks/exhaustive-deps": "warn" + }, + "overrides": [ + { + "files": ["**/*.ts", "**/*.tsx"], + "parser": "@typescript-eslint/parser", + "rules": { + "react/jsx-filename-extension": "off", + "camelcase": "off", + "@typescript-eslint/camelcase": ["error", { "properties": "never" }], + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": "error", + "@typescript-eslint/indent": ["error", 2] + } + }, + + { + "files": ["**/*.js"], + "parser": "@typescript-eslint/parser", + "rules": { + "@typescript-eslint/no-var-requires": "off" + } + } + ] +} diff --git a/.gitignore b/.gitignore index 9de55a7b46..4613a28ff3 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ package-lock.json # Build directory /public .DS_Store +build .env .firebase/* diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 5159a26f3b..0000000000 --- a/.prettierrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "printWidth": 80, - "tabWidth": 2, - "useTabs": false, - "semi": true, - "singleQuote": true, - "jsxSingleQuote": false, - "trailingComma": "es5", - "bracketSpacing": true, - "jsxBracketSameLine": false, - "arrowParens": "avoid" -} diff --git a/gatsby-config.js b/gatsby-config.js index ba837c76f5..cff415ac38 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -1,4 +1,5 @@ if (process.env.ENVIROMENT !== 'production') { +// eslint-disable-next-line global-require require('dotenv').config(); } @@ -17,50 +18,53 @@ module.exports = { 'gatsby-plugin-catch-links', 'gatsby-plugin-react-helmet', { - resolve: `gatsby-plugin-canonical-urls`, + resolve: 'gatsby-plugin-canonical-urls', options: { siteUrl: config.siteUrl, }, }, - `gatsby-plugin-sharp`, + 'gatsby-plugin-sharp', { - resolve: `gatsby-source-filesystem`, + resolve: 'gatsby-source-filesystem', options: { - name: `learn`, + name: 'learn', path: `${__dirname}/src/documentation/`, - include: [`**/*.md`], // ignore files starting with a dot + include: ['**/*.md'], // ignore files starting with a dot }, }, + { - resolve: `gatsby-plugin-manifest`, + resolve: 'gatsby-plugin-manifest', options: { name: config.title, + /* eslint-disable @typescript-eslint/camelcase */ short_name: config.title, start_url: '/', background_color: config.color, theme_color: config.color, + /* eslint-disable @typescript-eslint/camelcase */ display: config.display, icon: config.icon, }, }, 'gatsby-plugin-offline', - `gatsby-plugin-typescript`, + 'gatsby-plugin-typescript', { resolve: 'gatsby-transformer-remark', options: { plugins: [ { - resolve: `gatsby-remark-autolink-headers`, + resolve: 'gatsby-remark-autolink-headers', options: { - offsetY: `125`, - icon: ``, - className: `autolink-headers`, + offsetY: '125', + icon: '', + className: 'autolink-headers', maintainCase: false, removeAccents: true, }, }, { - resolve: `gatsby-remark-prismjs`, + resolve: 'gatsby-remark-prismjs', options: { classPrefix: 'language-', inlineCodeMarker: null, @@ -70,7 +74,7 @@ module.exports = { }, }, { - resolve: `gatsby-remark-images`, + resolve: 'gatsby-remark-images', options: { maxWidth: 590, }, @@ -79,7 +83,7 @@ module.exports = { }, }, { - resolve: `gatsby-plugin-sitemap`, + resolve: 'gatsby-plugin-sitemap', options: { query: `{ site { @@ -106,28 +110,23 @@ module.exports = { } }`, serialize: ({ site, allSitePage, allMarkdownRemark }) => { - let pages = []; - allSitePage.edges.map(edge => { - pages.push({ + const sitePages = allSitePage.edges.map(edge => ({ url: site.siteMetadata.siteUrlNoSlash + edge.node.path, - changefreq: `daily`, + changefreq: 'daily', priority: 0.7, - }); - }); - allMarkdownRemark.edges.map(edge => { - pages.push({ + })); + const markdownRemark = allMarkdownRemark.edges.map(edge => ({ url: `${site.siteMetadata.siteUrlNoSlash}/${edge.node.fields.slug}`, - changefreq: `daily`, + changefreq: 'daily', priority: 0.7, - }); - }); + })); - return pages; + return sitePages.concat(markdownRemark); }, }, }, { - resolve: `gatsby-plugin-emotion`, + resolve: 'gatsby-plugin-emotion', }, ], }; diff --git a/gatsby-node.js b/gatsby-node.js index a841e63ed8..473f6e41c5 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -1,8 +1,10 @@ -const createSlug = require('./src/util/createSlug'); +/* eslint-disable @typescript-eslint/no-var-requires */ +// Use in this file CommonJS syntax see https://www.gatsbyjs.org/docs/migrating-from-v1-to-v2/#convert-to-either-pure-commonjs-or-pure-es6 const path = require('path'); +const createSlug = require('./src/util/createSlug'); exports.createPages = ({ graphql, actions }) => { - const { createPage, createRedirect, createNodeField } = actions; + const { createPage } = actions; return new Promise((resolve, reject) => { const docTemplate = path.resolve('./src/templates/learn.tsx'); @@ -54,9 +56,10 @@ exports.createPages = ({ graphql, actions }) => { } } } - ` - ).then(result => { + `, + ).then((result) => { if (result.errors) { + // eslint-disable-next-line no-console console.log(result.errors); reject(result.errors); } @@ -65,7 +68,7 @@ exports.createPages = ({ graphql, actions }) => { const docPages = []; edges.forEach(({ node }, index) => { const { - fields: { slug, authors }, + fields: { slug }, frontmatter: { title, section }, parent: { relativePath }, } = node; @@ -80,8 +83,7 @@ exports.createPages = ({ graphql, actions }) => { } let nextNodeData = null; - const nextNode = - index === edges.length - 1 ? undefined : edges[index + 1].node; + const nextNode = index === edges.length - 1 ? undefined : edges[index + 1].node; if (nextNode) { nextNodeData = { slug: nextNode.fields.slug, @@ -108,7 +110,7 @@ exports.createPages = ({ graphql, actions }) => { }); }); - docPages.forEach(page => { + docPages.forEach((page) => { createPage({ path: `/${page.slug}`, component: docTemplate, @@ -117,44 +119,45 @@ exports.createPages = ({ graphql, actions }) => { next: page.next, previous: page.previous, relativePath: page.relativePath, - navigationData: navigationData, + navigationData, }, }); - if (page.slug === 'introduction-to-nodejs') + if (page.slug === 'introduction-to-nodejs') { createPage({ - path: `/`, + path: '/', component: docTemplate, context: { slug: page.slug, next: page.next, previous: page.previous, relativePath: page.relativePath, - navigationData: navigationData, + navigationData, }, }); + } }); - }) + }), ); }); }; -exports.onCreateNode = ({ node, getNode, actions }) => { +exports.onCreateNode = ({ node, actions }) => { if (node.internal.type === 'MarkdownRemark') { const { createNodeField } = actions; const slug = createSlug(node.frontmatter.title); createNodeField({ node, - name: `slug`, + name: 'slug', value: slug, }); - let authors = node.frontmatter.authors; + let { authors } = node.frontmatter; if (authors) { authors = authors.split(','); createNodeField({ node, - name: `authors`, + name: 'authors', value: authors, }); } diff --git a/package.json b/package.json index ab6a3b5718..9a83d82184 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "dotenv": "^6.0.0", "emotion": "^10.0.7", "emotion-server": "^10.0.7", + "eslint-plugin-jest": "^22.17.0", "gatsby": "^2.13.13", "gatsby-plugin-canonical-urls": "^2.0.10", "gatsby-plugin-catch-links": "^2.0.9", @@ -31,7 +32,6 @@ "react-dom": "^16.8.0", "react-emotion": "^10.0.0", "react-helmet": "^5.2.0", - "tslint": "^5.11.0", "typescript": "^3.1.1" }, "keywords": [ @@ -43,14 +43,15 @@ "build": "gatsby build", "build-ci": "gatsby build --prefix-paths", "start": "gatsby develop", - "format": "prettier --write '**/*.{ts,tsx,js}'", + "format": "yarn lint:fix", "format-check": "prettier --check '**/*.{ts,tsx,js}'", "jest": "jest", "update-snapshot": "jest --updateSnapshot", - "test": "yarn format-check && yarn tslint && yarn jest", + "test": "yarn lint && yarn jest", "test-watch": "yarn jest --watch", "test-ci": "yarn test --coverage && codecov", - "tslint": "tslint --project ./tsconfig.json", + "lint": "eslint .", + "lint:fix": "eslint --fix .", "serve": "yarn build && clear && gatsby serve" }, "devDependencies": { @@ -60,16 +61,25 @@ "@commitlint/config-conventional": "^7.3.1", "@types/jest": "^24.0.5", "@types/react-test-renderer": "^16.8.1", + "@typescript-eslint/eslint-plugin": "^1.4.2", "babel-jest": "^24.1.0", "babel-preset-gatsby": "^0.1.7", "codecov": "^3.3.0", + "eslint": "^5.14.1", + "eslint-config-airbnb": "^17.1.0", + "eslint-config-prettier": "^4.1.0", + "eslint-import-resolver-typescript": "^1.1.1", + "eslint-plugin-import": "^2.16.0", + "eslint-plugin-jsx-a11y": "^6.2.1", + "eslint-plugin-prettier": "^3.0.1", + "eslint-plugin-react": "^7.12.4", + "eslint-plugin-react-hooks": "^1.4.0", "husky": "^1.3.1", "identity-obj-proxy": "^3.0.0", "jest": "^24.1.0", "prettier": "^1.16.4", "react-test-renderer": "^16.8.2", - "tslint-config-prettier": "^1.15.0", - "tslint-react": "^3.6.0" + "typescript": "~3.2.1" }, "repository": { "type": "git", @@ -103,7 +113,7 @@ "husky": { "hooks": { "commit-msg": "commitlint --edit $HUSKY_GIT_PARAMS", - "pre-push": "yarn format-check && yarn tslint" + "pre-push": "yarn lint" } } } diff --git a/src/components/article.tsx b/src/components/article.tsx index d160200819..98685194ae 100644 --- a/src/components/article.tsx +++ b/src/components/article.tsx @@ -5,7 +5,7 @@ import EditLink from './edit-link'; import Pagination from './pagination'; import TOC from './toc'; -type Props = { +interface Props { title: string; html: string; tableOfContents: string; @@ -13,7 +13,7 @@ type Props = { relativePath: string; next?: PaginationInfo; previous?: PaginationInfo; -}; +} const Article = ({ title, @@ -23,7 +23,7 @@ const Article = ({ next, relativePath, authors, -}: Props) => ( +}: Props): JSX.Element => (

{title}

diff --git a/src/components/edit-link.tsx b/src/components/edit-link.tsx index c2fa597a8d..7955a901c2 100644 --- a/src/components/edit-link.tsx +++ b/src/components/edit-link.tsx @@ -30,11 +30,11 @@ const icon: SerializedStyles = css` vertical-align: middle; `; -type Props = { +interface Props { relativePath?: string; -}; +} -const EditLink = ({ relativePath }: Props) => { +const EditLink = ({ relativePath }: Props): JSX.Element | null => { if (!relativePath) { return null; } diff --git a/src/components/header.tsx b/src/components/header.tsx index 73625643b8..04b0116961 100644 --- a/src/components/header.tsx +++ b/src/components/header.tsx @@ -14,7 +14,7 @@ const ulStyles: SerializedStyles = css` list-style: none; `; -const Header = () => ( +const Header = (): JSX.Element => (