mirror of
https://github.com/coder/coder.git
synced 2025-07-10 23:53:15 +00:00
chore: Add linter for typescript code (#45)
- Add and configure `eslint` - Add to build pipeline - Fix lint failures
This commit is contained in:
122
.eslintrc.yaml
Normal file
122
.eslintrc.yaml
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
---
|
||||||
|
env:
|
||||||
|
browser: true
|
||||||
|
commonjs: true
|
||||||
|
es6: true
|
||||||
|
jest: true
|
||||||
|
node: true
|
||||||
|
extends:
|
||||||
|
- eslint:recommended
|
||||||
|
- plugin:@typescript-eslint/recommended
|
||||||
|
- plugin:import/recommended
|
||||||
|
- plugin:import/typescript
|
||||||
|
- plugin:react/recommended
|
||||||
|
- plugin:jsx-a11y/strict
|
||||||
|
- plugin:compat/recommended
|
||||||
|
- prettier
|
||||||
|
parser: "@typescript-eslint/parser"
|
||||||
|
parserOptions:
|
||||||
|
ecmaVersion: 2018
|
||||||
|
project:
|
||||||
|
- "./tsconfig.json"
|
||||||
|
- "./site/tsconfig.json"
|
||||||
|
sourceType: module
|
||||||
|
ecmaFeatures:
|
||||||
|
jsx: true
|
||||||
|
tsconfigRootDir: "./"
|
||||||
|
plugins:
|
||||||
|
- "@typescript-eslint"
|
||||||
|
- import
|
||||||
|
- react-hooks
|
||||||
|
- jest
|
||||||
|
- no-storage
|
||||||
|
root: true
|
||||||
|
rules:
|
||||||
|
"@typescript-eslint/brace-style":
|
||||||
|
["error", "1tbs", { "allowSingleLine": false }]
|
||||||
|
"@typescript-eslint/camelcase": "off"
|
||||||
|
"@typescript-eslint/explicit-function-return-type": "off"
|
||||||
|
"@typescript-eslint/explicit-module-boundary-types": "error"
|
||||||
|
"@typescript-eslint/method-signature-style": ["error", "property"]
|
||||||
|
"@typescript-eslint/no-invalid-void-type": error
|
||||||
|
# We're disabling the `no-namespace` rule to use a pattern of defining an interface,
|
||||||
|
# and then defining functions that operate on that data via namespace. This is helpful for
|
||||||
|
# dealing with immutable objects. This is a common pattern that shows up in some other
|
||||||
|
# large TypeScript projects, like VSCode.
|
||||||
|
# More details: https://github.com/coder/m/pull/9720#discussion_r697609528
|
||||||
|
"@typescript-eslint/no-namespace": "off"
|
||||||
|
"@typescript-eslint/no-unnecessary-boolean-literal-compare": error
|
||||||
|
"@typescript-eslint/no-unnecessary-condition": warn
|
||||||
|
"@typescript-eslint/no-unnecessary-type-assertion": warn
|
||||||
|
"@typescript-eslint/no-unused-vars":
|
||||||
|
- error
|
||||||
|
- argsIgnorePattern: "^_"
|
||||||
|
varsIgnorePattern: "^_"
|
||||||
|
"@typescript-eslint/no-use-before-define": "off"
|
||||||
|
"@typescript-eslint/object-curly-spacing": ["error", "always"]
|
||||||
|
"@typescript-eslint/triple-slash-reference": "off"
|
||||||
|
"brace-style": "off"
|
||||||
|
"curly": ["error", "all"]
|
||||||
|
eqeqeq: error
|
||||||
|
import/default: "off"
|
||||||
|
import/namespace: "off"
|
||||||
|
import/newline-after-import:
|
||||||
|
- error
|
||||||
|
- count: 1
|
||||||
|
import/no-named-as-default: "off"
|
||||||
|
import/no-named-as-default-member: "off"
|
||||||
|
import/prefer-default-export: "off"
|
||||||
|
jest/no-focused-tests: "error"
|
||||||
|
jsx-a11y/label-has-for: "off"
|
||||||
|
jsx-a11y/no-autofocus: "off"
|
||||||
|
no-console:
|
||||||
|
- warn
|
||||||
|
- allow:
|
||||||
|
- warn
|
||||||
|
- error
|
||||||
|
- info
|
||||||
|
- debug
|
||||||
|
no-dupe-class-members: "off"
|
||||||
|
no-restricted-imports:
|
||||||
|
- error
|
||||||
|
- paths:
|
||||||
|
- name: "@material-ui/core"
|
||||||
|
message:
|
||||||
|
"Use path imports to avoid pulling in unused modules. See:
|
||||||
|
https://material-ui.com/guides/minimizing-bundle-size/"
|
||||||
|
- name: "@material-ui/icons"
|
||||||
|
message:
|
||||||
|
"Use path imports to avoid pulling in unused modules. See:
|
||||||
|
https://material-ui.com/guides/minimizing-bundle-size/"
|
||||||
|
- name: "@material-ui/styles"
|
||||||
|
message:
|
||||||
|
"Use path imports to avoid pulling in unused modules. See:
|
||||||
|
https://material-ui.com/guides/minimizing-bundle-size/"
|
||||||
|
- name: "@material-ui/core/Tooltip"
|
||||||
|
message: "Use the custom Tooltip on componens/Tooltip"
|
||||||
|
no-storage/no-browser-storage: error
|
||||||
|
no-unused-vars: "off"
|
||||||
|
"object-curly-spacing": "off"
|
||||||
|
react-hooks/exhaustive-deps: warn
|
||||||
|
react-hooks/rules-of-hooks: error
|
||||||
|
react/jsx-no-script-url:
|
||||||
|
- error
|
||||||
|
- - name: Link
|
||||||
|
props:
|
||||||
|
- to
|
||||||
|
- name: Button
|
||||||
|
props:
|
||||||
|
- href
|
||||||
|
- name: IconButton
|
||||||
|
props:
|
||||||
|
- href
|
||||||
|
react/prop-types: "off"
|
||||||
|
react/jsx-boolean-value: ["error", "never"]
|
||||||
|
react/jsx-curly-brace-presence:
|
||||||
|
- error
|
||||||
|
- children: ignore
|
||||||
|
settings:
|
||||||
|
react:
|
||||||
|
version: detect
|
||||||
|
import/resolver:
|
||||||
|
typescript: {}
|
22
.github/workflows/coder.yaml
vendored
22
.github/workflows/coder.yaml
vendored
@ -38,6 +38,28 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
|
|
||||||
|
style-lint-typescript:
|
||||||
|
name: "style/lint/typescript"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Cache Node
|
||||||
|
id: cache-node
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
**/node_modules
|
||||||
|
.eslintcache
|
||||||
|
key: js-${{ runner.os }}-test-${{ hashFiles('**/yarn.lock') }}
|
||||||
|
|
||||||
|
- name: Install node_modules
|
||||||
|
run: yarn install
|
||||||
|
|
||||||
|
- name: "yarn lint"
|
||||||
|
run: yarn lint
|
||||||
|
|
||||||
gen:
|
gen:
|
||||||
name: "style/gen"
|
name: "style/gen"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
13
jest-runner.eslint.config.js
Normal file
13
jest-runner.eslint.config.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Toggle eslint --fix by specifying the `FIX` env.
|
||||||
|
const fix = !!process.env.FIX
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
cliOptions: {
|
||||||
|
ext: [".js", ".ts", ".tsx"],
|
||||||
|
ignorePath: ".eslintignore",
|
||||||
|
cache: false,
|
||||||
|
fix,
|
||||||
|
resolvePluginsRelativeTo: ".",
|
||||||
|
maxWarnings: 0,
|
||||||
|
},
|
||||||
|
}
|
@ -13,6 +13,12 @@ module.exports = {
|
|||||||
testPathIgnorePatterns: ["/node_modules/", "/__tests__/fakes"],
|
testPathIgnorePatterns: ["/node_modules/", "/__tests__/fakes"],
|
||||||
moduleDirectories: ["node_modules", "<rootDir>"],
|
moduleDirectories: ["node_modules", "<rootDir>"],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
displayName: "lint",
|
||||||
|
runner: "jest-runner-eslint",
|
||||||
|
testMatch: ["<rootDir>/site/**/*.js", "<rootDir>/site/**/*.ts", "<rootDir>/site/**/*.tsx"],
|
||||||
|
testPathIgnorePatterns: ["/.next/", "/out/"],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
collectCoverageFrom: [
|
collectCoverageFrom: [
|
||||||
"<rootDir>/site/**/*.js",
|
"<rootDir>/site/**/*.js",
|
||||||
|
16
package.json
16
package.json
@ -10,6 +10,8 @@
|
|||||||
"export": "next export site",
|
"export": "next export site",
|
||||||
"format:check": "prettier --check '**/*.{css,html,js,json,jsx,md,ts,tsx,yaml,yml}'",
|
"format:check": "prettier --check '**/*.{css,html,js,json,jsx,md,ts,tsx,yaml,yml}'",
|
||||||
"format:write": "prettier --write '**/*.{css,html,js,json,jsx,md,ts,tsx,yaml,yml}' && sql-formatter -l postgresql ./database/query.sql -o ./database/query.sql",
|
"format:write": "prettier --write '**/*.{css,html,js,json,jsx,md,ts,tsx,yaml,yml}' && sql-formatter -l postgresql ./database/query.sql -o ./database/query.sql",
|
||||||
|
"lint": "jest --selectProjects lint",
|
||||||
|
"lint:fix": "FIX=true yarn lint",
|
||||||
"test": "jest --selectProjects test",
|
"test": "jest --selectProjects test",
|
||||||
"test:coverage": "jest --selectProjects test --collectCoverage"
|
"test:coverage": "jest --selectProjects test --collectCoverage"
|
||||||
},
|
},
|
||||||
@ -24,9 +26,23 @@
|
|||||||
"@types/react": "17.0.38",
|
"@types/react": "17.0.38",
|
||||||
"@types/react-dom": "17.0.11",
|
"@types/react-dom": "17.0.11",
|
||||||
"@types/superagent": "4.1.14",
|
"@types/superagent": "4.1.14",
|
||||||
|
"@typescript-eslint/eslint-plugin": "4.33.0",
|
||||||
|
"@typescript-eslint/parser": "4.33.0",
|
||||||
|
"eslint": "7.32.0",
|
||||||
|
"eslint-config-prettier": "8.3.0",
|
||||||
|
"eslint-import-resolver-alias": "1.1.2",
|
||||||
|
"eslint-import-resolver-typescript": "2.5.0",
|
||||||
|
"eslint-plugin-compat": "4.0.1",
|
||||||
|
"eslint-plugin-import": "2.25.4",
|
||||||
|
"eslint-plugin-jest": "25.7.0",
|
||||||
|
"eslint-plugin-jsx-a11y": "6.5.1",
|
||||||
|
"eslint-plugin-no-storage": "1.0.2",
|
||||||
|
"eslint-plugin-react": "7.28.0",
|
||||||
|
"eslint-plugin-react-hooks": "4.3.0",
|
||||||
"express": "4.17.2",
|
"express": "4.17.2",
|
||||||
"http-proxy-middleware": "2.0.1",
|
"http-proxy-middleware": "2.0.1",
|
||||||
"jest": "27.4.7",
|
"jest": "27.4.7",
|
||||||
|
"jest-runner-eslint": "1.0.0",
|
||||||
"next": "12.0.7",
|
"next": "12.0.7",
|
||||||
"prettier": "2.5.1",
|
"prettier": "2.5.1",
|
||||||
"react": "17.0.2",
|
"react": "17.0.2",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { screen } from "@testing-library/react"
|
import { screen } from "@testing-library/react"
|
||||||
import { render } from "../../test_helpers"
|
import { render } from "../../test_helpers"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import { EmptyState, EmptyStateProps } from "./index"
|
import { EmptyState } from "./index"
|
||||||
|
|
||||||
describe("EmptyState", () => {
|
describe("EmptyState", () => {
|
||||||
it("renders (smoke test)", async () => {
|
it("renders (smoke test)", async () => {
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import { SvgIcon } from "@material-ui/core"
|
import SvgIcon from "@material-ui/core/SvgIcon"
|
||||||
import { render } from "./../../test_helpers"
|
import { render } from "./../../test_helpers"
|
||||||
|
|
||||||
import * as Icons from "./index"
|
import * as Icons from "./index"
|
||||||
|
|
||||||
const getAllIcons = (): [string, typeof SvgIcon][] => {
|
const getAllIcons = (): [string, typeof SvgIcon][] => {
|
||||||
let k: keyof typeof Icons
|
let k: keyof typeof Icons
|
||||||
let ret: [string, typeof SvgIcon][] = []
|
const ret: [string, typeof SvgIcon][] = []
|
||||||
for (k in Icons) {
|
for (k in Icons) {
|
||||||
ret.push([k, Icons[k]])
|
ret.push([k, Icons[k]])
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
|
import Button from "@material-ui/core/Button"
|
||||||
|
import List from "@material-ui/core/List"
|
||||||
|
import ListSubheader from "@material-ui/core/ListSubheader"
|
||||||
import { makeStyles } from "@material-ui/core/styles"
|
import { makeStyles } from "@material-ui/core/styles"
|
||||||
import { Button, List, ListSubheader } from "@material-ui/core"
|
|
||||||
|
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ module.exports = {
|
|||||||
// Allows us to import TS files from outside product/coder/site.
|
// Allows us to import TS files from outside product/coder/site.
|
||||||
externalDir: true,
|
externalDir: true,
|
||||||
},
|
},
|
||||||
webpack: (config, { dev, isServer, webpack }) => {
|
webpack: (config, { isServer, webpack }) => {
|
||||||
// Inject CODERD_HOST environment variable for clients
|
// Inject CODERD_HOST environment variable for clients
|
||||||
if (!isServer) {
|
if (!isServer) {
|
||||||
config.plugins.push(
|
config.plugins.push(
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
|
|
||||||
import CssBaseline from "@material-ui/core/CssBaseline"
|
import CssBaseline from "@material-ui/core/CssBaseline"
|
||||||
|
import { makeStyles } from "@material-ui/core/styles"
|
||||||
import ThemeProvider from "@material-ui/styles/ThemeProvider"
|
import ThemeProvider from "@material-ui/styles/ThemeProvider"
|
||||||
|
|
||||||
import { dark } from "../theme"
|
import { dark } from "../theme"
|
||||||
import { AppProps } from "next/app"
|
import { AppProps } from "next/app"
|
||||||
import { makeStyles } from "@material-ui/core"
|
|
||||||
import { Navbar } from "../components/Navbar"
|
import { Navbar } from "../components/Navbar"
|
||||||
import { Footer } from "../components/Page"
|
import { Footer } from "../components/Page"
|
||||||
|
|
||||||
@ -64,7 +63,7 @@ const MyApp: React.FC<AppProps> = (appProps) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles(() => ({
|
||||||
root: {
|
root: {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import { makeStyles, Box, Paper } from "@material-ui/core"
|
import Box from "@material-ui/core/Box"
|
||||||
import { AddToQueue as AddWorkspaceIcon } from "@material-ui/icons"
|
import { makeStyles } from "@material-ui/core/styles"
|
||||||
|
import Paper from "@material-ui/core/Paper"
|
||||||
|
import AddWorkspaceIcon from "@material-ui/icons/AddToQueue"
|
||||||
|
|
||||||
import { EmptyState, SplitButton } from "../components"
|
import { EmptyState, SplitButton } from "../components"
|
||||||
|
|
||||||
|
@ -4,9 +4,6 @@ import { CustomPalette, darkPalette, lightPalette } from "./palettes"
|
|||||||
import { typography } from "./typography"
|
import { typography } from "./typography"
|
||||||
|
|
||||||
const makeTheme = (palette: CustomPalette) => {
|
const makeTheme = (palette: CustomPalette) => {
|
||||||
// Grab defaults to re-use in overrides
|
|
||||||
const { breakpoints } = createMuiTheme()
|
|
||||||
|
|
||||||
return createMuiTheme({
|
return createMuiTheme({
|
||||||
palette,
|
palette,
|
||||||
typography,
|
typography,
|
||||||
|
Reference in New Issue
Block a user