@shelf/eslint-config 6.2.1 → 6.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # @shelf/eslint-config ![](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)
1
+ # @shelf/eslint-config
2
2
 
3
3
  ## Style Guide
4
4
 
@@ -15,7 +15,7 @@ $ pnpm add --save-dev --save-exact @shelf/eslint-config
15
15
  ### Backend
16
16
 
17
17
  ```js
18
- import tsConfig from '@shelf/eslint-config/typescript';
18
+ import tsConfig from '@shelf/eslint-config/typescript.js';
19
19
 
20
20
  export default [...tsConfig];
21
21
  ```
@@ -23,7 +23,7 @@ export default [...tsConfig];
23
23
  ### Frontend
24
24
 
25
25
  ```js
26
- import feTsConfig from '@shelf/eslint-config/frontend-typescript';
26
+ import feTsConfig from '@shelf/eslint-config/frontend-typescript.js';
27
27
 
28
28
  export default [
29
29
  ...feTsConfig,
@@ -37,6 +37,37 @@ export default [
37
37
  ];
38
38
  ```
39
39
 
40
+ ## Oxfmt Migrations
41
+
42
+ Repos that move formatting out of ESLint and into Oxfmt should use the additive no-Prettier entrypoints:
43
+
44
+ ### Backend, no Prettier plugin
45
+
46
+ ```js
47
+ import tsConfig from '@shelf/eslint-config/typescript-no-prettier.js';
48
+
49
+ export default [...tsConfig];
50
+ ```
51
+
52
+ ### Frontend, no Prettier plugin
53
+
54
+ ```js
55
+ import feTsConfig from '@shelf/eslint-config/frontend-typescript-no-prettier.js';
56
+
57
+ export default [
58
+ ...feTsConfig,
59
+ {
60
+ settings: {
61
+ react: {
62
+ version: 'detect',
63
+ },
64
+ },
65
+ },
66
+ ];
67
+ ```
68
+
69
+ The legacy `typescript.js` and `frontend-typescript.js` entrypoints stay supported for repos that still format through Prettier.
70
+
40
71
  ## Publish
41
72
 
