fc52e02787
Spinning out from #37151 and my draft PR #52845, this enables the two basic recommended rulesets from [typescript-eslint](https://typescript-eslint.io) for the Next.js monorepo source code: * [`plugin:@typescript-eslint/recommended`](https://typescript-eslint.io/linting/configs#recommended): Our base recommended rules that detect common bugs or _(non-stylistic)_ TypeScript bad practices * [`plugin:@typescript-eslint/stylistic`](https://typescript-eslint.io/linting/configs#stylistic): Our base starting stylistic recommended for keeping codebases visually consistent and avoiding out-of-practice visual constructs The process I used is pretty standard (see https://github.com/typescript-eslint/typescript-eslint/issues/6760 for other repos it was done on): 1. Enable those base recommended presets 2. Remove any rule settings that are now redundant 3. Reconfigure any rule whose default settings didn't seem to make sense for this codebase 4. Add a `// Todo: ...` comment, and under it, add a disable for any rule that immediately reported a lot of complaints Note that this only enables the presets internally. It doesn't impact what end-users of published packages such as Next.js or `create-next-app` experience. That's a separate task in #52845. I also didn't fix any existing warning from the `canary` branch. Would you like me to do that? My preference would be a separate PR to get it in more quickly. Any code changes are commented inline. --------- Co-authored-by: Steven <steven@ceriously.com>
367 lines
11 KiB
JSON
367 lines
11 KiB
JSON
{
|
|
"root": true,
|
|
"parser": "@babel/eslint-parser",
|
|
"plugins": ["react", "react-hooks", "jest", "import", "jsdoc"],
|
|
"env": {
|
|
"browser": true,
|
|
"commonjs": true,
|
|
"es6": true,
|
|
"node": true
|
|
},
|
|
"parserOptions": {
|
|
"requireConfigFile": false,
|
|
"sourceType": "module",
|
|
"ecmaFeatures": {
|
|
"jsx": true
|
|
},
|
|
"babelOptions": {
|
|
"presets": ["next/babel"],
|
|
"caller": {
|
|
// Eslint supports top level await when a parser for it is included. We enable the parser by default for Babel.
|
|
"supportsTopLevelAwait": true
|
|
}
|
|
}
|
|
},
|
|
"settings": {
|
|
"react": {
|
|
"version": "detect"
|
|
},
|
|
"import/internal-regex": "^next/"
|
|
},
|
|
"overrides": [
|
|
{
|
|
"files": ["test/**/*.js", "test/**/*.ts", "**/*.test.ts"],
|
|
"extends": ["plugin:jest/recommended"],
|
|
"rules": {
|
|
"jest/expect-expect": "off",
|
|
"jest/no-disabled-tests": "off",
|
|
"jest/no-conditional-expect": "off",
|
|
"jest/valid-title": "off",
|
|
"jest/no-interpolation-in-snapshots": "off",
|
|
"jest/no-export": "off"
|
|
}
|
|
},
|
|
{ "files": ["**/__tests__/**"], "env": { "jest": true } },
|
|
{
|
|
"extends": [
|
|
"plugin:@typescript-eslint/recommended",
|
|
"plugin:@typescript-eslint/stylistic"
|
|
],
|
|
"files": ["**/*.ts", "**/*.tsx"],
|
|
"parser": "@typescript-eslint/parser",
|
|
"parserOptions": {
|
|
"sourceType": "module",
|
|
"warnOnUnsupportedTypeScriptVersion": false
|
|
},
|
|
"plugins": ["@typescript-eslint"],
|
|
"rules": {
|
|
// Todo: investigate, for each of these rules, whether we want them.
|
|
"@typescript-eslint/array-type": "off",
|
|
"@typescript-eslint/ban-ts-comment": "off",
|
|
"@typescript-eslint/ban-tslint-comment": "off",
|
|
"@typescript-eslint/ban-types": "off",
|
|
"@typescript-eslint/class-literal-property-style": "off",
|
|
"@typescript-eslint/consistent-generic-constructors": "off",
|
|
"@typescript-eslint/consistent-indexed-object-style": "off",
|
|
"@typescript-eslint/consistent-type-definitions": "off",
|
|
"@typescript-eslint/no-empty-function": "off",
|
|
"@typescript-eslint/no-namespace": "off",
|
|
"@typescript-eslint/no-shadow": "off",
|
|
"@typescript-eslint/no-empty-interface": "off",
|
|
"@typescript-eslint/no-explicit-any": "off",
|
|
"@typescript-eslint/no-inferrable-types": "off",
|
|
"@typescript-eslint/no-var-requires": "off",
|
|
"@typescript-eslint/prefer-for-of": "off",
|
|
"@typescript-eslint/prefer-function-type": "off",
|
|
"@typescript-eslint/no-this-alias": "off",
|
|
"@typescript-eslint/triple-slash-reference": "off",
|
|
"no-var": "off",
|
|
"prefer-const": "off",
|
|
"prefer-rest-params": "off",
|
|
"prefer-spread": "off",
|
|
|
|
// These off- or differently-configured rules work well for us.
|
|
"no-unused-expressions": "off",
|
|
"@typescript-eslint/no-unused-expressions": [
|
|
"error",
|
|
{
|
|
"allowShortCircuit": true,
|
|
"allowTernary": true,
|
|
"allowTaggedTemplates": true
|
|
}
|
|
],
|
|
"no-unused-vars": "off",
|
|
"@typescript-eslint/no-unused-vars": [
|
|
"warn",
|
|
{
|
|
"args": "none",
|
|
"ignoreRestSiblings": true
|
|
}
|
|
],
|
|
"no-use-before-define": "off",
|
|
"@typescript-eslint/no-use-before-define": [
|
|
"warn",
|
|
{
|
|
"functions": true,
|
|
"classes": true,
|
|
"variables": true,
|
|
"enums": true,
|
|
"typedefs": true
|
|
}
|
|
],
|
|
"no-useless-constructor": "off",
|
|
"@typescript-eslint/no-useless-constructor": "warn",
|
|
"@typescript-eslint/prefer-literal-enum-member": "error"
|
|
},
|
|
"overrides": [
|
|
{
|
|
"files": ["packages/**"],
|
|
"rules": {
|
|
"jsdoc/no-types": "error",
|
|
"jsdoc/no-undefined-types": "error"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"files": [
|
|
"test/**/*",
|
|
"examples/**/*",
|
|
"packages/create-next-app/templates/**/*"
|
|
],
|
|
"rules": { "react/react-in-jsx-scope": "off" }
|
|
},
|
|
{
|
|
"files": ["examples/**/*"],
|
|
"rules": {
|
|
"@typescript-eslint/no-use-before-define": [
|
|
"error",
|
|
{
|
|
"functions": true,
|
|
"classes": true,
|
|
"variables": true,
|
|
"enums": true,
|
|
"typedefs": true
|
|
}
|
|
],
|
|
"import/no-anonymous-default-export": [
|
|
"error",
|
|
{
|
|
// React components:
|
|
"allowArrowFunction": false,
|
|
"allowAnonymousClass": false,
|
|
"allowAnonymousFunction": false,
|
|
|
|
// Non-React stuff:
|
|
"allowArray": true,
|
|
"allowCallExpression": true,
|
|
"allowLiteral": true,
|
|
"allowObject": true
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"files": ["packages/**"],
|
|
"excludedFiles": ["packages/next/taskfile.js"],
|
|
"rules": {
|
|
"no-shadow": ["warn", { "builtinGlobals": false }],
|
|
"import/no-extraneous-dependencies": [
|
|
"error",
|
|
{ "devDependencies": false }
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"files": ["packages/**/*.tsx", "packages/**/*.ts"],
|
|
"rules": {
|
|
// Note: you must disable the base rule as it can report incorrect errors
|
|
"no-shadow": "off",
|
|
"@typescript-eslint/no-shadow": ["warn", { "builtinGlobals": false }],
|
|
"@typescript-eslint/no-unused-vars": [
|
|
"warn",
|
|
{
|
|
"args": "all",
|
|
"argsIgnorePattern": "^_",
|
|
"ignoreRestSiblings": true
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"files": [
|
|
"packages/eslint-plugin-next/**/*.js",
|
|
"test/unit/eslint-plugin-next/**/*.test.ts"
|
|
],
|
|
"extends": ["plugin:eslint-plugin/recommended"],
|
|
"parserOptions": {
|
|
"sourceType": "script"
|
|
},
|
|
"rules": {
|
|
"eslint-plugin/prefer-replace-text": "error",
|
|
"eslint-plugin/report-message-format": [
|
|
"error",
|
|
".+\\. See: https://nextjs.org/docs/messages/[a-z\\-]+$"
|
|
],
|
|
"eslint-plugin/require-meta-docs-description": [
|
|
"error",
|
|
{
|
|
"pattern": ".+"
|
|
}
|
|
],
|
|
"eslint-plugin/require-meta-docs-url": "error"
|
|
}
|
|
}
|
|
],
|
|
"rules": {
|
|
"array-callback-return": "warn",
|
|
"default-case": ["warn", { "commentPattern": "^no default$" }],
|
|
"dot-location": ["warn", "property"],
|
|
"eqeqeq": ["warn", "smart"],
|
|
"new-parens": "warn",
|
|
"no-array-constructor": "warn",
|
|
"no-caller": "warn",
|
|
"no-cond-assign": ["warn", "except-parens"],
|
|
"no-const-assign": "warn",
|
|
"no-control-regex": "warn",
|
|
"no-delete-var": "warn",
|
|
"no-dupe-args": "warn",
|
|
"no-dupe-class-members": "warn",
|
|
"no-dupe-keys": "warn",
|
|
"no-duplicate-case": "warn",
|
|
"no-empty-character-class": "warn",
|
|
"no-empty-pattern": "warn",
|
|
"no-eval": "warn",
|
|
"no-ex-assign": "warn",
|
|
"no-extend-native": "warn",
|
|
"no-extra-bind": "warn",
|
|
"no-extra-label": "warn",
|
|
"no-fallthrough": "warn",
|
|
"no-func-assign": "warn",
|
|
"no-implied-eval": "warn",
|
|
"no-invalid-regexp": "warn",
|
|
"no-iterator": "warn",
|
|
"no-label-var": "warn",
|
|
"no-labels": ["warn", { "allowLoop": true, "allowSwitch": false }],
|
|
"no-lone-blocks": "warn",
|
|
"no-loop-func": "warn",
|
|
"no-mixed-operators": [
|
|
"warn",
|
|
{
|
|
"groups": [
|
|
["&", "|", "^", "~", "<<", ">>", ">>>"],
|
|
["==", "!=", "===", "!==", ">", ">=", "<", "<="],
|
|
["&&", "||"],
|
|
["in", "instanceof"]
|
|
],
|
|
"allowSamePrecedence": false
|
|
}
|
|
],
|
|
"no-multi-str": "warn",
|
|
"no-native-reassign": "warn",
|
|
"no-negated-in-lhs": "warn",
|
|
"no-new-func": "warn",
|
|
"no-new-object": "warn",
|
|
"no-new-symbol": "warn",
|
|
"no-new-wrappers": "warn",
|
|
"no-obj-calls": "warn",
|
|
"no-octal": "warn",
|
|
"no-octal-escape": "warn",
|
|
"no-regex-spaces": "warn",
|
|
"no-restricted-syntax": [
|
|
"warn",
|
|
"WithStatement",
|
|
{
|
|
"message": "substr() is deprecated, use slice() or substring() instead",
|
|
"selector": "MemberExpression > Identifier[name='substr']"
|
|
}
|
|
],
|
|
"no-script-url": "warn",
|
|
"no-self-assign": "warn",
|
|
"no-self-compare": "warn",
|
|
"no-sequences": "warn",
|
|
"no-shadow-restricted-names": "warn",
|
|
"no-sparse-arrays": "warn",
|
|
"no-template-curly-in-string": "error",
|
|
"no-this-before-super": "warn",
|
|
"no-throw-literal": "warn",
|
|
"no-undef": "error",
|
|
"no-unexpected-multiline": "warn",
|
|
"no-unreachable": "warn",
|
|
"no-unused-expressions": [
|
|
"error",
|
|
{
|
|
"allowShortCircuit": true,
|
|
"allowTernary": true,
|
|
"allowTaggedTemplates": true
|
|
}
|
|
],
|
|
"no-unused-labels": "warn",
|
|
"no-unused-vars": [
|
|
"warn",
|
|
{
|
|
"args": "none",
|
|
"ignoreRestSiblings": true
|
|
}
|
|
],
|
|
"no-use-before-define": [
|
|
"warn",
|
|
{
|
|
"functions": false,
|
|
"classes": false,
|
|
"variables": false
|
|
}
|
|
],
|
|
"no-useless-computed-key": "warn",
|
|
"no-useless-concat": "warn",
|
|
"no-useless-constructor": "warn",
|
|
"no-useless-escape": "warn",
|
|
"no-useless-rename": [
|
|
"warn",
|
|
{
|
|
"ignoreDestructuring": false,
|
|
"ignoreImport": false,
|
|
"ignoreExport": false
|
|
}
|
|
],
|
|
"no-with": "warn",
|
|
"no-whitespace-before-property": "warn",
|
|
"react-hooks/exhaustive-deps": "warn",
|
|
"require-yield": "warn",
|
|
"rest-spread-spacing": ["warn", "never"],
|
|
"strict": ["warn", "never"],
|
|
"unicode-bom": ["warn", "never"],
|
|
"use-isnan": "warn",
|
|
"valid-typeof": "warn",
|
|
"getter-return": "warn",
|
|
"react/forbid-foreign-prop-types": ["warn", { "allowInPropTypes": true }],
|
|
"react/jsx-no-comment-textnodes": "warn",
|
|
"react/jsx-no-duplicate-props": "warn",
|
|
"react/jsx-no-target-blank": "warn",
|
|
"react/jsx-no-undef": "error",
|
|
"react/jsx-pascal-case": [
|
|
"warn",
|
|
{
|
|
"allowAllCaps": true,
|
|
"ignore": []
|
|
}
|
|
],
|
|
"react/jsx-uses-react": "warn",
|
|
"react/jsx-uses-vars": "warn",
|
|
"react/no-danger-with-children": "warn",
|
|
"react/no-deprecated": "warn",
|
|
"react/no-direct-mutation-state": "warn",
|
|
"react/no-is-mounted": "warn",
|
|
"react/no-typos": "error",
|
|
"react/react-in-jsx-scope": "error",
|
|
"react/require-render-return": "error",
|
|
"react/style-prop-object": "warn",
|
|
"react-hooks/rules-of-hooks": "error",
|
|
// "@typescript-eslint/non-nullable-type-assertion-style": "warn",
|
|
"@typescript-eslint/prefer-as-const": "warn",
|
|
"@typescript-eslint/no-redeclare": [
|
|
"warn",
|
|
{ "builtinGlobals": false, "ignoreDeclarationMerge": true }
|
|
]
|
|
}
|
|
}
|