Skip to content

Commit

Permalink
new rules (#157)
Browse files Browse the repository at this point in the history
* new rules

* ignore ts extensions for react

* chore(dependencies): updated changesets for modified dependencies

* comment quotes

* fixes for .md

* improve eslint-remote-tester.config

* fix lint extension for imports in code-blocks with react config

* chore(dependencies): updated changesets for modified dependencies

* fix

* try

* try2

* add `unicorn/no-negated-condition`

* 'react/hook-use-state'
'react/iframe-missing-sandbox'
'react/jsx-no-leaked-render'

restrict isNaN in favour of Number.isNaN

* add changeset

* remove jsx-no-leaked-render

* Update .changeset/hot-pigs-share.md

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
Dimitri POSTOLOV and github-actions[bot] authored Jan 30, 2023
1 parent 4dae9ea commit 3f7437f
Show file tree
Hide file tree
Showing 16 changed files with 562 additions and 186 deletions.
15 changes: 15 additions & 0 deletions .changeset/@theguild_eslint-config-157-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
"@theguild/eslint-config": patch
---
dependencies updates:
- Updated dependency [`@typescript-eslint/eslint-plugin@^5.48.1` ↗︎](https://www.npmjs.com/package/@typescript-eslint/eslint-plugin/v/5.48.1) (from `^5.45.1`, in `dependencies`)
- Updated dependency [`@typescript-eslint/parser@^5.48.1` ↗︎](https://www.npmjs.com/package/@typescript-eslint/parser/v/5.48.1) (from `^5.45.1`, in `dependencies`)
- Updated dependency [`eslint-config-prettier@^8.6.0` ↗︎](https://www.npmjs.com/package/eslint-config-prettier/v/8.6.0) (from `^8.5.0`, in `dependencies`)
- Updated dependency [`eslint-plugin-import@^2.27.0` ↗︎](https://www.npmjs.com/package/eslint-plugin-import/v/2.27.0) (from `^2.26.0`, in `dependencies`)
- Updated dependency [`eslint-plugin-jsonc@^2.6.0` ↗︎](https://www.npmjs.com/package/eslint-plugin-jsonc/v/2.6.0) (from `^2.5.0`, in `dependencies`)
- Updated dependency [`eslint-plugin-jsx-a11y@^6.7.0` ↗︎](https://www.npmjs.com/package/eslint-plugin-jsx-a11y/v/6.7.0) (from `^6.6.1`, in `dependencies`)
- Updated dependency [`eslint-plugin-n@^15.6.1` ↗︎](https://www.npmjs.com/package/eslint-plugin-n/v/15.6.1) (from `^15.6.0`, in `dependencies`)
- Updated dependency [`eslint-plugin-react@^7.32.0` ↗︎](https://www.npmjs.com/package/eslint-plugin-react/v/7.32.0) (from `^7.31.11`, in `dependencies`)
- Updated dependency [`eslint-plugin-unicorn@^45.0.2` ↗︎](https://www.npmjs.com/package/eslint-plugin-unicorn/v/45.0.2) (from `^45.0.1`, in `dependencies`)
- Updated dependency [`eslint-plugin-yml@^1.4.0` ↗︎](https://www.npmjs.com/package/eslint-plugin-yml/v/1.4.0) (from `^1.2.0`, in `dependencies`)
- Added dependency [`eslint-import-resolver-typescript@^3.5.3` ↗︎](https://www.npmjs.com/package/eslint-import-resolver-typescript/v/3.5.3) (to `dependencies`)
32 changes: 32 additions & 0 deletions .changeset/hot-pigs-share.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
'@theguild/eslint-config': minor
---

new rules:

- `yoda`

- `unicorn/prefer-export-from`

- `promise/no-multiple-resolved`

- `unicorn/prefer-logical-operator-over-ternary`

- `@typescript-eslint/no-unused-expressions`

- `unicorn/no-negated-condition`

react:

fix `import/extensions`

- 'react/prop-types': 'off'
- 'react/jsx-boolean-value': 'error'
- 'react/hook-use-state': 'error'
- 'react/iframe-missing-sandbox': 'error'

forbid:

- `process.browser`

- restrict `isNaN` in favour of `Number.isNaN`
5 changes: 5 additions & 0 deletions .changeset/tender-berries-camp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@theguild/prettier-config': patch
---

format svg with html parser
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pnpm-lock.yaml
eslint-remote-tester-results/*.md
52 changes: 48 additions & 4 deletions eslint-remote-tester.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ enum Repo {
Bob = 'kamilkisiela/bob',
DataLoader = 'graphql/dataloader',
LiveQuery = 'n1ru4l/graphql-live-query',
GraphiQL = 'graphql/graphiql',
GraphQLOrg = 'graphql/graphql.github.io',
GraphQLHTTP = 'graphql/graphql-http',
GraphQLWS = 'enisdenjo/graphql-ws',
GraphQLSSE = 'enisdenjo/graphql-sse',
// Other
Nextra = 'shuding/nextra',
Satori = 'vercel/satori',
NextJS = 'vercel/next.js',
}

const overrideConfig: Config['eslintrc'] = {
Expand Down Expand Up @@ -66,7 +75,28 @@ const overrideConfig: Config['eslintrc'] = {
'promise',
],
rules: {
'no-unreachable-loop': 'error',
'no-restricted-syntax': [
'error',
{
// ❌ process.browser
selector:
'ExpressionStatement[expression.object.name=process][expression.property.name=browser]',
message: '`process.browser` is deprecated, use `!!globalThis.window`',
},
{
// ❌ let { foo: {bar} } = baz
selector:
'VariableDeclarator[init.type!=AwaitExpression] > ObjectPattern[properties.length=1][properties.0.value.type=ObjectPattern]',
message: 'Do not use nested destructuring.',
},
{
// ❌ useMemo(…, [])
selector:
'CallExpression[callee.name=useMemo][arguments.1.type=ArrayExpression][arguments.1.elements.length=0]',
message:
"`useMemo` with an empty dependency array can't provide a stable reference, use `useRef` instead.",
},
],
},
};

Expand All @@ -81,9 +111,23 @@ const config: Config = {
'packages/load/tests/loaders/schema/test-files/error.ts', // tools
'action/index.js', // inspector
'.yarn/releases/yarn-berry.cjs', // shield
'.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs', // swift
'.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs', // swift
'.yarn/plugins/@yarnpkg/plugin-typescript.cjs', // swift
// swift
'.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs',
'.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs',
'.yarn/plugins/@yarnpkg/plugin-typescript.cjs',
// next.js
'packages/next/src/compiled/babel/bundle.js',
'packages/next/src/compiled/mini-css-extract-plugin/loader.js',
'packages/next/src/compiled/undici/index.js',
'packages/next/src/compiled/ws/index.js',
'test/development/basic/hmr/components/parse-error.js',
// dataloader
'flow-typed/npm/jest_v24.x.x.js',
'src/__tests__/abuse.test.js',
'src/__tests__/browser.test.js',
'src/__tests__/dataloader.test.js',
'src/__tests__/oldbrowser.test.js',
'src/__tests__/unhandled.test.js',
].join('|')})`,
rulesUnderTesting: () => true,
};
Expand Down
21 changes: 11 additions & 10 deletions packages/eslint-config/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,21 @@
},
"dependencies": {
"@rushstack/eslint-patch": "^1.2.0",
"@typescript-eslint/eslint-plugin": "^5.45.1",
"@typescript-eslint/parser": "^5.45.1",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsonc": "^2.5.0",
"eslint-plugin-jsx-a11y": "^6.6.1",
"@typescript-eslint/eslint-plugin": "^5.48.1",
"@typescript-eslint/parser": "^5.48.1",
"eslint-config-prettier": "^8.6.0",
"eslint-import-resolver-typescript": "^3.5.3",
"eslint-plugin-import": "^2.27.0",
"eslint-plugin-jsonc": "^2.6.0",
"eslint-plugin-jsx-a11y": "^6.7.0",
"eslint-plugin-mdx": "^2.0.5",
"eslint-plugin-n": "^15.6.0",
"eslint-plugin-n": "^15.6.1",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-react": "^7.31.11",
"eslint-plugin-react": "^7.32.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-sonarjs": "^0.18.0",
"eslint-plugin-unicorn": "^45.0.1",
"eslint-plugin-yml": "^1.2.0"
"eslint-plugin-unicorn": "^45.0.2",
"eslint-plugin-yml": "^1.4.0"
},
"publishConfig": {
"access": "public"
Expand Down
19 changes: 17 additions & 2 deletions packages/eslint-config/src/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const RESTRICTED_MODULES = [
{ name: 'lodash/identity.js', message: 'Use `(value) => value` instead.' },
];

/** @type {import('eslint').Linter.Config} */
module.exports = {
parser: '@typescript-eslint/parser',
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
Expand Down Expand Up @@ -56,6 +57,7 @@ module.exports = {
'import/extensions': ['error', 'ignorePackages'], // Bob when bundling requires to have `.js` extension
'import/no-default-export': 'error',
'import/prefer-default-export': 'off', // disable opposite of 'import/no-default-export'
'unicorn/filename-case': 'error',

'@typescript-eslint/no-unused-vars': [
'error',
Expand Down Expand Up @@ -94,18 +96,31 @@ module.exports = {

// Disallow specified global variables
// https://eslint.org/docs/latest/rules/no-restricted-globals
'no-restricted-globals': ['error', 'stop'],
'no-restricted-globals': [
'error',
'stop',
{ name: 'isNaN', message: 'Use Number.isNaN instead' },
],

'@typescript-eslint/no-explicit-any': 'error',
'prefer-const': ['error', { destructuring: 'all' }],

'import/no-duplicates': 'error',
'import/newline-after-import': 'error',
'import/newline-after-import': 'off', // prettified by prettier-plugin-sort-imports

'prefer-object-has-own': 'error',
'logical-assignment-operators': ['error', 'always', { enforceForIfStatements: true }],
'@typescript-eslint/prefer-optional-chain': 'error',

yoda: 'error',
'unicorn/prefer-export-from': ['error', { ignoreUsedVariables: true }],
'promise/no-multiple-resolved': 'error',
'unicorn/prefer-logical-operator-over-ternary': 'error',
'no-unused-expressions': 'off',
'@typescript-eslint/no-unused-expressions': 'error',
'no-negated-condition': 'off',
'unicorn/no-negated-condition': 'error', // has autofix

// 'prefer-destructuring': [ // TODO: Rediscuss later
// 'error',
// {
Expand Down
14 changes: 14 additions & 0 deletions packages/eslint-config/src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@ const RESTRICTED_SYNTAX = [
message:
'Prefer `!!…` over `Boolean(…)` because TypeScript infers a narrow literal boolean `type: true` instead of `type: boolean`.',
},
{
// ❌ process.browser
selector:
'ExpressionStatement[expression.object.name=process][expression.property.name=browser]',
message: '`process.browser` is deprecated, use `!!globalThis.window`',
},
// {
// // ❌ let { foo: { bar } } = baz
// // ✅ let { bar } = baz.foo
// // ✅ let { foo: { bar } } = await baz
// selector:
// 'VariableDeclarator[init.type!=AwaitExpression] > ObjectPattern[properties.length=1][properties.0.value.type=ObjectPattern]',
// message: 'Do not use nested destructuring.',
// },
];

const REACT_RESTRICTED_SYNTAX = [
Expand Down
9 changes: 1 addition & 8 deletions packages/eslint-config/src/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { CODE_FILE, CODE_BLOCK } = require('./constants.js');
const { CODE_FILE } = require('./constants.js');

require('@rushstack/eslint-patch/modern-module-resolution');

Expand All @@ -13,13 +13,6 @@ module.exports = {
files: CODE_FILE,
extends: './base',
},
{
files: CODE_FILE,
excludedFiles: CODE_BLOCK,
rules: {
'unicorn/filename-case': 'error',
},
},
{
files: ['*.c{j,t}s'],
env: { node: true },
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-config/src/json.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const { CODE_BLOCK } = require('./constants.js');

const JSONC_FILES = ['tsconfig.json', 'tsconfig.eslint.json', 'turbo.json', '.vscode/launch.json'];

/** @type {import('eslint').Linter.Config} */
module.exports = {
overrides: [
{
Expand Down
5 changes: 4 additions & 1 deletion packages/eslint-config/src/mdx.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const { CODE_BLOCK } = require('./constants.js');

/** @type {import('eslint').Linter.Config} */
module.exports = {
overrides: [
{
Expand All @@ -16,6 +17,7 @@ module.exports = {
'mdx/remark': 'error',
'import/no-default-export': 'off',
'@typescript-eslint/prefer-optional-chain': 'off', // throws "parserOptions.project" error
'react/jsx-filename-extension': 'off', // fixes JSX not allowed in files with extension '.mdx'
},
settings: {
'mdx/code-blocks': true,
Expand All @@ -27,7 +29,8 @@ module.exports = {
CODE_BLOCK,
'.changeset/*.md',
'CHANGELOG.md',
'.github/workflows/pull_request_template.md',
'.github/**/PULL_REQUEST_TEMPLATE.md',
'.github/ISSUE_TEMPLATE/bug_report.md',
'SECURITY.md',
'CODE_OF_CONDUCT.md',
'README.md',
Expand Down
20 changes: 16 additions & 4 deletions packages/eslint-config/src/react-base.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const RESTRICTED_IMPORTS = [
},
];

/** @type {import('eslint').Linter.Config} */
module.exports = {
settings: {
react: {
Expand All @@ -26,8 +27,10 @@ module.exports = {
plugins: ['import', 'unicorn'],
extends: [
'plugin:react/recommended',
'plugin:react/jsx-runtime',
'plugin:react-hooks/recommended',
'plugin:jsx-a11y/recommended',
'plugin:import/typescript',
'prettier',
],
rules: {
Expand All @@ -38,17 +41,26 @@ module.exports = {
// Disallows specific imports
// https://typescript-eslint.io/rules/no-restricted-imports
'@typescript-eslint/no-restricted-imports': ['error', ...RESTRICTED_IMPORTS],
'react/react-in-jsx-scope': 'off', // import of React is no longer required starting from react@17
// Disallow extra closing tags for components without children
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/self-closing-comp.md
'react/self-closing-comp': 'error',
'react/jsx-no-useless-fragment': 'error',
'react/no-unused-state': 'error',
'react/no-unescaped-entities': 'off', // annoying
'react/jsx-no-undef': 'off', // same as `no-undef`

'import/extensions': ['error', 'never'],
'unicorn/filename-case': ['error', { case: 'kebabCase', ignore: [/^\[\w+]\.tsx?$/] }],
'import/extensions': ['error', 'ignorePackages', { tsx: 'never', ts: 'never' }],
'no-restricted-syntax': ['error', ...REACT_RESTRICTED_SYNTAX],
// Disallow file extensions that may contain JSX
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-filename-extension.md
'react/jsx-filename-extension': ['error', { extensions: ['.tsx', '.jsx'], allow: 'as-needed' }],
'unicorn/filename-case': ['error', { case: 'kebabCase', ignore: [/^\[\w+]\.tsx?$/] }],
'react/prop-types': 'off',
'react/jsx-boolean-value': 'error',
'react/hook-use-state': 'error',
'react/iframe-missing-sandbox': 'error',

// TODO: add in base config
'prefer-destructuring': ['error', { VariableDeclarator: { object: true } }],
quotes: ['error', 'single', { avoidEscape: true }], // Matches Prettier, but also replaces backticks
},
};
13 changes: 4 additions & 9 deletions packages/eslint-config/src/react.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
const { CODE_FILE } = require('./constants.js');

/** @type {import('eslint').Linter.Config} */
module.exports = {
ignorePatterns: ['next-env.d.ts'],
overrides: [
{
files: '*.{,c,m}{j,t}s{,x}',
files: CODE_FILE,
extends: './react-base',
rules: {
// Disallow file extensions that may contain JSX
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-filename-extension.md
'react/jsx-filename-extension': [
'error',
{ extensions: ['.tsx', '.jsx'], allow: 'as-needed' },
],
},
},
{
files: [
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-config/src/yml.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const { CODE_BLOCK } = require('./constants.js');

/** @type {import('eslint').Linter.Config} */
module.exports = {
ignorePatterns: ['pnpm-lock.yaml'],
overrides: [
Expand Down
12 changes: 9 additions & 3 deletions packages/prettier-config/index.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ module.exports = {
trailingComma: 'none',
},
},
{
files: '*.svg',
options: {
parser: 'html',
},
},
],
plugins: [
// for prettifying shellscript, Dockerfile, properties, gitignore, dotenv
Expand All @@ -37,13 +43,13 @@ module.exports = {
'<THIRD_PARTY_MODULES>',
// Things that start with `@` or digit or underscore.
'^(@|\\d|_)',
// Anything that starts with a dot, or multiple dots, and doesnt have the "other files" extensions.
// Anything that starts with a dot, or multiple dots, and doesn't have the "other files" extensions.
'^(?=\\.+)(.(?!\\.(graphql|css|png|svg|jpe?g|webp|avif|wasm|mp4|webm)))+$',
// Other files with extensions.
'^.+\\.(graphql|css|png|svg|jpe?g|webp|avif|wasm|mp4|webm)$',
],
importOrderSeparation: false, // import order groups wont be separated by a new line
importOrderSeparation: false, // import order groups won't be separated by a new line
importOrderSortSpecifiers: true, // sorts the import specifiers alphabetically
importOrderCaseInsensitive: true, // case insensitive sorting
importOrderCaseInsensitive: true, // case-insensitive sorting
importOrderParserPlugins: ['typescript', 'jsx', 'decorators-legacy'],
};
Loading

0 comments on commit 3f7437f

Please sign in to comment.