@fullstacksjs/eslint-config 10.11.1 → 11.0.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.
Files changed (50) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +6 -4
  3. package/package.json +27 -50
  4. package/src/index.js +86 -0
  5. package/src/init.d.ts +21 -0
  6. package/src/modules/base.js +187 -0
  7. package/src/modules/cypress.js +23 -0
  8. package/{esm.js → src/modules/esm.js} +1 -1
  9. package/src/modules/fp.js +16 -0
  10. package/src/modules/graphql.js +84 -0
  11. package/src/modules/ignores.js +39 -0
  12. package/src/modules/imports.js +100 -0
  13. package/src/modules/jest.js +74 -0
  14. package/src/modules/next.js +32 -0
  15. package/src/modules/node.js +33 -0
  16. package/src/modules/prettier.js +93 -0
  17. package/src/modules/promise.js +27 -0
  18. package/src/modules/react.js +151 -0
  19. package/src/modules/storybook.js +34 -0
  20. package/src/modules/strict.js +16 -0
  21. package/src/modules/tailwind.js +19 -0
  22. package/src/modules/tests.js +43 -0
  23. package/src/modules/typescript.js +255 -0
  24. package/src/modules/vitest.js +84 -0
  25. package/src/utils/conditions.js +20 -0
  26. package/src/utils/globs.js +40 -0
  27. package/base.js +0 -246
  28. package/cypress.js +0 -31
  29. package/expensive-rules.js +0 -4
  30. package/fp.js +0 -23
  31. package/graphql.js +0 -79
  32. package/import.js +0 -64
  33. package/index.js +0 -20
  34. package/init.d.ts +0 -22
  35. package/init.js +0 -64
  36. package/jest.js +0 -80
  37. package/next.js +0 -27
  38. package/node.js +0 -43
  39. package/prettier.js +0 -8
  40. package/promise.js +0 -21
  41. package/react.js +0 -147
  42. package/registerOpts.js +0 -20
  43. package/storybook.js +0 -31
  44. package/strict.js +0 -15
  45. package/tailwind.js +0 -15
  46. package/test.js +0 -40
  47. package/typecheck.js +0 -89
  48. package/typescript.js +0 -169
  49. package/utils.js +0 -21
  50. /package/{naming-convention.js → src/utils/naming-convention.js} +0 -0