42
73
  ```sh
@@ -0,0 +1,68 @@
1
+ import jestFormatting from 'eslint-plugin-jest-formatting';
2
+ import jestPlugin from 'eslint-plugin-jest';
3
+ import stylistic from '@stylistic/eslint-plugin';
4
+ import eslintConfigPrettier from 'eslint-config-prettier';
5
+ import {fixupPluginRules} from '@eslint/compat';
6
+ import env from './common/env.js';
7
+ import paddingLineRules from './rules/padding-line-between-statements.js';
8
+ import jestRules from './rules/jest.js';
9
+ import preferEs6 from './rules/prefer-es6.js';
10
+ import importOrder from './rules/import-order.js';
11
+ import sortImports from './rules/sort-imports.js';
12
+ import comments from './rules/comments.js';
13
+ import defaultBarrelExports, {
14
+ barrelPagesOverride,
15
+ barrelPlugin,
16
+ } from './rules/default-barrel-exports.js';
17
+
18
+ const jestFormattingCompat = fixupPluginRules(jestFormatting);
19
+
20
+ export default [
21
+ {
22
+ files: jestFormattingCompat.configs.strict.overrides[0].files,
23
+ rules: jestFormattingCompat.configs.strict.overrides[0].rules,
24
+ plugins: {
25
+ 'jest-formatting': jestFormattingCompat,
26
+ },
27
+ },
28
+ jestPlugin.configs['flat/recommended'],
29
+ jestPlugin.configs['flat/style'],
30
+ {
31
+ plugins: {
32
+ '@stylistic': stylistic,
33
+ ...barrelPlugin,
34
+ },
35
+
36
+ languageOptions: {
37
+ globals: {
38
+ ...env,
39
+ },
40
+ },
41
+
42
+ rules: {
43
+ ...paddingLineRules,
44
+ ...jestRules,
45
+ ...preferEs6,
46
+ 'no-empty': [
47
+ 'error',
48
+ {
49
+ allowEmptyCatch: true,
50
+ },
51
+ ],
52
+ ...importOrder,
53
+ ...sortImports,
54
+ ...comments,
55
+ ...defaultBarrelExports,
56
+ 'comma-dangle': 'off',
57
+ camelcase: 'error',
58
+ eqeqeq: ['error', 'smart'],
59
+ 'new-cap': 'error',
60
+ 'no-extend-native': 'error',
61
+ 'no-use-before-define': ['error', 'nofunc'],
62
+ '@stylistic/multiline-comment-style': ['error', 'separate-lines'],
63
+ 'require-await': 'error',
64
+ },
65
+ },
66
+ barrelPagesOverride,
67
+ eslintConfigPrettier,
68
+ ];
@@ -0,0 +1,124 @@
1
+ import path from 'node:path';
2
+ import {fileURLToPath} from 'node:url';
3
+ import node from 'eslint-plugin-n';
4
+ import testingLibrary from 'eslint-plugin-testing-library';
5
+ import {fixupConfigRules, fixupPluginRules} from '@eslint/compat';
6
+ import tsParser from '@typescript-eslint/parser';
7
+ import js from '@eslint/js';
8
+ import {FlatCompat} from '@eslint/eslintrc';
9
+ import tsEslint from 'typescript-eslint';
10
+ import sonarjs from 'eslint-plugin-sonarjs';
11
+ import eslintConfigPrettier from 'eslint-config-prettier';
12
+ import react from 'eslint-plugin-react';
13
+ import reactHooks from 'eslint-plugin-react-hooks';
14
+ import _import from 'eslint-plugin-import';
15
+ import globals from 'globals';
16
+ import overrides from './common/overrides.js';
17
+ import youDontNeedLodash from './rules/you-dont-need-lodash.js';
18
+ import typescriptRules from './rules/typescript.js';
19
+ import consistentTypeImports from './rules/consistent-type-imports.js';
20
+ import baseNoPrettierConfig from './base-no-prettier.js';
21
+ import env from './common/env.js';
22
+ import restrictedPackages from './rules/restricted-packages-import.js';
23
+
24
+ const __filename = fileURLToPath(import.meta.url);
25
+ const __dirname = path.dirname(__filename);
26
+ const compat = new FlatCompat({
27
+ baseDirectory: __dirname,
28
+ recommendedConfig: js.configs.recommended,
29
+ });
30
+
31
+ const testingLibraryReact = {
32
+ rules: compat.extends('plugin:testing-library/react')[0].rules,
33
+ files: ['**/__tests__/**/*.[jt]s?(x)', '**/?(*.)+(spec|test).[jt]s?(x)'],
34
+ };
35
+
36
+ export default [
37
+ ...compat.extends('plugin:you-dont-need-lodash-underscore/compatible'),
38
+ ...tsEslint.configs.recommended,
39
+ ...fixupConfigRules(compat.extends('plugin:react/recommended', 'plugin:react-hooks/recommended')),
40
+ sonarjs.configs.recommended,
41
+ ...baseNoPrettierConfig,
42
+ {
43
+ rules: {
44
+ ...restrictedPackages,
45
+ 'no-console': 'error',
46
+ 'react-hooks/exhaustive-deps': 'error',
47
+ 'sonarjs/cognitive-complexity': ['error', 18],
48
+ '@stylistic/multiline-comment-style': 'off',
49
+ 'no-unreachable': 'error',
50
+ 'react/react-in-jsx-scope': 'off',
51
+ },
52
+ },
53
+ testingLibraryReact,
54
+ {
55
+ plugins: {
56
+ react: fixupPluginRules(react),
57
+ 'react-hooks': fixupPluginRules(reactHooks),
58
+ import: fixupPluginRules(_import),
59
+ '@typescript-eslint': tsEslint.plugin,
60
+ node,
61
+ 'testing-library': fixupPluginRules(testingLibrary),
62
+ },
63
+
64
+ languageOptions: {
65
+ globals: {
66
+ ...env,
67
+ ...globals.browser,
68
+ },
69
+ parser: tsParser,
70
+ parserOptions: {
71
+ ecmaFeatures: {
72
+ jsx: true,
73
+ },
74
+ },
75
+ },
76
+
77
+ rules: {
78
+ // Often test name starts with component name which are always capitalized
79
+ 'jest/lowercase-name': 'off',
80
+ 'react/prop-types': 'off',
81
+ 'react/display-name': 'warn',
82
+ 'testing-library/await-async-queries': 'error',
83
+ 'testing-library/no-await-sync-queries': 'error',
84
+ // 'testing-library/no-wait-for-empty-callback': 'error',
85
+ // It's enabled in overrides
86
+ 'testing-library/no-debugging-utils': 'off',
87
+ 'testing-library/consistent-data-testid': [
88
+ 2,
89
+ {
90
+ testIdPattern: '^(([a-z])+(-)*)+$',
91
+ },
92
+ ],
93
+ ...consistentTypeImports,
94
+ // it fail to compile TS on react static class properties (displayName | defaultProps | etc..)
95
+ '@typescript-eslint/explicit-member-accessibility': 0,
96
+ '@typescript-eslint/consistent-type-assertions': 'warn',
97
+ // Don`t need for typescript files
98
+ '@typescript-eslint/no-empty-function': 'off',
99
+ ...typescriptRules,
100
+ '@typescript-eslint/no-unused-vars': ['error', {ignoreRestSiblings: true}],
101
+ ...youDontNeedLodash,
102
+ },
103
+ },
104
+ overrides.allowRequireInConfigs,
105
+ overrides.noExplicitsInTests,
106
+ overrides.noUnusedVarsInTypes,
107
+ overrides.noCastWithJestMock,
108
+ overrides.noTSRulesWithJSON,
109
+ {
110
+ files: ['**/*.test.{ts,tsx,js}', '**/mocks.ts', '**/mock.js'],
111
+ rules: {
112
+ camelcase: 'off',
113
+ 'sonarjs/no-duplicate-string': 'off',
114
+ 'testing-library/no-debugging-utils': 'error',
115
+ },
116
+ },
117
+ {
118
+ files: ['**/*.styled.{ts,tsx}'],
119
+ rules: {
120
+ 'sonarjs/no-nested-template-literals': 'off',
121
+ },
122
+ },
123
+ eslintConfigPrettier,
124
+ ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shelf/eslint-config",
3
- "version": "6.2.1",
3
+ "version": "6.3.0",
4
4
  "description": "ESLint Config for Shelf Projects",
