From 7584016c12a57fbe7e0a9b76c64e1a437df3b6b5 Mon Sep 17 00:00:00 2001 From: SimeonC <1085899+SimeonC@users.noreply.github.com> Date: Thu, 30 Nov 2023 10:09:40 +0900 Subject: [PATCH 1/3] fix: allow `disabled` as a boolean variable name exception Commonly we have boolean props that want to be called `disabled` but according to rules we need to make these `isDisabled` or similar. This is a common conventional name and thus should be allowed. --- packages/eslint-config/src/rules/namingConvention.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/eslint-config/src/rules/namingConvention.ts b/packages/eslint-config/src/rules/namingConvention.ts index 943c4e5e..596c0e94 100644 --- a/packages/eslint-config/src/rules/namingConvention.ts +++ b/packages/eslint-config/src/rules/namingConvention.ts @@ -54,7 +54,9 @@ export const namingRules: Linter.RulesRecord = { 'will', 'allow', ]; - return `^(${booleanValues.join('|')})|^[a-z]+(${booleanValues + return `^(disabled$|${booleanValues.join( + '|', + )})|^[a-z]+(${booleanValues .map((name) => `${name[0].toUpperCase()}${name.substring(1)}`) .join('|')})`; })(), From 3f07faa8d47012ad243f7914d7fdf31f7d7a98f4 Mon Sep 17 00:00:00 2001 From: SimeonC <1085899+SimeonC@users.noreply.github.com> Date: Thu, 30 Nov 2023 15:15:35 +0900 Subject: [PATCH 2/3] fix: eslint-config cypress and storybook definitions fixes --- packages/eslint-config/README.stories.mdx | 5 ++- packages/eslint-config/package.json | 5 +++ .../src/overrides/buildBaseTypescript.ts | 10 +---- .../eslint-config/src/overrides/storybook.ts | 4 ++ .../src/overrides/typescriptDefinitions.ts | 2 - packages/eslint-config/src/presets/basic.ts | 8 +--- packages/eslint-config/src/presets/cypress.ts | 44 +----------------- .../src/presets/cypressComponent.ts | 6 ++- .../src/presets/cypressInternal.ts | 45 +++++++++++++++++++ .../eslint-config/src/presets/storybook.ts | 17 +++++++ .../eslint-config/src/presets/typescript.ts | 2 - 11 files changed, 84 insertions(+), 64 deletions(-) create mode 100644 packages/eslint-config/src/presets/cypressInternal.ts create mode 100644 packages/eslint-config/src/presets/storybook.ts diff --git a/packages/eslint-config/README.stories.mdx b/packages/eslint-config/README.stories.mdx index 024bece4..e0799dc3 100644 --- a/packages/eslint-config/README.stories.mdx +++ b/packages/eslint-config/README.stories.mdx @@ -27,15 +27,16 @@ eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./ #### Specific Presets -- `@tablecheck/eslint-config/basic` - Rules for vanilla javascript only repositories. +- `@tablecheck/eslint-config/basic` - Rules for vanilla javascript only repositories. (Recommend using Typescript over this) - `@tablecheck/eslint-config/typescript` - Rules for vanilla typescript projects - `@tablecheck/eslint-config/react` - Rules for react javascript project - `@tablecheck/eslint-config/react-typescript` - Rules for react typescript project +- `@tablecheck/eslint-config/cypress` - Rules for Cypress projects in typescript The following cypress presets should be used with one of the above Specific Presets -- `@tablecheck/eslint-config/cypress` - Rules for Cypress projects (applies to all files) - `@tablecheck/eslint-config/cypress-component` - Use this when adding component testing to a project, it adds an override for `*.cypress.*` and `*.cy.*` files +- `@tablecheck/eslint-config/storybook` - This adds an override for story/stories files, use with typescript package For example, a react typescript project with cypress component testing should use the following; diff --git a/packages/eslint-config/package.json b/packages/eslint-config/package.json index d2a5cf44..d7b2dc80 100644 --- a/packages/eslint-config/package.json +++ b/packages/eslint-config/package.json @@ -44,6 +44,11 @@ "main": "./dist/presets/reactTs.js", "default": "./dist/presets/reactTs.js" }, + "./storybook": { + "types": "./dist/presets/storybook.d.ts", + "main": "./dist/presets/storybook.js", + "default": "./dist/presets/storybook.js" + }, "./package.json": "./package.json" }, "main": "./dist/index.js", diff --git a/packages/eslint-config/src/overrides/buildBaseTypescript.ts b/packages/eslint-config/src/overrides/buildBaseTypescript.ts index 9fbd5a96..24eebad6 100644 --- a/packages/eslint-config/src/overrides/buildBaseTypescript.ts +++ b/packages/eslint-config/src/overrides/buildBaseTypescript.ts @@ -42,18 +42,13 @@ export const baseTypescriptRules: Linter.RulesRecord = { '@tablecheck/prefer-shortest-import': 'error', }; -export function buildBaseTypescript< - T extends Linter.RulesRecord, - TForced extends Linter.RulesRecord, ->({ +export function buildBaseTypescript({ files, rules, - forcedRules, ...options }: { files: Linter.ConfigOverride['files']; rules: T; - forcedRules?: TForced; } & Omit< Linter.ConfigOverride, 'parser' | 'extends' | 'plugins' | 'settings' | 'rules' | 'files' @@ -86,9 +81,8 @@ export function buildBaseTypescript< }, }, rules: { - ...rules, ...baseTypescriptRules, - ...forcedRules, + ...rules, }, }; } diff --git a/packages/eslint-config/src/overrides/storybook.ts b/packages/eslint-config/src/overrides/storybook.ts index 3969f04d..c7e92c0a 100644 --- a/packages/eslint-config/src/overrides/storybook.ts +++ b/packages/eslint-config/src/overrides/storybook.ts @@ -14,6 +14,10 @@ export const storybookOverrides: Linter.ConfigOverride = { 'react-hooks/exhaustive-deps': 'off', 'react/function-component-definition': 'off', 'react/jsx-no-constructed-context-values': 'off', + 'react/jsx-props-no-spreading': 'off', + 'react/react-in-jsx-scope': 'off', + 'react/prop-types': 'off', + 'react/require-default-props': 'off', 'react-refresh/only-export-components': 'off', '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/naming-convention': 'off', diff --git a/packages/eslint-config/src/overrides/typescriptDefinitions.ts b/packages/eslint-config/src/overrides/typescriptDefinitions.ts index 3a396b3b..d6cc2861 100644 --- a/packages/eslint-config/src/overrides/typescriptDefinitions.ts +++ b/packages/eslint-config/src/overrides/typescriptDefinitions.ts @@ -12,8 +12,6 @@ export const typescriptDefinitionOverrides = buildBaseTypescript({ ...reactRules, ...promiseRules, ...emotionRules, - }, - forcedRules: { 'import/no-default-export': 'off', 'vars-on-top': 'off', 'no-unused-vars': 'off', diff --git a/packages/eslint-config/src/presets/basic.ts b/packages/eslint-config/src/presets/basic.ts index 40345d19..785948d6 100644 --- a/packages/eslint-config/src/presets/basic.ts +++ b/packages/eslint-config/src/presets/basic.ts @@ -2,7 +2,6 @@ import type { Linter } from 'eslint'; import { rootConfigsOverrides } from '../overrides/rootConfigs'; import { scriptsOverrides } from '../overrides/scripts'; -import { storybookOverrides } from '../overrides/storybook'; import { testOverrides } from '../overrides/tests'; import { emotionRules } from '../rules/emotion'; import { generalRules } from '../rules/general'; @@ -36,10 +35,5 @@ module.exports = { ...emotionRules, }, - overrides: [ - rootConfigsOverrides, - scriptsOverrides, - testOverrides, - storybookOverrides, - ], + overrides: [rootConfigsOverrides, scriptsOverrides, testOverrides], } satisfies Linter.Config; diff --git a/packages/eslint-config/src/presets/cypress.ts b/packages/eslint-config/src/presets/cypress.ts index 2afde0e2..57ee9f8f 100644 --- a/packages/eslint-config/src/presets/cypress.ts +++ b/packages/eslint-config/src/presets/cypress.ts @@ -1,43 +1,3 @@ -import type { Linter } from 'eslint'; +import { cypressPreset } from './cypressInternal'; -import { testOverrides as testRules } from '../overrides/tests'; -import { namingRules } from '../rules/namingConvention'; - -if (!process.env.NODE_ENV) { - // This check allows us to run linters inside IDE's - process.env.NODE_ENV = 'development'; -} - -const testOverrides = Object.keys(testRules.rules ?? {}).reduce( - (result, ruleKey) => ({ ...result, [ruleKey]: 'off' }), - {}, -); - -module.exports = { - env: { - 'cypress/globals': true, - }, - rules: { - ...testOverrides, - 'promise/catch-or-return': 'off', - 'promise/always-return': 'off', - 'import/no-import-module-exports': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-namespace': 'off', - '@typescript-eslint/naming-convention': ( - ['error'] as Linter.RuleLevelAndOptions - ).concat( - ( - namingRules[ - '@typescript-eslint/naming-convention' - ] as Linter.RuleLevelAndOptions - ).slice(1), - [ - { - selector: 'memberLike', - format: null, - }, - ], - ) as Linter.RuleLevelAndOptions, - }, -} satisfies Linter.Config; +module.exports = cypressPreset; diff --git a/packages/eslint-config/src/presets/cypressComponent.ts b/packages/eslint-config/src/presets/cypressComponent.ts index f9224a89..cd6bf9a5 100644 --- a/packages/eslint-config/src/presets/cypressComponent.ts +++ b/packages/eslint-config/src/presets/cypressComponent.ts @@ -1,15 +1,19 @@ import type { Linter } from 'eslint'; +import { cypressPreset } from './cypressInternal'; + if (!process.env.NODE_ENV) { // This check allows us to run linters inside IDE's process.env.NODE_ENV = 'development'; } +const { extends: extendPreset, ...config } = cypressPreset; + module.exports = { overrides: [ { files: ['**/cypress/**/*', '**/*.{cy,cypress}.{js,jsx,ts,tsx}'], - extends: ['@tablecheck/eslint-config/cypress'], + ...config, }, ], } satisfies Linter.Config; diff --git a/packages/eslint-config/src/presets/cypressInternal.ts b/packages/eslint-config/src/presets/cypressInternal.ts new file mode 100644 index 00000000..ced39bcf --- /dev/null +++ b/packages/eslint-config/src/presets/cypressInternal.ts @@ -0,0 +1,45 @@ +import type { Linter } from 'eslint'; + +import { testOverrides as testRules } from '../overrides/tests'; +import { namingRules } from '../rules/namingConvention'; + +if (!process.env.NODE_ENV) { + // This check allows us to run linters inside IDE's + process.env.NODE_ENV = 'development'; +} + +const testOverrides = Object.keys(testRules.rules ?? {}).reduce( + (result, ruleKey) => ({ ...result, [ruleKey]: 'off' }), + {}, +); + +export const cypressPreset = { + plugins: ['cypress'], + extends: ['@tablecheck/eslint-config/typescript'], + env: { + 'cypress/globals': true, + }, + rules: { + ...testOverrides, + 'promise/catch-or-return': 'off', + 'promise/always-return': 'off', + 'import/no-import-module-exports': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-namespace': 'off', + '@typescript-eslint/naming-convention': ( + ['error'] as Linter.RuleLevelAndOptions + ).concat( + ( + namingRules[ + '@typescript-eslint/naming-convention' + ] as Linter.RuleLevelAndOptions + ).slice(1), + [ + { + selector: 'memberLike', + format: null, + }, + ], + ) as Linter.RuleLevelAndOptions, + }, +} satisfies Linter.Config; diff --git a/packages/eslint-config/src/presets/storybook.ts b/packages/eslint-config/src/presets/storybook.ts new file mode 100644 index 00000000..e3623aa6 --- /dev/null +++ b/packages/eslint-config/src/presets/storybook.ts @@ -0,0 +1,17 @@ +import type { Linter } from 'eslint'; + +import { storybookOverrides } from '../overrides/storybook'; + +if (!process.env.NODE_ENV) { + // This check allows us to run linters inside IDE's + process.env.NODE_ENV = 'development'; +} + +module.exports = { + overrides: [ + { + extends: ['@tablecheck/eslint-config/typescript'], + ...storybookOverrides, + }, + ], +} satisfies Linter.Config; diff --git a/packages/eslint-config/src/presets/typescript.ts b/packages/eslint-config/src/presets/typescript.ts index fb5abafb..6e47a102 100644 --- a/packages/eslint-config/src/presets/typescript.ts +++ b/packages/eslint-config/src/presets/typescript.ts @@ -1,7 +1,6 @@ import type { Linter } from 'eslint'; import { buildBaseTypescript } from '../overrides/buildBaseTypescript'; -import { storybookOverrides } from '../overrides/storybook'; import { testOverrides } from '../overrides/tests'; import { emotionRules } from '../rules/emotion'; import { generalRules } from '../rules/general'; @@ -61,6 +60,5 @@ module.exports = { node: true, }, }), - buildBaseTypescript(storybookOverrides as never), ], } satisfies Linter.Config; From 0bd333b252209687ddd4f5217baac31c6a1ec231 Mon Sep 17 00:00:00 2001 From: SimeonC <1085899+SimeonC@users.noreply.github.com> Date: Fri, 1 Dec 2023 12:31:35 +0900 Subject: [PATCH 3/3] fix: naming-convention errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added some basic tests for current cases for naming-convention as it’s very complicated. --- packages/eslint-config/package.json | 3 --- packages/eslint-config/project.json | 20 +++++++++++++++++++ .../eslint-config/src/presets/typescript.ts | 2 +- .../src/rules/namingConvention.ts | 17 +++++++++++----- packages/eslint-config/tests/.eslintrc.cjs | 12 +++++++++++ .../tests/namingConvention.ts/variables.tsx | 13 ++++++++++++ packages/eslint-config/tests/tsconfig.json | 14 +++++++++++++ 7 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 packages/eslint-config/tests/.eslintrc.cjs create mode 100644 packages/eslint-config/tests/namingConvention.ts/variables.tsx create mode 100644 packages/eslint-config/tests/tsconfig.json diff --git a/packages/eslint-config/package.json b/packages/eslint-config/package.json index d7b2dc80..233ba94d 100644 --- a/packages/eslint-config/package.json +++ b/packages/eslint-config/package.json @@ -56,9 +56,6 @@ "files": [ "dist" ], - "scripts": { - "build": "tsc -p ./tsconfig.build.json" - }, "dependencies": { "@emotion/eslint-plugin": "^11.11.0", "@nx/eslint-plugin": "^16.5.0", diff --git a/packages/eslint-config/project.json b/packages/eslint-config/project.json index 5892eb03..53983673 100644 --- a/packages/eslint-config/project.json +++ b/packages/eslint-config/project.json @@ -4,6 +4,26 @@ "sourceRoot": "packages/eslint-config/src", "projectType": "library", "targets": { + "build": { + "executor": "nx:run-commands", + "options": { + "command": "tsc -p packages/eslint-config/tsconfig.build.json" + } + }, + "test": { + "executor": "@nx/linter:eslint", + "outputs": ["{options.outputFile}"], + "dependsOn": ["build"], + "options": { + "noEslintrc": true, + "eslintConfig": "packages/eslint-config/tests/.eslintrc.cjs", + "reportUnusedDisableDirectives": "error", + "lintFilePatterns": [ + "packages/eslint-config/tests/**/*.ts", + "packages/eslint-config/tests/**/*.tsx" + ] + } + }, "quality": { "executor": "@tablecheck/nx:quality", "outputs": ["{options.outputFile}"], diff --git a/packages/eslint-config/src/presets/typescript.ts b/packages/eslint-config/src/presets/typescript.ts index 6e47a102..6910c8e3 100644 --- a/packages/eslint-config/src/presets/typescript.ts +++ b/packages/eslint-config/src/presets/typescript.ts @@ -22,6 +22,7 @@ module.exports = { ...promiseRules, ...emotionRules, ...namingRules, + 'no-unused-vars': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off', }, }), @@ -30,7 +31,6 @@ module.exports = { rules: { 'import/no-default-export': 'off', 'vars-on-top': 'off', - 'no-unused-vars': 'off', '@typescript-eslint/no-unused-vars': 'off', '@typescript-eslint/no-empty-interface': 'warn', '@typescript-eslint/explicit-module-boundary-types': 'off', diff --git a/packages/eslint-config/src/rules/namingConvention.ts b/packages/eslint-config/src/rules/namingConvention.ts index 596c0e94..4c9dd012 100644 --- a/packages/eslint-config/src/rules/namingConvention.ts +++ b/packages/eslint-config/src/rules/namingConvention.ts @@ -1,16 +1,18 @@ import type { Linter } from 'eslint'; +const componentRegexpMatch = { + regex: '(?