@@ -0,0 +1,100 @@
1
+ const plugin = require('eslint-plugin-import-x');
2
+ const { predicate } = require('../utils/conditions');
3
+
4
+ const tsExtensions = ['.ts', '.tsx', '.cts', '.mts', '.ctsx', '.mtsx'];
5
+ const jsExtensions = ['.mjs', '.js', '.jsx', '.cjs'];
6
+ const allExtensions = [...jsExtensions, ...tsExtensions];
7
+
8
+ /**
9
+ * @param { import('../init').Options } options
10
+ * @return { import('eslint').Linter.FlatConfig }
11
+ */
12
+ function imports(options = {}) {
13
+ const isObject = typeof options.import === 'object';
14
+
15
+ const config = {
16
+ plugins: { import: plugin },
17
+
18
+ settings: {
19
+ 'import-x/extensions': allExtensions,
20
+ 'import-x/resolver': {
21
+ node: { extensions: allExtensions },
22
+ ...predicate(isObject && 'projects' in options.import, {
23
+ typescript: { project: options.import.projects },
24
+ }),
25
+ },
26
+ 'import-x/parsers': { '@typescript-eslint/parser': tsExtensions },
27
+ 'import-x/external-module-folders': ['node_modules', 'node_modules/@types'],
28
+ 'import-x/ignore': ['node_modules', '\\.(scss|css|svg|json)$'],
29
+ ...predicate(isObject && 'internalRegExp' in options.import, {
30
+ 'import-x/internal-regex': options.import.internalRegExp,
31
+ }),
32
+ ...predicate(isObject && 'lifetime' in options.import, {
33
+ 'import-x/cache': { lifetime: options.import.lifetime },
34
+ }),
35
+ },
36
+ rules: {
37
+ 'import/consistent-type-specifier-style': ['warn', 'prefer-top-level'],
38
+ 'import/extensions': [
39
+ 'error',
40
+ 'always',
41
+ {
42
+ js: 'never',
43
+ jsx: 'never',
44
+ ts: 'never',
45
+ tsx: 'never',
46
+ },
47
+ ],
48
+ 'import/first': 'error',
49
+ 'import/newline-after-import': 'warn',
50
+ 'import/no-absolute-path': 'error',
51
+ 'import/no-amd': 'error',
52
+ 'import/no-duplicates': 'error',
53
+ 'import/no-empty-named-blocks': 'error',
54
+ 'import/no-extraneous-dependencies': ['error', { devDependencies: true }],
55
+ 'import/no-mutable-exports': 'error',
56
+ 'import/no-named-as-default': 'error',
57
+ 'import/no-named-default': 'error',
58
+ 'import/no-relative-packages': 'error',
59
+ 'import/no-self-import': 'error',
60
+ 'import/no-unresolved': ['error', { caseSensitiveStrict: true }],
61
+ 'import/no-useless-path-segments': 'warn',
62
+ 'import/no-webpack-loader-syntax': 'error',
63
+ 'import/order': ['warn', { groups: ['builtin', ['external', 'internal'], 'parent', ['sibling', 'index']] }], // collision
64
+
65
+ ...predicate(!options.disableExpensiveRules, {
66
+ 'import/default': 'error',
67
+ 'import/export': 'error',
68
+ 'import/named': 'error',
69
+ 'import/namespace': 'error',
70
+ 'import/no-cycle': ['error', { maxDepth: Infinity }],
71
+ 'import/no-deprecated': 'warn',
72
+ 'import/no-named-as-default-member': 'error',
73
+ }),
74
+
75
+ 'import/dynamic-import-chunkname': 'off',
76
+ 'import/exports-last': 'off',
77
+ 'import/group-exports': 'off',
78
+ 'import/max-dependencies': 'off',
79
+ 'import/no-anonymous-default-export': 'off',
80
+ 'import/no-commonjs': 'off',
81
+ 'import/no-default-export': 'off',
82
+ 'import/no-dynamic-require': 'off',
83
+ 'import/no-import-module-exports': 'off',
84
+ 'import/no-internal-modules': 'off',
85
+ 'import/no-named-export': 'off',
86
+ 'import/no-namespace': 'off',
87
+ 'import/no-nodejs-modules': 'off',
88
+ 'import/no-relative-parent-imports': 'off',
89
+ 'import/no-restricted-paths': 'off',
90
+ 'import/no-unassigned-import': 'off',
91
+ 'import/no-unused-modules': 'off',
92
+ 'import/prefer-default-export': 'off',
93
+ 'import/unambiguous': 'off',
94
+ },
95
+ };
96
+
97
+ return config;
98
+ }
99
+
100
+ module.exports = imports;
@@ -0,0 +1,74 @@
1
+ const globals = require('globals');
2
+ const plugin = require('eslint-plugin-jest');
3
+ const { predicate } = require('../utils/conditions');
4
+ const { globs } = require('../utils/globs');
5
+
6
+ /**
7
+ * @param { import('./init.d.ts').Options } options
8
+ * @return { import('eslint').Linter.FlatConfig } */
9
+ function jest(options = {}) {
10
+ return {
11
+ files: globs.test,
12
+ plugins: { jest: plugin },
13
+ languageOptions: { globals: globals.jest },
14
+ rules: {
15
+ 'jest/consistent-test-it': 'off',
16
+ 'jest/expect-expect': 'off',
17
+ 'jest/lowercase-name': 'off',
18
+ 'jest/max-nested-describe': ['error', { max: 2 }],
19
+ 'jest/no-alias-methods': 'error',
20
+ 'jest/no-commented-out-tests': 'warn',
21
+ 'jest/no-conditional-expect': 'error',
22
+ 'jest/no-conditional-in-test': 'error',
23
+ 'jest/no-confusing-set-timeout': 'warn',
24
+ 'jest/no-done-callback': 'warn',
25
+ 'jest/no-expect-resolves': 'off',
26
+ 'jest/no-export': 'error',
27
+ 'jest/no-hooks': 'off',
28
+ 'jest/no-interpolation-in-snapshots': 'error',
29
+ 'jest/no-jasmine-globals': 'off',
30
+ 'jest/no-large-snapshots': ['warn', { maxSize: 300 }],
31
+ 'jest/no-mocks-import': 'error',
32
+ 'jest/no-restricted-jest-methods': 'off',
33
+ 'jest/no-restricted-matchers': 'error',
34
+ 'jest/no-standalone-expect': 'off',
35
+ 'jest/no-test-callback': 'off',
36
+ 'jest/no-test-prefixes': 'error',
37
+ 'jest/no-test-return-statement': 'off',
38
+ 'jest/no-truthy-falsy': 'off',
39
+ 'jest/prefer-called-with': 'error',
40
+ 'jest/prefer-each': 'warn',
41
+ 'jest/prefer-expect-assertions': 'off',
42
+ 'jest/prefer-expect-resolves': 'warn',
43
+ 'jest/prefer-hooks-on-top': 'error',
44
+ 'jest/prefer-inline-snapshots': 'off',
45
+ 'jest/prefer-lowercase-title': 'off',
46
+ 'jest/prefer-mock-promise-shorthand': 'warn',
47
+ 'jest/prefer-snapshot-hint': 'warn',
48
+ 'jest/prefer-spy-on': 'off',
49
+ 'jest/prefer-strict-equal': 'off',
50
+ 'jest/prefer-to-be-null': 'off',
51
+ 'jest/prefer-to-be-undefined': 'off',
52
+ 'jest/prefer-to-be': 'warn',
53
+ 'jest/prefer-to-contain': 'warn',
54
+ 'jest/prefer-to-have-length': 'warn',
55
+ 'jest/prefer-todo': 'warn',
56
+ 'jest/require-hook': 'off',
57
+ 'jest/require-to-throw-message': 'off',
58
+ 'jest/require-top-level-describe': 'off',
59
+ 'jest/valid-describe-callback': 'error',
60
+ 'jest/valid-expect-in-promise': 'error',
61
+ 'jest/valid-expect': 'error',
62
+ 'jest/valid-title': 'warn',
63
+ 'jest/no-deprecated-functions': 'error',
64
+
65
+ // ...predicate(options.typescript, {
66
+ // '@typescript-eslint/unbound-method': 'off',
67
+ // 'jest/unbound-method': 'error',
68
+ // 'jest/no-untyped-mock-factory': 'warn',
69
+ // }),
70
+ },
71
+ };
72
+ }
73
+
74
+ module.exports = jest;
@@ -0,0 +1,32 @@
1
+ const plugin = require('@next/eslint-plugin-next');
2
+
3
+ /** @type { import('eslint').Linter.FlatConfig } */
4
+ function next() {
5
+ return {
6
+ plugins: { next: plugin },
7
+ rules: {
8
+ '@next/next/google-font-display': 'warn',
9
+ '@next/next/google-font-preconnect': 'warn',
10
+ '@next/next/inline-script-id': 'warn',
11
+ '@next/next/next-script-for-ga': 'warn',
12
+ '@next/next/no-assign-module-variable': 'warn',
13
+ '@next/next/no-async-client-component': 'warn',
14
+ '@next/next/no-before-interactive-script-outside-document': 'warn',
15
+ '@next/next/no-css-tags': 'warn',
16
+ '@next/next/no-document-import-in-page': 'warn',
17
+ '@next/next/no-duplicate-head': 'warn',
18
+ '@next/next/no-head-element': 'warn',
19
+ '@next/next/no-head-import-in-document': 'warn',
20
+ '@next/next/no-html-link-for-pages': 'warn',
21
+ '@next/next/no-img-element': 'warn',
22
+ '@next/next/no-page-custom-font': 'warn',
23
+ '@next/next/no-script-component-in-head': 'warn',
24
+ '@next/next/no-styled-jsx-in-document': 'warn',
25
+ '@next/next/no-sync-scripts': 'warn',
26
+ '@next/next/no-title-in-document-head': 'warn',
27
+ '@next/next/no-unwanted-polyfillio': 'warn',
28
+ },
29
+ };
30
+ }
31
+
32
+ module.exports = next;
@@ -0,0 +1,33 @@
1
+ const plugin = require('eslint-plugin-n');
2
+
3
+ /** @return { import('eslint').Linter.FlatConfig } */
4
+ function node() {
5
+ return {
6
+ plugins: { n: plugin },
7
+ rules: {
8
+ 'n/no-unsupported-features/es-builtins': 'off', // Nice but not a general rule
9
+ 'n/no-unsupported-features/es-syntax': 'off', // Nice but not a general rule
10
+ 'n/no-unsupported-features/node-builtins': 'off', // Nice but not a general rule
11
+ 'n/prefer-global/buffer': 'warn',
12
+ 'n/prefer-global/console': 'warn',
13
+ 'n/prefer-global/process': 'warn',
14
+ 'n/prefer-global/text-decoder': 'warn',
15
+ 'n/prefer-global/text-encoder': 'warn',
16
+ 'n/prefer-global/url-search-params': 'warn',
17
+ 'n/prefer-global/url': 'warn',
18
+ 'n/prefer-promises/dns': 'warn',
19
+ 'n/prefer-promises/fs': 'warn',
20
+ 'n/exports-style': ['error', 'module.exports', { allowBatchAssign: false }],
21
+ 'n/global-require': 'warn',
22
+ 'n/handle-callback-err': 'warn',
23
+ 'n/no-deprecated-api': 'error',
24
+ 'n/no-exports-assign': 'error',
25
+ 'n/no-mixed-requires': 'warn',
26
+ 'n/no-new-require': 'error',
27
+ 'n/no-path-concat': 'error',
28
+ 'n/process-exit-as-throw': 'error',
29
+ },
30
+ };
31
+ }
32
+
33
+ module.exports = node;
@@ -0,0 +1,93 @@
1
+ const plugin = require('eslint-plugin-prettier');
2
+
3
+ /** @return { Promise<import('eslint').Linter.FlatConfig> } */
4
+ function prettier() {
5
+ return {
6
+ plugins: { prettier: plugin },
7
+ rules: {
8
+ 'prettier/prettier': 'error',
9
+
10
+ 'curly': 'off',
11
+ 'brace-style': 'off',
12
+ 'no-unexpected-multiline': 'off',
13
+
14
+ '@typescript-eslint/lines-around-comment': 'off',
15
+ '@typescript-eslint/quotes': 'off',
16
+ '@typescript-eslint/block-spacing': 'off',
17
+ '@typescript-eslint/brace-style': 'off',
18
+ '@typescript-eslint/comma-dangle': 'off',
19
+ '@typescript-eslint/comma-spacing': 'off',
20
+ '@typescript-eslint/func-call-spacing': 'off',
21
+ '@typescript-eslint/indent': 'off',
22
+ '@typescript-eslint/key-spacing': 'off',
23
+ '@typescript-eslint/keyword-spacing': 'off',
24
+ '@typescript-eslint/member-delimiter-style': 'off',
25
+ '@typescript-eslint/no-extra-parens': 'off',
26
+ '@typescript-eslint/no-extra-semi': 'off',
27
+ '@typescript-eslint/object-curly-spacing': 'off',
28
+ '@typescript-eslint/semi': 'off',
29
+ '@typescript-eslint/space-before-blocks': 'off',
30
+ '@typescript-eslint/space-before-function-paren': 'off',
31
+ '@typescript-eslint/space-infix-ops': 'off',
32
+ '@typescript-eslint/type-annotation-spacing': 'off',
33
+
34
+ 'react/jsx-child-element-spacing': 'off',
35
+ 'react/jsx-closing-bracket-location': 'off',
36
+ 'react/jsx-closing-tag-location': 'off',
37
+ 'react/jsx-curly-newline': 'off',
38
+ 'react/jsx-curly-spacing': 'off',
39
+ 'react/jsx-equals-spacing': 'off',
40
+ 'react/jsx-first-prop-new-line': 'off',
41
+ 'react/jsx-indent': 'off',
42
+ 'react/jsx-indent-props': 'off',
43
+ 'react/jsx-max-props-per-line': 'off',
44
+ 'react/jsx-newline': 'off',
45
+ 'react/jsx-one-expression-per-line': 'off',
46
+ 'react/jsx-props-no-multi-spaces': 'off',
47
+ 'react/jsx-tag-spacing': 'off',
48
+ 'react/jsx-wrap-multilines': 'off',
49
+
50
+ 'vue/html-self-closing': 'off',
51
+ 'vue/max-len': 'off',
52
+ 'vue/array-bracket-newline': 'off',
53
+ 'vue/array-bracket-spacing': 'off',
54
+ 'vue/array-element-newline': 'off',
55
+ 'vue/arrow-spacing': 'off',
56
+ 'vue/block-spacing': 'off',
57
+ 'vue/block-tag-newline': 'off',
58
+ 'vue/brace-style': 'off',
59
+ 'vue/comma-dangle': 'off',
60
+ 'vue/comma-spacing': 'off',
61
+ 'vue/comma-style': 'off',
62
+ 'vue/dot-location': 'off',
63
+ 'vue/func-call-spacing': 'off',
64
+ 'vue/html-closing-bracket-newline': 'off',
65
+ 'vue/html-closing-bracket-spacing': 'off',
66
+ 'vue/html-end-tags': 'off',
67
+ 'vue/html-indent': 'off',
68
+ 'vue/html-quotes': 'off',
69
+ 'vue/key-spacing': 'off',
70
+ 'vue/keyword-spacing': 'off',
71
+ 'vue/max-attributes-per-line': 'off',
72
+ 'vue/multiline-html-element-content-newline': 'off',
73
+ 'vue/multiline-ternary': 'off',
74
+ 'vue/mustache-interpolation-spacing': 'off',
75
+ 'vue/no-extra-parens': 'off',
76
+ 'vue/no-multi-spaces': 'off',
77
+ 'vue/no-spaces-around-equal-signs-in-attribute': 'off',
78
+ 'vue/object-curly-newline': 'off',
79
+ 'vue/object-curly-spacing': 'off',
80
+ 'vue/object-property-newline': 'off',
81
+ 'vue/operator-linebreak': 'off',
82
+ 'vue/quote-props': 'off',
83
+ 'vue/script-indent': 'off',
84
+ 'vue/singleline-html-element-content-newline': 'off',
85
+ 'vue/space-in-parens': 'off',
86
+ 'vue/space-infix-ops': 'off',
87
+ 'vue/space-unary-ops': 'off',
88
+ 'vue/template-curly-spacing': 'off',
89
+ },
90
+ };
91
+ }
92
+
93
+ module.exports = prettier;
@@ -0,0 +1,27 @@
1
+ const plugin = require('eslint-plugin-promise');
2
+
3
+ /** @return { import('eslint').Linter.FlatConfig } */
4
+ function promise() {
5
+ return {
6
+ plugins: { promise: plugin },
7
+ rules: {
8
+ 'promise/always-return': 'off',
9
+ 'promise/avoid-new': 'off',
10
+ 'promise/catch-or-return': 'off',
11
+ 'promise/no-callback-in-promise': 'off',
12
+ 'promise/no-native': 'off',
13
+ 'promise/no-nesting': 'off',
14
+ 'promise/no-new-statics': 'error',
15
+ 'promise/no-promise-in-callback': 'error',
16
+ 'promise/no-return-in-finally': 'warn',
17
+ 'promise/no-return-wrap': 'error',
18
+ 'promise/param-names': 'warn',
19
+ 'promise/prefer-await-to-callbacks': 'off',
20
+ 'promise/prefer-await-to-then': 'off',
21
+ 'promise/valid-params': 'warn',
22
+ 'promise/no-multiple-resolved': 'warn',
23
+ },
24
+ };
25
+ }
26
+
27
+ module.exports = promise;
@@ -0,0 +1,151 @@
1
+ const reactPlugin = require('eslint-plugin-react');
2
+ const hooksPlugin = require('eslint-plugin-react-hooks');
3
+ const a11yPlugin = require('eslint-plugin-jsx-a11y');
4
+
5
+ /** @return { import('eslint').Linter.FlatConfig } */
6
+ function react() {
7
+ return {
8
+ plugins: {
9
+ 'react': reactPlugin,
10
+ 'react-hooks': hooksPlugin,
11
+ 'jsx-a11y': a11yPlugin,
12
+ },
13
+ settings: {
14
+ react: {
15
+ pragma: 'React',
16
+ version: 'detect',
17
+ },
18
+ },
19
+ rules: {
20
+ 'react/boolean-prop-naming': 'off',
21
+ 'react/button-has-type': 'off',
22
+ 'react/default-props-match-prop-types': 'off',
23
+ 'react/destructuring-assignment': 'off',
24
+ 'react/display-name': ['off', { ignoreTranspilerName: false }],
25
+ 'react/forbid-component-props': 'off',
26
+ 'react/forbid-dom-props': 'off',
27
+ 'react/forbid-elements': 'off',
28
+ 'react/forbid-foreign-prop-types': 'error',
29
+ 'react/forbid-prop-types': 'off',
30
+ 'react/function-component-definition': ['warn', { namedComponents: 'arrow-function', unnamedComponents: 'arrow-function' }],
31
+ 'react/hook-use-state': 'off',
32
+ 'react/iframe-missing-sandbox': 'error',
33
+ 'react/jsx-boolean-value': 'warn',
34
+ 'react/jsx-child-element-spacing': 'warn',
35
+ 'react/jsx-curly-brace-presence': ['warn', { props: 'never', children: 'ignore' }],
36
+ 'react/jsx-filename-extension': ['error', { extensions: ['.jsx', '.tsx'] }],
37
+ 'react/jsx-fragments': 'off',
38
+ 'react/jsx-handler-names': 'off',
39
+ 'react/jsx-key': 'error',
40
+ 'react/jsx-max-depth': 'off',
41
+ 'react/jsx-newline': 'off',
42
+ 'react/jsx-no-bind': 'off',
43
+ 'react/jsx-no-comment-textnodes': 'error',
44
+ 'react/jsx-no-constructed-context-values': 'error',
45
+ 'react/jsx-no-duplicate-props': 'error',
46
+ 'react/jsx-no-leaked-render': 'error',
47
+ 'react/jsx-no-literals': 'off',
48
+ 'react/jsx-no-script-url': 'error',
49
+ 'react/jsx-no-target-blank': 'error',
50
+ 'react/jsx-no-undef': 'error',
51
+ 'react/jsx-no-useless-fragment': 'warn',
52
+ 'react/jsx-one-expression-per-line': ['off', { allow: 'literal' }],
53
+ 'react/jsx-pascal-case': 'error',
54
+ 'react/jsx-props-no-multi-spaces': 'off',
55
+ 'react/jsx-props-no-spreading': 'off',
56
+ 'react/jsx-sort-props': 'off',
57
+ 'react/jsx-uses-react': 'error',
58
+ 'react/jsx-uses-vars': 'error',
59
+ 'react/no-access-state-in-setstate': 'error',
60
+ 'react/no-adjacent-inline-elements': 'error',
61
+ 'react/no-array-index-key': 'warn',
62
+ 'react/no-arrow-function-lifecycle': 'error',
63
+ 'react/no-children-prop': 'off',
64
+ 'react/no-danger': 'off',
65
+ 'react/no-danger-with-children': 'error',
66
+ 'react/no-deprecated': 'error',
67
+ 'react/no-did-mount-set-state': 'error',
68
+ 'react/no-did-update-set-state': 'error',
69
+ 'react/no-direct-mutation-state': 'error',
70
+ 'react/no-find-dom-node': 'error',
71
+ 'react/no-invalid-html-attribute': 'warn',
72
+ 'react/no-is-mounted': 'error',
73
+ 'react/no-multi-comp': 'off',
74
+ 'react/no-namespace': 'error',
75
+ 'react/no-object-type-as-default-prop': 'warn',
76
+ 'react/no-redundant-should-component-update': 'error',
77
+ 'react/no-render-return-value': 'error',
78
+ 'react/no-set-state': 'off',
79
+ 'react/no-string-refs': 'error',
80
+ 'react/no-this-in-sfc': 'error',
81
+ 'react/no-typos': 'error',
82
+ 'react/no-unescaped-entities': 'warn',
83
+ 'react/no-unknown-property': 'error',
84
+ 'react/no-unsafe': 'warn',
85
+ 'react/no-unstable-nested-components': ['error', { allowAsProps: true }],
86
+ 'react/no-unused-class-component-methods': 'warn',
87
+ 'react/no-unused-prop-types': 'error',
88
+ 'react/no-unused-state': 'error',
89
+ 'react/no-will-update-set-state': 'error',
90
+ 'react/prefer-es6-class': 'off',
91
+ 'react/prefer-exact-props': 'off',
92
+ 'react/prefer-read-only-props': 'off',
93
+ 'react/prefer-stateless-function': 'off',
94
+ 'react/prop-types': 'off',
95
+ 'react/react-in-jsx-scope': 'off', // JSX automatic runtime
96
+ 'react/require-default-props': 'off',
97
+ 'react/require-optimization': 'off',
98
+ 'react/require-render-return': 'error',
99
+ 'react/self-closing-comp': 'error',
100
+ 'react/sort-comp': 'off',
101
+ 'react/sort-default-props': 'warn',
102
+ 'react/sort-prop-types': 'off',
103
+ 'react/state-in-constructor': 'off',
104
+ 'react/static-property-placement': 'off',
105
+ 'react/style-prop-object': 'error',
106
+ 'react/void-dom-elements-no-children': 'error',
107
+
108
+ 'react-hooks/exhaustive-deps': 'warn',
109
+ 'react-hooks/rules-of-hooks': 'error',
110
+
111
+ 'jsx-a11y/alt-text': 'warn',
112
+ 'jsx-a11y/anchor-has-content': 'error',
113
+ 'jsx-a11y/anchor-is-valid': 'error',
114
+ 'jsx-a11y/aria-activedescendant-has-tabindex': 'error',
115
+ 'jsx-a11y/aria-props': 'error',
116
+ 'jsx-a11y/aria-proptypes': 'error',
117
+ 'jsx-a11y/aria-role': 'error',
118
+ 'jsx-a11y/aria-unsupported-elements': 'error',
119
+ 'jsx-a11y/autocomplete-valid': 'off',
120
+ 'jsx-a11y/click-events-have-key-events': 'error',
121
+ 'jsx-a11y/control-has-associated-label': 'off',
122
+ 'jsx-a11y/heading-has-content': 'error',
123
+ 'jsx-a11y/html-has-lang': 'error',
124
+ 'jsx-a11y/iframe-has-title': 'error',
125
+ 'jsx-a11y/img-redundant-alt': 'error',
126
+ 'jsx-a11y/interactive-supports-focus': 'warn',
127
+ 'jsx-a11y/label-has-associated-control': 'error',
128
+ 'jsx-a11y/lang': 'error',
129
+ 'jsx-a11y/media-has-caption': 'warn',
130
+ 'jsx-a11y/mouse-events-have-key-events': 'error',
131
+ 'jsx-a11y/no-access-key': 'error',
132
+ 'jsx-a11y/no-aria-hidden-on-focusable': 'warn',
133
+ 'jsx-a11y/no-autofocus': 'off',
134
+ 'jsx-a11y/no-distracting-elements': 'error',
135
+ 'jsx-a11y/no-interactive-element-to-noninteractive-role': 'warn',
136
+ 'jsx-a11y/no-noninteractive-element-interactions': 'warn',
137
+ 'jsx-a11y/no-noninteractive-element-to-interactive-role': 'warn',
138
+ 'jsx-a11y/no-noninteractive-tabindex': 'off',
139
+ 'jsx-a11y/no-redundant-roles': 'error',
140
+ 'jsx-a11y/no-static-element-interactions': 'off',
141
+ 'jsx-a11y/role-has-required-aria-props': 'error',
142
+ 'jsx-a11y/role-supports-aria-props': 'error',
143
+ 'jsx-a11y/scope': 'error',
144
+ 'jsx-a11y/tabindex-no-positive': 'warn',
145
+ 'jsx-a11y/anchor-ambiguous-text': 'off',
146
+ 'jsx-a11y/prefer-tag-over-role': 'off',
147
+ },
148
+ };
149
+ }
150
+
151
+ module.exports = react;
@@ -0,0 +1,34 @@
1
+ const plugin = require('eslint-plugin-storybook');
2
+ const { globs } = require('../utils/globs');
3
+
4
+ /** @return { import('eslint').Linter.FlatConfig } */
5
+ function storybook() {
6
+ return {
7
+ files: globs.storybook,
8
+ plugins: { storybook: plugin },
9
+ rules: {
10
+ 'storybook/await-interactions': 'error',
11
+ 'storybook/context-in-play-function': 'error',
12
+ 'storybook/default-exports': 'error',
13
+ 'storybook/hierarchy-separator': 'warn',
14
+ 'storybook/no-redundant-story-name': 'warn',
15
+ 'storybook/no-uninstalled-addons': 'error',
16
+ 'storybook/prefer-pascal-case': 'warn',
17
+ 'storybook/story-exports': 'error',
18
+ 'storybook/use-storybook-expect': 'error',
19
+ 'storybook/use-storybook-testing-library': 'error',
20
+
21
+ 'storybook/csf-component': 'warn',
22
+ 'storybook/no-stories-of': 'warn',
23
+ 'storybook/no-title-property-in-meta': 'off',
24
+ 'storybook/meta-inline-properties': 'off',
25
+
26
+ // Conflicts
27
+ '@typescript-eslint/no-confusing-void-expression': 'off',
28
+ 'react/jsx-no-useless-fragment': 'off',
29
+ 'react-hooks/rules-of-hooks': 'off',
30
+ },
31
+ };
32
+ }
33
+
34
+ module.exports = storybook;
@@ -0,0 +1,16 @@
1
+ const { predicate } = require('../utils/conditions');
2
+
3
+ /**
4
+ * @param {import('../init.d.ts').Options} options
5
+ * @return { import('eslint').Linter.FlatConfig }
6
+ */
7
+ function strict(options = {}) {
8
+ return {
9
+ rules: {
10
+ 'no-console': 'warn',
11
+ // ...predicate(options.typescript, { '@typescript-eslint/no-non-null-assertion': 'warn' }),
12
+ },
13
+ };
14
+ }
15
+
16
+ module.exports = strict;
@@ -0,0 +1,19 @@
1
+ const plugin = require('eslint-plugin-tailwindcss');
2
+
3
+ /** @return { Promise<import('eslint').Linter.FlatConfig> } */
4
+ function tailwind() {
5
+ return {
6
+ plugins: { tailwindcss: plugin },
7
+ rules: {
8
+ 'tailwindcss/classnames-order': 'warn',
9
+ 'tailwindcss/enforces-negative-arbitrary-values': 'warn',
10
+ 'tailwindcss/enforces-shorthand': 'warn',
11
+ 'tailwindcss/migration-from-tailwind-2': 'warn',
12
+ 'tailwindcss/no-arbitrary-value': 'off',
13
+ 'tailwindcss/no-custom-classname': 'warn',
14
+ 'tailwindcss/no-contradicting-classname': 'error',
15
+ },
16
+ };
17
+ }
18
+
19
+ module.exports = tailwind;
@@ -0,0 +1,43 @@
1
+ const plugin = require('eslint-plugin-jest-formatting');
2
+ const { globs } = require('../utils/globs');
3
+ const { predicate } = require('../utils/conditions');
4
+
5
+ /**
6
+ * @param {import('../init').Options} options
7
+ * @return { import('eslint').Linter.FlatConfig }
8
+ */
9
+ function tests(options = {}) {
10
+ return {
11
+ plugins: { 'jest-formatting': plugin },
12
+ files: [...globs.test, ...globs.e2e],
13
+ rules: {
14
+ 'jest-formatting/padding-around-after-all-blocks': 'warn',
15
+ 'jest-formatting/padding-around-after-each-blocks': 'warn',
16
+ 'jest-formatting/padding-around-before-all-blocks': 'warn',
17
+ 'jest-formatting/padding-around-before-each-blocks': 'warn',
18
+ 'jest-formatting/padding-around-describe-blocks': 'warn',
19
+ 'jest-formatting/padding-around-test-blocks': 'warn',
20
+
21
+ 'max-lines-per-function': 'off',
22
+ 'no-sparse-arrays': 'off',
23
+
24
+ ...predicate(options.fp, {
25
+ 'functional/no-let': 'off',
26
+ 'functional/no-loop-statements': 'off',
27
+ }),
28
+
29
+ ...predicate(options.react, {
30
+ 'react/jsx-no-constructed-context-values': 'off',
31
+ }),
32
+
33
+ ...predicate(options.typescript, {
34
+ '@typescript-eslint/method-signature-style': 'off',
35
+ '@typescript-eslint/no-namespace ': 'off',
36
+ '@typescript-eslint/unbound-method': 'off',
37
+ '@typescript-eslint/no-empty-function': 'off',
38
+ }),
39
+ },
40
+ };
41
+ }
42
+
43
+ module.exports = tests;