5
5
  "license": "MIT",
6
6
  "repository": "shelfio/eslint-config",
@@ -16,8 +16,11 @@
16
16
  "common",
17
17
  "rules",
18
18
  "base.js",
19
+ "base-no-prettier.js",
19
20
  "frontend-typescript.js",
20
- "typescript.js"
21
+ "frontend-typescript-no-prettier.js",
22
+ "typescript.js",
23
+ "typescript-no-prettier.js"
21
24
  ],
22
25
  "main": "base.js",
23
26
  "keywords": [
@@ -61,6 +64,11 @@
61
64
  "eslint": "10.x",
62
65
  "prettier": "3.x"
63
66
  },
67
+ "peerDependenciesMeta": {
68
+ "prettier": {
69
+ "optional": true
70
+ }
71
+ },
64
72
  "publishConfig": {
65
73
  "access": "public"
66
74
  },
@@ -0,0 +1,146 @@
1
+ import path from 'node:path';
2
+ import {fileURLToPath} from 'node:url';
3
+ import jestFormatting from 'eslint-plugin-jest-formatting';
4
+ import _import from 'eslint-plugin-import';
5
+ import node from 'eslint-plugin-n';
6
+ import {fixupPluginRules} from '@eslint/compat';
7
+ import tsParser from '@typescript-eslint/parser';
8
+ import js from '@eslint/js';
9
+ import {FlatCompat} from '@eslint/eslintrc';
10
+ import tsEslint from 'typescript-eslint';
11
+ import jestPlugin from 'eslint-plugin-jest';
12
+ import shelfNoLodash from 'eslint-plugin-shelf-no-need-lodash-methods';
13
+ import stylistic from '@stylistic/eslint-plugin';
14
+ import eslintConfigPrettier from 'eslint-config-prettier';
15
+ import env from './common/env.js';
16
+ import jestRules from './rules/jest.js';
17
+ import paddingLineRules from './rules/padding-line-between-statements.js';
18
+ import preferEs6 from './rules/prefer-es6.js';
19
+ import importOrder from './rules/import-order.js';
20
+ import sortImports from './rules/sort-imports.js';
21
+ import typeAssertionRules from './rules/consistent-type-assertions.js';
22
+ import consistentTypeImports from './rules/consistent-type-imports.js';
23
+ import youDontNeedLodash from './rules/you-dont-need-lodash.js';
24
+ import typescriptRules from './rules/typescript.js';
25
+ import restrictedPackages from './rules/restricted-packages-import.js';
26
+ import overrides from './common/overrides.js';
27
+
28
+ const __filename = fileURLToPath(import.meta.url);
29
+ const __dirname = path.dirname(__filename);
30
+ const compat = new FlatCompat({
31
+ baseDirectory: __dirname,
32
+ recommendedConfig: js.configs.recommended,
33
+ });
34
+ const jestFormattingCompat = fixupPluginRules(jestFormatting);
35
+
36
+ export default [
37
+ ...compat.extends('plugin:you-dont-need-lodash-underscore/compatible'),
38
+ ...tsEslint.configs.recommended,
39
+ {
40
+ files: jestFormattingCompat.configs.strict.overrides[0].files,
41
+ rules: jestFormattingCompat.configs.strict.overrides[0].rules,
42
+ plugins: {
43
+ 'jest-formatting': jestFormattingCompat,
44
+ },
45
+ },
46
+ jestPlugin.configs['flat/recommended'],
47
+ jestPlugin.configs['flat/style'],
48
+ shelfNoLodash.configs.all,
49
+ {
50
+ plugins: {
51
+ 'jest-formatting': jestFormattingCompat,
52
+ import: fixupPluginRules(_import),
53
+ node,
54
+ '@stylistic': stylistic,
55
+ },
56
+
57
+ languageOptions: {
58
+ globals: {
59
+ ...env,
60
+ },
61
+
62
+ parser: tsParser,
63
+
64
+ parserOptions: {
65
+ ecmaFeatures: {
66
+ jsx: true,
67
+ },
68
+ },
69
+ },
70
+
71
+ settings: {
72
+ 'import/internal-regex': '^@shelf/',
73
+ },
74
+
75
+ rules: {
76
+ complexity: [
77
+ 'warn',
78
+ {
79
+ max: 5,
80
+ },
81
+ ],
82
+
83
+ 'multiline-ternary': ['error', 'never'],
84
+ curly: 'error',
85
+ 'no-nested-ternary': 'error',
86
+
87
+ ...paddingLineRules,
88
+ ...jestRules,
89
+ ...preferEs6,
90
+ ...importOrder,
91
+ ...sortImports,
92
+ 'comma-dangle': 'off',
93
+ ...typeAssertionRules,
94
+ camelcase: [
95
+ 'error',
96
+ {
97
+ properties: 'never',
98
+ ignoreGlobals: true,
99
+ allow: ['hash_key', 'range_key'],
100
+ },
101
+ ],
102
+ eqeqeq: ['error', 'smart'],
103
+ 'new-cap': 'error',
104
+ 'no-extend-native': 'error',
105
+ 'no-use-before-define': 'off',
106
+ ...consistentTypeImports,
107
+ '@stylistic/multiline-comment-style': ['error', 'separate-lines'],
108
+ 'arrow-body-style': [
109
+ 'error',
110
+ 'as-needed',
111
+ {
112
+ requireReturnForObjectLiteral: true,
113
+ },
114
+ ],
115
+ 'id-length': [
116
+ 'warn',
117
+ {
118
+ min: 1,
119
+ max: 22,
120
+ properties: 'never',
121
+ },
122
+ ],
123
+ 'no-unreachable': 'error',
124
+ 'require-await': 'error',
125
+ ...youDontNeedLodash,
126
+ '@typescript-eslint/ban-ts-comment': 'warn',
127
+ '@typescript-eslint/no-non-null-assertion': 'off',
128
+ ...typescriptRules,
129
+ ...restrictedPackages,
130
+ '@typescript-eslint/no-explicit-any': 'warn',
131
+ 'no-restricted-syntax': [
132
+ 'error',
133
+ {
134
+ selector: "ObjectExpression > Property[key.name='accountId'] ~ SpreadElement",
135
+ message: "Danger, this can overwrite 'accountId'. Rearrange the order.",
136
+ },
137
+ ],
138
+ },
139
+ },
140
+ eslintConfigPrettier,
141
+ overrides.allowRequireInConfigs,
142
+ overrides.noExplicitsInTests,
143
+ overrides.noUnusedVarsInTypes,
144
+ overrides.noCastWithJestMock,
145
+ overrides.noTSRulesWithJSON,
146
+ ];