linter-bundle 2.0.0 → 2.4.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/CHANGELOG.md CHANGED
@@ -6,7 +6,88 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
- [Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v2.0.0...HEAD)
9
+ [Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v2.4.0...HEAD)
10
+
11
+ ## [2.4.0] - 2022.02.09
12
+
13
+ - [eslint] Updated `@typescript-eslint/eslint-plugin` from v5.10.1 to v5.11.0
14
+ - [eslint] Updated `eslint` from v8.7.0 to v8.8.0
15
+ - [eslint] Updated `eslint-plugin-functional` from v4.1.1 to v4.2.0
16
+ - [eslint] Updated `eslint-plugin-jest` from v26.0.0 to v26.1.0
17
+ - [eslint] Updated `eslint-plugin-jsdoc` from v37.7.0 to v37.8.1
18
+ - [markdownlint] Updated `markdownlint-cli` from v0.30.0 to v0.31.1, which adds the new rules `MD049` and `MD050` for consistent emphasis/strong style, and improves the rules `MD007`/`MD010`/`MD032`/`MD033`/`MD035`/`MD037`/`MD039`
19
+ - [stylelint] Updated `stylelint` from v14.3.0 to v14.4.0
20
+ - [eslint] Activated `unusedExports` option of the [`import/no-unused-modules`](https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-unused-modules.md) rule
21
+ - [eslint] Activate [`@typescript-eslint/explicit-function-return-type`](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/explicit-function-return-type.md) rule
22
+ - [eslint/react] Add React class methods (`componentDidMount`, `render` etc.) to the allowed names in the [`@typescript-eslint/explicit-function-return-type`](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/explicit-function-return-type.md) rule
23
+ - [eslint/jest] Make use of new [`no-conditional-in-test`](https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-conditional-in-test.md) rule, which deprecates `no-if`
24
+ - [eslint/jest] Make use of new [`prefer-snapshot-hint`](https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/prefer-snapshot-hint.md) rule
25
+ - [stylelint] Added but disabled new [`function-no-unknown`](https://github.com/stylelint/stylelint/blob/main/lib/rules/function-no-unknown/README.md) rule, because of false positives
26
+
27
+ [Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v2.3.1...v2.4.0)
28
+
29
+ ## [2.3.1] - 2022.01.28
30
+
31
+ ### Fixed
32
+
33
+ - [eslint/overrides-javascript(-lazy)] Move `import/no-import-module-exports` rule to`overrides-javascript`
34
+ - [eslint/overrides-gatsby] Ignore '@reach/router' in `import/no-unresolved` rule
35
+ - [eslint] Disabled `react/require-default-props`, because of false-positive for React.forwardRef wrapped functional components
36
+ - [eslint] Disabled `unicorn/prefer-top-level-await`, because of false-positive on environments with Node.js below v14.8
37
+ - [eslint] Activated `allowThrowingUnknown` option of the [`@typescript-eslint/no-throw-literal`](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-throw-literal.md) rule
38
+ - [stylelint] Activate `camelCaseSvgKeywords` option of the [`value-keyword-case`](https://github.com/stylelint/stylelint/tree/main/lib/rules/value-keyword-case) rule
39
+
40
+ [Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v2.3.0...v2.3.1)
41
+
42
+ ## [2.3.0] - 2022.01.27
43
+
44
+ ### Changed
45
+
46
+ - [eslint] In the `.vscode/settings.json` the "configFile" option in "eslint.options" has been renamed to "overrideConfigFile"
47
+ - [eslint] Re-added [`eslint-plugin-jsx-a11y`](https://www.npmjs.com/package/eslint-plugin-jsx-a11y) v6.5.1
48
+ - [eslint] Re-added [`eslint-plugin-promise`](https://www.npmjs.com/package/eslint-plugin-promise) v6.0.0
49
+ - [eslint] Re-added [`eslint-plugin-react`](https://www.npmjs.com/package/eslint-plugin-react) v7.28.0
50
+ - [stylelint] Re-added [`stylelint-declaration-block-no-ignored-properties`](https://www.npmjs.com/package/stylelint-declaration-block-no-ignored-properties) v2.5.0
51
+ - [eslint] Updated `eslint-plugin-react-hooks` from v4.2.1-alpha-13455d26d-20211104 to v4.3.0
52
+ - [eslint] Re-added [`react/no-invalid-html-attribute`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-invalid-html-attribute.md) rule
53
+ - [eslint] Re-added [`react/no-arrow-function-lifecycle`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-arrow-function-lifecycle.md) rule
54
+ - [eslint] Re-added [`react/no-unused-class-component-methods`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-unused-class-component-methods.md) rule
55
+ - [eslint] Disabled [`unicorn/prefer-object-has-own`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-object-has-own.md) for now, because of limited engine support
56
+ - [eslint] Disabled `allowThrowingAny` and `allowThrowingUnknown` of the [`@typescript-eslint/no-throw-literal`](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-throw-literal.md) rule
57
+ - [eslint] Reactivated [`import/no-import-module-exports`](https://github.com/import-js/eslint-plugin-import/blob/master/docs/rules/no-import-module-exports.md) rule
58
+ - [eslint] Added new [`import/no-unused-modules`](https://github.com/import-js/eslint-plugin-import/blob/master/docs/rules/no-unused-modules.md) rule
59
+ - [eslint] Added new [`jest/prefer-comparison-matcher`](https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/prefer-comparison-matcher.md) rule
60
+ - [eslint] Added new [`jest/prefer-equality-matcher`](https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/prefer-equality-matcher.md) rule
61
+ - [eslint] Added new [`unicorn/no-await-expression-member`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-await-expression-member.md) rule
62
+ - [eslint] Added new [`unicorn/prefer-code-point`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-code-point.md) rule
63
+ - [eslint] Added new [`unicorn/no-thenable`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-thenable.md) rule
64
+ - [eslint] Added new [`unicorn/no-useless-promise-resolve-reject`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-promise-resolve-reject.md) rule
65
+ - [eslint] Added new [`unicorn/relative-url-style`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/relative-url-style.md) rule
66
+ - [eslint] Added new [`unicorn/prefer-json-parse-buffer`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-json-parse-buffer.md) rule
67
+ - [eslint] Updated `@typescript-eslint` from v5.3.0 to v5.10.1
68
+ - [eslint] Updated `eslint` from v8.2.0 to v8.7.0
69
+ - [eslint] Updated `eslint-plugin-functional` from v4.0.2 to v4.1.1
70
+ - [eslint] Updated `eslint-plugin-import` from v2.25.2 to v2.25.4
71
+ - [eslint] Updated `eslint-plugin-jest` from v25.2.3 to v26.0.0
72
+ - [eslint] Updated `eslint-plugin-jsdoc` from v37.0.3 to v37.7.0
73
+ - [eslint] Updated `eslint-plugin-unicode` from v38.0.0 to v40.1.0
74
+ - [markdownlint] Updated `markdownlint-cli` from v0.29.0 to v0.30.0
75
+ - [stylelint] Updated `stylelint` from v14.0.1 to v14.3.0
76
+ - [stylelint] Updated `stylelint-scss` from v4.0.0 to v4.1.0
77
+ - [stylelint] Added new [`scss/dollar-variable-no-namespaced-assignment`](https://github.com/stylelint-scss/stylelint-scss/tree/master/src/rules/dollar-variable-no-namespaced-assignment) rule
78
+ - [stylelint] Added new [`scss/at-use-no-unnamespaced`](https://github.com/stylelint-scss/stylelint-scss/tree/master/src/rules/at-use-no-unnamespaced) rule
79
+ - [stylelint] Added but disabled [`rule-selector-property-disallowed-list`](https://github.com/stylelint/stylelint/tree/main/lib/rules/rule-selector-property-disallowed-list) rule
80
+
81
+ [Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v2.1.0...v2.3.0)
82
+
83
+ ## [2.1.0] - 2021.11.07
84
+
85
+ ### Changed
86
+
87
+ - [stylelint] Forked [`stylelint-high-performance-animation`](https://www.npmjs.com/package/stylelint-high-performance-animation), because it seems not to be regularly maintained anymore
88
+ - [eslint] Updated `eslint` from v8.1.0 to v8.2.0
89
+
90
+ [Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v2.0.0...v2.1.0)
10
91
 
11
92
  ## [2.0.0] - 2021.11.05
12
93
 
@@ -14,7 +95,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
14
95
 
15
96
  - [eslint] [`eslint-plugin-jsx-a11y`](https://www.npmjs.com/package/eslint-plugin-jsx-a11y) has been removed, because it seems not to be regularly maintained anymore, which blocks us from updating to ESLint v8
16
97
  - [eslint] [`eslint-plugin-promise`](https://www.npmjs.com/package/eslint-plugin-promise) has been removed, because it seems not to be regularly maintained anymore, which blocks us from updating to ESLint v8
17
- - [eslint] [`eslint-plugin-react`](https://www.npmjs.com/package/eslint-plugin-jsx-a11y) has been removed, because it's relying on unmaintained dependencies, which blocks us from updating to ESLint v8
98
+ - [eslint] [`eslint-plugin-react`](https://www.npmjs.com/package/eslint-plugin-react) has been removed, because it's relying on unmaintained dependencies, which blocks us from updating to ESLint v8
18
99
  - [stylelint] [`stylelint-declaration-block-no-ignored-properties`](https://www.npmjs.com/package/stylelint-declaration-block-no-ignored-properties) has been removed, because it seems not to be regularly maintained anymore, which blocks us from updating to Stylelint v14
19
100
  - [stylelint] [`stylelint-use-nesting`](https://www.npmjs.com/package/stylelint-use-nesting) has been removed, because it seems not to be regularly maintained anymore, which blocks us from updating to Stylelint v14
20
101
 
package/README.md CHANGED
@@ -28,8 +28,11 @@ This setup is using the following additional plugins:
28
28
  - [eslint-plugin-import](https://www.npmjs.com/package/eslint-plugin-import)
29
29
  - [eslint-plugin-jest](https://www.npmjs.com/package/eslint-plugin-jest)
30
30
  - [eslint-plugin-jsdoc](https://www.npmjs.com/package/eslint-plugin-jsdoc)
31
+ - [eslint-plugin-jsx-a11y](https://www.npmjs.com/package/eslint-plugin-jsx-a11y)
31
32
  - [eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node)
33
+ - [eslint-plugin-promise](https://www.npmjs.com/package/eslint-plugin-promise)
32
34
  - [eslint-plugin-react-hooks](https://www.npmjs.com/package/eslint-plugin-react-hooks)
35
+ - [eslint-plugin-react](https://www.npmjs.com/package/eslint-plugin-react)
33
36
  - [eslint-plugin-unicorn](https://www.npmjs.com/package/eslint-plugin-unicorn)
34
37
 
35
38
  Beside that, the following additional rules are part of this bundle:
@@ -38,22 +41,19 @@ Beside that, the following additional rules are part of this bundle:
38
41
 
39
42
  ### stylelint
40
43
 
41
- - [stylelint-high-performance-animation](https://www.npmjs.com/package/stylelint-high-performance-animation)
44
+ - [stylelint-declaration-block-no-ignored-properties](https://www.npmjs.com/package/stylelint-declaration-block-no-ignored-properties)
45
+ - [stylelint-high-performance-animation](https://www.npmjs.com/package/stylelint-high-performance-animation) (Forked version)
42
46
  - [stylelint-order](https://www.npmjs.com/package/stylelint-order)
43
47
  - [stylelint-scss](https://www.npmjs.com/package/stylelint-scss)
44
48
  - [stylelint-selector-no-empty](https://www.npmjs.com/package/stylelint-selector-no-empty)
45
- - [stylelint-use-logical-spec](https://www.npmjs.com/package/stylelint-use-logical-spec)
46
49
  - [stylelint-selector-tag-no-without-class](https://www.npmjs.com/package/stylelint-selector-tag-no-without-class) (Forked version)
50
+ - [stylelint-use-logical-spec](https://www.npmjs.com/package/stylelint-use-logical-spec)
47
51
 
48
52
  ### Previously used, but now unmaintained plugins
49
53
 
50
54
  Unfortunately a couple of previously used plugins are not regularly maintained or depend on unmaintained third-party code which blocks them from updating, so they don't provide updates for the major releases of the linters (ESLint and Stylelint).
51
55
  For that reason the following plugins are not used anymore:
52
56
 
53
- - [eslint-plugin-jsx-a11y](https://www.npmjs.com/package/eslint-plugin-jsx-a11y) (removed on 2021-11-05)
54
- - [eslint-plugin-promise](https://www.npmjs.com/package/eslint-plugin-promise) (removed on 2021-11-05)
55
- - [eslint-plugin-react](https://www.npmjs.com/package/eslint-plugin-react) (removed on 2021-11-05)
56
- - [stylelint-declaration-block-no-ignored-properties](https://www.npmjs.com/package/stylelint-declaration-block-no-ignored-properties) (removed on 2021-11-05)
57
57
  - [stylelint-use-nesting](https://www.npmjs.com/package/stylelint-use-nesting) (removed on 2021-11-05)
58
58
 
59
59
  If these plugins are maintained again, the plugins will also be used again.
@@ -318,7 +318,7 @@ This can be done by adding these options to your `.vscode/settings.json`:
318
318
  {
319
319
  "eslint.nodePath": "./node_modules/linter-bundle/node_modules/eslint",
320
320
  "eslint.options": {
321
- "configFile": "./.eslintrc.js",
321
+ "overrideConfigFile": "./.eslintrc.js",
322
322
  "resolvePluginsRelativeTo": "./node_modules/linter-bundle",
323
323
  "rulePaths": ["./node_modules/linter-bundle/eslint/rules"],
324
324
  "reportUnusedDisableDirectives": "error",
package/eslint/index.js CHANGED
@@ -22,7 +22,10 @@ module.exports = {
22
22
  'eslint-comments',
23
23
  'functional',
24
24
  'import',
25
+ 'jsx-a11y',
26
+ 'promise',
25
27
  'react-hooks',
28
+ 'react',
26
29
  'unicorn'
27
30
  ],
28
31
  extends: [
@@ -421,7 +424,7 @@ module.exports = {
421
424
  '@typescript-eslint/consistent-type-exports': 'error',
422
425
  '@typescript-eslint/consistent-type-imports': ['error', { disallowTypeAnnotations: false }],
423
426
  '@typescript-eslint/dot-notation': 'error',
424
- '@typescript-eslint/explicit-function-return-type': 'off', // @todo Disabled till we can specify exceptions (React-default class methods, like render())
427
+ '@typescript-eslint/explicit-function-return-type': 'error',
425
428
  '@typescript-eslint/explicit-member-accessibility': ['error', {
426
429
  ignoredMethodNames: [
427
430
  'constructor',
@@ -639,7 +642,10 @@ module.exports = {
639
642
  '@typescript-eslint/no-require-imports': 'error',
640
643
  '@typescript-eslint/no-shadow': 'error',
641
644
  '@typescript-eslint/no-this-alias': 'error',
642
- '@typescript-eslint/no-throw-literal': 'error',
645
+ '@typescript-eslint/no-throw-literal': ['error', {
646
+ allowThrowingAny: false,
647
+ allowThrowingUnknown: true
648
+ }],
643
649
  '@typescript-eslint/no-type-alias': ['off', { // @todo There should be an option like 'sub-in-unions-and-intersections', which allows `type A = (string | number)[];`
644
650
  allowAliases: 'always',
645
651
  allowCallbacks: 'always',
@@ -764,7 +770,7 @@ module.exports = {
764
770
  'workbox-window/utils/WorkboxEvent'
765
771
  ]
766
772
  }],
767
- 'import/no-import-module-exports': 'off', // @todo The rule reports files, which don't use `exports`. This must be a bug, report it!
773
+ 'import/no-import-module-exports': 'off', // Activated only for JavaScript files
768
774
  'import/no-mutable-exports': 'error',
769
775
  'import/no-named-as-default-member': 'error',
770
776
  'import/no-named-as-default': 'error',
@@ -783,7 +789,7 @@ module.exports = {
783
789
  ]
784
790
  }],
785
791
  'import/no-unresolved': ['error', { caseSensitiveStrict: true }],
786
- 'import/no-unused-modules': 'error',
792
+ 'import/no-unused-modules': ['error', { unusedExports: true }],
787
793
  'import/no-useless-path-segments': 'error',
788
794
  'import/no-webpack-loader-syntax': 'off', // Indeed, you should avoid that, but if we do it, we have a reason for it
789
795
  'import/order': ['error', {
@@ -809,6 +815,43 @@ module.exports = {
809
815
  'import/prefer-default-export': 'off',
810
816
  'import/unambiguous': 'off',
811
817
 
818
+ /**
819
+ * eslint-plugin-jsx-a11y
820
+ *
821
+ * @see https://github.com/jsx-eslint/eslint-plugin-jsx-a11y
822
+ */
823
+ 'jsx-a11y/alt-text': 'error',
824
+ 'jsx-a11y/anchor-has-content': 'error',
825
+ 'jsx-a11y/anchor-is-valid': 'error',
826
+ 'jsx-a11y/aria-activedescendant-has-tabindex': 'error',
827
+ 'jsx-a11y/aria-props': 'error',
828
+ 'jsx-a11y/aria-proptypes': 'error',
829
+ 'jsx-a11y/aria-role': 'error',
830
+ 'jsx-a11y/aria-unsupported-elements': 'error',
831
+ 'jsx-a11y/autocomplete-valid': 'error',
832
+ 'jsx-a11y/click-events-have-key-events': 'error',
833
+ 'jsx-a11y/heading-has-content': 'error',
834
+ 'jsx-a11y/html-has-lang': 'off', // <html> elements set by react-helmet automatically have a lang attribute set
835
+ 'jsx-a11y/iframe-has-title': 'error',
836
+ 'jsx-a11y/img-redundant-alt': 'error',
837
+ 'jsx-a11y/interactive-supports-focus': 'error',
838
+ 'jsx-a11y/label-has-associated-control': 'error',
839
+ 'jsx-a11y/media-has-caption': 'error',
840
+ 'jsx-a11y/mouse-events-have-key-events': 'error',
841
+ 'jsx-a11y/no-access-key': 'off', // If you explicitly specify an access key, you usually have a reason for this, so it should not be prevented by a rule
842
+ 'jsx-a11y/no-autofocus': ['error', { ignoreNonDOM: true }],
843
+ 'jsx-a11y/no-distracting-elements': 'error',
844
+ 'jsx-a11y/no-interactive-element-to-noninteractive-role': 'error',
845
+ 'jsx-a11y/no-noninteractive-element-interactions': 'error',
846
+ 'jsx-a11y/no-noninteractive-element-to-interactive-role': 'error',
847
+ 'jsx-a11y/no-noninteractive-tabindex': 'error',
848
+ 'jsx-a11y/no-redundant-roles': 'error',
849
+ 'jsx-a11y/no-static-element-interactions': 'error',
850
+ 'jsx-a11y/role-has-required-aria-props': 'error',
851
+ 'jsx-a11y/role-supports-aria-props': 'error',
852
+ 'jsx-a11y/scope': 'error',
853
+ 'jsx-a11y/tabindex-no-positive': 'error',
854
+
812
855
  /**
813
856
  * eslint-plugin-eslint-comments
814
857
  *
@@ -824,6 +867,26 @@ module.exports = {
824
867
  'eslint-comments/no-use': 'off',
825
868
  'eslint-comments/require-description': ['error', { ignore: ['eslint-enable'] }],
826
869
 
870
+ /**
871
+ * eslint-plugin-promise
872
+ *
873
+ * @see https://github.com/xjamundx/eslint-plugin-promise
874
+ */
875
+ 'promise/always-return': 'off', // If the result of an `.then()` is not used, there is no need to return something.
876
+ 'promise/avoid-new': 'off',
877
+ 'promise/catch-or-return': 'error',
878
+ 'promise/no-callback-in-promise': 'off',
879
+ 'promise/no-native': 'off',
880
+ 'promise/no-nesting': 'off',
881
+ 'promise/no-new-statics': 'error',
882
+ 'promise/no-promise-in-callback': 'off',
883
+ 'promise/no-return-in-finally': 'error',
884
+ 'promise/no-return-wrap': 'error',
885
+ 'promise/param-names': 'off', // @todo Disabled until this issue is fixed: https://github.com/xjamundx/eslint-plugin-promise/issues/206
886
+ 'promise/prefer-await-to-callbacks': 'off', // It's not always possible to use avoid callbacks.
887
+ 'promise/prefer-await-to-then': 'off', // Depending on the use-case `.then()`/`.catch()` might be easier to understand
888
+ 'promise/valid-params': 'off', // TypeScript ensures that
889
+
827
890
  /**
828
891
  * eslint-plugin-unicorn
829
892
  *
@@ -852,11 +915,12 @@ module.exports = {
852
915
  'unicorn/import-style': 'error',
853
916
  'unicorn/new-for-builtins': 'error',
854
917
  'unicorn/no-abusive-eslint-disable': 'error',
855
- 'unicorn/no-array-callback-reference': 'off', // If I use functions, they are specially developed for this use-case
918
+ 'unicorn/no-array-callback-reference': 'off', // If I use functions, they are the best option for this use-case
856
919
  'unicorn/no-array-for-each': 'error',
857
920
  'unicorn/no-array-method-this-argument': 'error',
858
921
  'unicorn/no-array-push-push': 'error',
859
922
  'unicorn/no-array-reduce': ['error', { allowSimpleOperations: true }],
923
+ 'unicorn/no-await-expression-member': 'error',
860
924
  'unicorn/no-console-spaces': 'error',
861
925
  'unicorn/no-document-cookie': 'error',
862
926
  'unicorn/no-empty-file': 'error',
@@ -872,11 +936,13 @@ module.exports = {
872
936
  'unicorn/no-object-as-default-parameter': 'error',
873
937
  'unicorn/no-process-exit': 'error',
874
938
  'unicorn/no-static-only-class': 'error',
939
+ 'unicorn/no-thenable': 'error',
875
940
  'unicorn/no-this-assignment': 'error',
876
941
  'unicorn/no-unreadable-array-destructuring': 'error',
877
942
  'unicorn/no-unsafe-regex': 'off',
878
943
  'unicorn/no-unused-properties': 'error',
879
944
  'unicorn/no-useless-fallback-in-spread': 'error',
945
+ 'unicorn/no-useless-promise-resolve-reject': 'error',
880
946
  'unicorn/no-invalid-remove-event-listener': 'error',
881
947
  'unicorn/no-useless-length-check': 'error',
882
948
  'unicorn/no-useless-spread': 'error',
@@ -891,6 +957,7 @@ module.exports = {
891
957
  'unicorn/prefer-array-index-of': 'error',
892
958
  'unicorn/prefer-array-some': 'error',
893
959
  'unicorn/prefer-at': 'off', // @todo Disabled for now, since `at` is not supported by TypeScript type definitions yet.
960
+ 'unicorn/prefer-code-point': 'error',
894
961
  'unicorn/prefer-date-now': 'error',
895
962
  'unicorn/prefer-default-parameters': 'error',
896
963
  'unicorn/prefer-dom-node-append': 'error',
@@ -899,13 +966,14 @@ module.exports = {
899
966
  'unicorn/prefer-dom-node-text-content': 'error',
900
967
  'unicorn/prefer-export-from': 'error',
901
968
  'unicorn/prefer-includes': 'error',
969
+ 'unicorn/prefer-json-parse-buffer': 'error',
902
970
  'unicorn/prefer-keyboard-event-key': 'error',
903
971
  'unicorn/prefer-math-trunc': 'error',
904
972
  'unicorn/prefer-modern-dom-apis': 'error',
905
973
  'unicorn/prefer-module': 'off',
906
974
  'unicorn/prefer-negative-index': 'error',
907
975
  'unicorn/prefer-number-properties': 'error',
908
- 'unicorn/prefer-object-has-own': 'error',
976
+ 'unicorn/prefer-object-has-own': 'off', // Not widely supported yet. Can be activated in 2024
909
977
  'unicorn/prefer-object-from-entries': 'error',
910
978
  'unicorn/prefer-optional-catch-binding': 'error',
911
979
  'unicorn/prefer-prototype-methods': 'error',
@@ -919,10 +987,11 @@ module.exports = {
919
987
  'unicorn/prefer-string-trim-start-end': 'error',
920
988
  'unicorn/prefer-switch': 'error',
921
989
  'unicorn/prefer-ternary': 'off', // We prefer readability over saving a few chars
922
- 'unicorn/prefer-top-level-await': 'error',
990
+ 'unicorn/prefer-top-level-await': 'off', // @todo There should be a detection that this option is only activated on Node.js v14.8 environments and above (Check for "engine" property in package.json, and "node -v")
923
991
  'unicorn/prefer-regexp-test': 'error',
924
992
  'unicorn/prefer-type-error': 'error',
925
993
  'unicorn/prevent-abbreviations': ['error', { ignore: ['args', 'i', 'j', 'i18n', 'ref', 'Ref', 'params', 'props', 'Props'] }],
994
+ 'unicorn/relative-url-style': 'error',
926
995
  'unicorn/require-array-join-separator': 'error',
927
996
  'unicorn/require-number-to-fixed-digits-argument': 'error',
928
997
  'unicorn/require-post-message-target-origin': 'off', // False-positive with Workers which don't support a `targetOrigin`
@@ -33,6 +33,13 @@ module.exports = {
33
33
  */
34
34
  '@typescript-eslint/no-confusing-void-expression': 'off', // @todo Conflicts with graphql-template strings
35
35
 
36
+ /**
37
+ * eslint-plugin-import
38
+ *
39
+ * @see https://github.com/import-js/eslint-plugin-import
40
+ */
41
+ 'import/no-unresolved': ['error', { caseSensitiveStrict: true, ignore: ['@reach/router'] }],
42
+
36
43
  /**
37
44
  * eslint-plugin-unicorn
38
45
  *
@@ -42,6 +42,7 @@ module.exports = {
42
42
  * @see https://github.com/import-js/eslint-plugin-import
43
43
  */
44
44
  'import/no-commonjs': 'off',
45
+ 'import/no-import-module-exports': 'error',
45
46
  'import/no-internal-modules': 'off',
46
47
  'import/no-nodejs-modules': 'off',
47
48
 
@@ -66,6 +66,7 @@ module.exports = {
66
66
  'jest/no-alias-methods': 'error',
67
67
  'jest/no-commented-out-tests': 'error',
68
68
  'jest/no-conditional-expect': 'error',
69
+ 'jest/no-conditional-in-test': 'error',
69
70
  'jest/no-deprecated-functions': 'error',
70
71
  'jest/no-disabled-tests': 'error',
71
72
  'jest/no-done-callback': 'error',
@@ -74,7 +75,6 @@ module.exports = {
74
75
  'jest/no-focused-tests': 'error',
75
76
  'jest/no-hooks': ['error', { allow: ['beforeEach', 'afterEach', 'afterAll'] }],
76
77
  'jest/no-identical-title': 'error',
77
- 'jest/no-if': 'error',
78
78
  'jest/no-interpolation-in-snapshots': 'error',
79
79
  'jest/no-jasmine-globals': 'error',
80
80
  'jest/no-jest-import': 'error',
@@ -88,6 +88,9 @@ module.exports = {
88
88
  'jest/prefer-expect-resolves': 'off', // We prefer `expect(await promise)` enforced by 'jest/no-restricted-matchers'
89
89
  'jest/prefer-hooks-on-top': 'error',
90
90
  'jest/require-hook': 'error',
91
+ 'jest/prefer-comparison-matcher': 'error',
92
+ 'jest/prefer-equality-matcher': 'error',
93
+ 'jest/prefer-snapshot-hint': 'error',
91
94
  'jest/prefer-spy-on': 'error',
92
95
  'jest/prefer-strict-equal': 'error',
93
96
  'jest/prefer-to-be': 'error',
@@ -24,8 +24,8 @@ module.exports = {
24
24
  */
25
25
  'jsdoc/check-access': 'error',
26
26
  'jsdoc/check-alignment': 'error',
27
- 'jsdoc/check-examples': 'off', // @todo need to be configured to allow text-based examples
28
- 'jsdoc/check-indentation': ['off', { excludeTags: ['typedef'] }],
27
+ 'jsdoc/check-examples': 'off', // @todo Need to be configured to allow text-based examples
28
+ 'jsdoc/check-indentation': ['off', { excludeTags: ['typedef'] }], // @todo Why is this disabled?
29
29
  'jsdoc/check-param-names': 'error',
30
30
  'jsdoc/check-syntax': 'error',
31
31
  'jsdoc/check-line-alignment': 'error',
@@ -2,6 +2,8 @@
2
2
  * @file Settings for React code in TypeScript (TSX) files.
3
3
  */
4
4
 
5
+ const ensureType = require('../helper/ensure-type');
6
+
5
7
  module.exports = {
6
8
  overrides: [
7
9
  {
@@ -13,6 +15,19 @@ module.exports = {
13
15
  * @see https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules
14
16
  */
15
17
  '@typescript-eslint/member-ordering': 'off', // For React components we are using react/sort-comp
18
+ '@typescript-eslint/explicit-function-return-type': ['error', {
19
+ allowedNames: [
20
+ 'componentDidCatch',
21
+ 'componentDidMount',
22
+ 'componentDidUpdate',
23
+ 'componentWillUnmount',
24
+ 'getDerivedStateFromError',
25
+ 'getDerivedStateFromProps',
26
+ 'getSnapshotBeforeUpdate',
27
+ 'render',
28
+ 'shouldComponentUpdate'
29
+ ]
30
+ }],
16
31
 
17
32
  /**
18
33
  * eslint-plugin-react-hooks
@@ -21,7 +36,143 @@ module.exports = {
21
36
  * @see https://reactjs.org/docs/hooks-rules.html
22
37
  */
23
38
  'react-hooks/rules-of-hooks': 'error',
24
- 'react-hooks/exhaustive-deps': 'error'
39
+ 'react-hooks/exhaustive-deps': 'error',
40
+
41
+ /**
42
+ * eslint-plugin-react
43
+ *
44
+ * @see https://github.com/yannickcr/eslint-plugin-react
45
+ */
46
+ 'react/boolean-prop-naming': 'error',
47
+ 'react/button-has-type': 'error',
48
+ 'react/default-props-match-prop-types': 'error',
49
+ 'react/destructuring-assignment': 'off', // Sometimes destructuring makes sense, sometimes it doesn't - that depends on the context.
50
+ 'react/display-name': 'error',
51
+ 'react/forbid-component-props': ['error', { forbid: [
52
+ {
53
+ propName: 'className',
54
+ allowedFor: ensureType.array(global.linterBundleSettings?.overrides?.react?.['react/forbid-component-props']?.allowClassNameFor)
55
+ },
56
+ {
57
+ propName: 'style',
58
+ allowedFor: ensureType.array(global.linterBundleSettings?.overrides?.react?.['react/forbid-component-props']?.allowStyleFor)
59
+ }
60
+ ] }],
61
+ 'react/forbid-dom-props': 'error',
62
+ 'react/forbid-elements': 'error',
63
+ 'react/forbid-prop-types': 'error',
64
+ 'react/forbid-foreign-prop-types': 'error',
65
+ 'react/function-component-definition': ['off', { // @todo Doesn't work with Component-Factories, which shall return named components `return function MyComponent () {}`, while in modules, `const MyComponent = () => {}` shall be used
66
+ namedComponents: 'arrow-function',
67
+ unnamedComponents: 'arrow-function'
68
+ }],
69
+ 'react/no-access-state-in-setstate': 'error',
70
+ 'react/no-array-index-key': 'error',
71
+ 'react/no-arrow-function-lifecycle': 'error',
72
+ 'react/no-children-prop': 'error',
73
+ 'react/no-danger': 'off',
74
+ 'react/no-danger-with-children': 'error',
75
+ 'react/no-deprecated': 'error',
76
+ 'react/no-did-mount-set-state': 'error',
77
+ 'react/no-did-update-set-state': 'error',
78
+ 'react/no-direct-mutation-state': 'error',
79
+ 'react/no-find-dom-node': 'error',
80
+ 'react/no-invalid-html-attribute': 'error',
81
+ 'react/no-is-mounted': 'error',
82
+ 'react/no-multi-comp': 'error',
83
+ 'react/no-namespace': 'error',
84
+ 'react/no-redundant-should-component-update': 'error',
85
+ 'react/no-render-return-value': 'error',
86
+ 'react/no-set-state': 'off',
87
+ 'react/no-typos': 'error',
88
+ 'react/no-string-refs': 'error',
89
+ 'react/no-this-in-sfc': 'error',
90
+ 'react/no-unescaped-entities': 'error',
91
+ 'react/no-unknown-property': 'error',
92
+ 'react/no-unsafe': 'error',
93
+ 'react/no-unstable-nested-components': 'error',
94
+ 'react/no-unused-class-component-methods': 'error',
95
+ 'react/no-unused-prop-types': 'error',
96
+ 'react/no-unused-state': 'error',
97
+ 'react/no-will-update-set-state': 'error',
98
+ 'react/prefer-es6-class': 'error',
99
+ 'react/prefer-exact-props': 'off', // With TypeScript interfaces, this rule is not required
100
+ 'react/prefer-read-only-props': 'error',
101
+ 'react/prefer-stateless-function': 'error',
102
+ 'react/prop-types': 'off',
103
+ 'react/react-in-jsx-scope': 'error',
104
+ 'react/require-default-props': ['off', { forbidDefaultForRequired: true, ignoreFunctionalComponents: true }], // @see https://medium.com/@matanbobi/react-defaultprops-is-dying-whos-the-contender-443c19d9e7f1 @todo Also disabled becaues of false-positive with React.forwardRef(), create bug report?
105
+ 'react/require-optimization': 'error',
106
+ 'react/require-render-return': 'error',
107
+ 'react/self-closing-comp': 'error',
108
+ 'react/sort-comp': ['error', {
109
+ order: [
110
+ 'type-annotations',
111
+ 'static-variables',
112
+ 'instance-variables',
113
+ 'getters',
114
+ 'setters',
115
+ 'lifecycle',
116
+ 'render',
117
+ '/^render.+$/',
118
+ '/^handle.+$/',
119
+ 'everything-else',
120
+ 'instance-methods',
121
+ 'static-methods'
122
+ ]
123
+ }],
124
+ 'react/sort-prop-types': 'error',
125
+ 'react/state-in-constructor': 'error',
126
+ 'react/static-property-placement': 'error',
127
+ 'react/style-prop-object': 'error',
128
+ 'react/void-dom-elements-no-children': 'error',
129
+
130
+ // JSX-specific rules
131
+ 'react/jsx-boolean-value': ['error', 'always'],
132
+ 'react/jsx-child-element-spacing': 'off', // @todo Why is this disabled? Could it be, that the faulty behaviour is fixed in the meantime?
133
+ 'react/jsx-closing-bracket-location': 'error',
134
+ 'react/jsx-closing-tag-location': 'error',
135
+ 'react/jsx-curly-newline': 'off',
136
+ 'react/jsx-curly-spacing': 'error',
137
+ 'react/jsx-equals-spacing': 'error',
138
+ 'react/jsx-filename-extension': ['error', { extensions: ['.tsx'] }],
139
+ 'react/jsx-first-prop-new-line': 'error',
140
+ 'react/jsx-handler-names': 'off', // @todo There should be an option which checks if the function is used multiple times in a class (like this.closeTooltip()) - in that case, the 'handle' prefix should not be mandatory
141
+ 'react/jsx-indent': ['error', 'tab', { checkAttributes: true, indentLogicalExpressions: true }],
142
+ 'react/jsx-indent-props': ['error', 'tab'],
143
+ 'react/jsx-key': ['error', { checkKeyMustBeforeSpread: true }],
144
+ 'react/jsx-max-depth': ['error', { max: 8 }],
145
+ 'react/jsx-max-props-per-line': ['error', { maximum: { single: 5, multi: 1 } }],
146
+ 'react/no-adjacent-inline-elements': 'off', // @todo There is an issue if inline and block elements are mixed. Simple example: `<span>Text</span><br />` here, the space between the SPAN and BR should not be forced, because a space at the end of a line does not make sense.
147
+ 'react/jsx-newline': 'off',
148
+ 'react/jsx-no-bind': ['error', { ignoreDOMComponents: true }],
149
+ 'react/jsx-no-comment-textnodes': 'error',
150
+ 'react/jsx-no-constructed-context-values': 'error',
151
+ 'react/jsx-no-duplicate-props': 'error',
152
+ 'react/jsx-no-literals': 'off',
153
+ 'react/jsx-no-script-url': 'error',
154
+ 'react/jsx-no-target-blank': ['error', { allowReferrer: true, forms: true }],
155
+ 'react/jsx-no-undef': 'error',
156
+ 'react/jsx-no-useless-fragment': 'error',
157
+ 'react/jsx-one-expression-per-line': ['off', { allow: 'single-child' }], // @todo Doesn't work with something like "Text <a href="...">Link</a> More Text", which should be valid
158
+ 'react/jsx-curly-brace-presence': 'error',
159
+ 'react/jsx-fragments': ['error', 'element'],
160
+ 'react/jsx-pascal-case': ['error', { allowAllCaps: true }],
161
+ 'react/jsx-props-no-multi-spaces': 'error',
162
+ 'react/jsx-props-no-spreading': 'off',
163
+ 'react/jsx-sort-default-props': 'error',
164
+ 'react/jsx-sort-props': ['error', {
165
+ ignoreCase: true,
166
+ callbacksLast: true,
167
+ shorthandFirst: true,
168
+ shorthandLast: false,
169
+ noSortAlphabetically: true,
170
+ reservedFirst: true
171
+ }],
172
+ 'react/jsx-tag-spacing': 'error',
173
+ 'react/jsx-uses-react': 'error',
174
+ 'react/jsx-uses-vars': 'error',
175
+ 'react/jsx-wrap-multilines': 'error'
25
176
  }
26
177
  }
27
178
  ]
@@ -21,6 +21,7 @@ module.exports = {
21
21
  * @see https://github.com/import-js/eslint-plugin-import
22
22
  */
23
23
  'import/no-default-export': 'off',
24
+ 'import/no-unused-modules': 'off',
24
25
 
25
26
  /**
26
27
  * eslint-plugin-unicorn
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linter-bundle",
3
- "version": "2.0.0",
3
+ "version": "2.4.0",
4
4
  "description": "Ready-to use bundle of linting tools, containing configurations for ESLint, stylelint and markdownlint.",
5
5
  "keywords": [
6
6
  "eslint",
@@ -33,38 +33,45 @@
33
33
  "publish:minor": "npm version minor",
34
34
  "publish:patch": "npm version patch",
35
35
  "lint": "node ./lint tsc ts md audit --min-severity=critical",
36
- "preversion": "npm run check-outdated && npm run lint",
36
+ "preversion": "npm run check-outdated && npm run stylelint-find-rules && npm run lint",
37
37
  "postversion": "git push && git push --tags && npm publish",
38
+ "stylelint-find-rules": "stylelint-find-new-rules ./stylelint/index.js",
38
39
  "check-outdated": "npx --yes -- check-outdated --ignore-pre-releases"
39
40
  },
40
41
  "dependencies": {
41
- "@typescript-eslint/eslint-plugin": "5.3.0",
42
- "@typescript-eslint/parser": "5.3.0",
43
- "eslint": "8.1.0",
42
+ "@typescript-eslint/eslint-plugin": "5.11.0",
43
+ "@typescript-eslint/parser": "5.11.0",
44
+ "eslint": "8.8.0",
44
45
  "eslint-import-resolver-typescript": "2.5.0",
45
46
  "eslint-import-resolver-webpack": "0.13.2",
46
47
  "eslint-plugin-eslint-comments": "3.2.0",
47
- "eslint-plugin-functional": "4.0.2",
48
- "eslint-plugin-import": "2.25.2",
49
- "eslint-plugin-jest": "25.2.3",
50
- "eslint-plugin-jsdoc": "37.0.3",
48
+ "eslint-plugin-functional": "4.2.0",
49
+ "eslint-plugin-import": "2.25.4",
50
+ "eslint-plugin-jest": "26.1.0",
51
+ "eslint-plugin-jsdoc": "37.8.1",
52
+ "eslint-plugin-jsx-a11y": "6.5.1",
51
53
  "eslint-plugin-node": "11.1.0",
52
- "eslint-plugin-react-hooks": "4.2.1-alpha-13455d26d-20211104",
53
- "eslint-plugin-unicorn": "38.0.0",
54
- "markdownlint-cli": "0.29.0",
55
- "postcss-scss": "4.0.2",
56
- "stylelint": "14.0.1",
54
+ "eslint-plugin-promise": "6.0.0",
55
+ "eslint-plugin-react": "7.28.0",
56
+ "eslint-plugin-react-hooks": "4.3.0",
57
+ "eslint-plugin-unicorn": "40.1.0",
58
+ "markdownlint-cli": "0.31.1",
59
+ "postcss-scss": "4.0.3",
60
+ "stylelint": "14.4.0",
61
+ "stylelint-declaration-block-no-ignored-properties": "2.5.0",
57
62
  "stylelint-order": "5.0.0",
58
- "stylelint-scss": "4.0.0",
63
+ "stylelint-scss": "4.1.0",
59
64
  "stylelint-selector-no-empty": "1.0.8",
60
65
  "stylelint-use-logical-spec": "3.2.2"
61
66
  },
62
67
  "peerDependencies": {
63
- "typescript": "^4.0.0"
68
+ "typescript": "^4.0.0",
69
+ "postcss-value-parser": "*"
64
70
  },
65
71
  "devDependencies": {
66
- "@types/eslint": "7.28.2",
67
- "@types/node": "16.11.6",
68
- "typescript": "4.4.4"
72
+ "@types/eslint": "8.4.1",
73
+ "@types/node": "17.0.16",
74
+ "stylelint-find-new-rules": "^3.0.4",
75
+ "typescript": "4.5.5"
69
76
  }
70
77
  }
@@ -4,18 +4,21 @@
4
4
 
5
5
  /* eslint-disable max-lines -- The rules can be easier managed if they are all in one file */
6
6
 
7
+ const path = require('path');
8
+
7
9
  module.exports = {
8
10
  reportNeedlessDisables: true,
9
11
  reportInvalidScopeDisables: true,
10
12
  reportDescriptionlessDisables: true,
11
13
  customSyntax: 'postcss-scss',
12
14
  plugins: [
13
- 'stylelint-high-performance-animation',
15
+ 'stylelint-declaration-block-no-ignored-properties',
14
16
  'stylelint-order',
15
17
  'stylelint-scss',
16
18
  'stylelint-selector-no-empty',
17
19
  'stylelint-use-logical-spec',
18
- './plugins/stylelint-selector-tag-no-without-class.js'
20
+ path.join(__dirname, '/plugins/stylelint-high-performance-animation.js'),
21
+ path.join(__dirname, '/plugins/stylelint-selector-tag-no-without-class.js')
19
22
  ],
20
23
  overrides: [
21
24
  {
@@ -180,6 +183,7 @@ module.exports = {
180
183
  'function-linear-gradient-no-nonstandard-direction': true,
181
184
  'function-max-empty-lines': 0,
182
185
  'function-name-case': 'lower',
186
+ 'function-no-unknown': false, // @todo Create issue for false positives for "color.scale"
183
187
  'function-parentheses-newline-inside': 'always-multi-line',
184
188
  'function-parentheses-space-inside': 'never-single-line',
185
189
  'function-url-no-scheme-relative': true,
@@ -240,6 +244,7 @@ module.exports = {
240
244
  ],
241
245
  'property-no-unknown': true,
242
246
  'property-no-vendor-prefix': true,
247
+ 'rule-selector-property-disallowed-list': null,
243
248
  'rule-empty-line-before': [
244
249
  'always-multi-line',
245
250
  {
@@ -305,7 +310,12 @@ module.exports = {
305
310
  'unit-case': 'lower',
306
311
  'unit-disallowed-list': null,
307
312
  'unit-no-unknown': true,
308
- 'value-keyword-case': 'lower',
313
+ 'value-keyword-case': [
314
+ 'lower',
315
+ {
316
+ camelCaseSvgKeywords: true
317
+ }
318
+ ],
309
319
  'value-list-comma-newline-after': 'always-multi-line',
310
320
  'value-list-comma-newline-before': 'never-multi-line',
311
321
  'value-list-comma-space-after': 'always-single-line',
@@ -313,6 +323,13 @@ module.exports = {
313
323
  'value-list-max-empty-lines': 0,
314
324
  'value-no-vendor-prefix': true,
315
325
 
326
+ /**
327
+ * stylelint-declaration-block-no-ignored-properties
328
+ *
329
+ * @see https://www.npmjs.com/package/stylelint-declaration-block-no-ignored-properties
330
+ */
331
+ 'plugin/declaration-block-no-ignored-properties': true,
332
+
316
333
  /**
317
334
  * stylelint-high-performance-animation
318
335
  *
@@ -837,6 +854,7 @@ module.exports = {
837
854
  'scss/at-mixin-pattern': '^[a-z]+(-[a-z]+)*$',
838
855
  'scss/at-rule-conditional-no-parentheses': true,
839
856
  'scss/at-rule-no-unknown': true,
857
+ 'scss/at-use-no-unnamespaced': true,
840
858
  'scss/comment-no-empty': true,
841
859
  'scss/comment-no-loud': true,
842
860
  'scss/declaration-nested-properties-no-divided-groups': true,
@@ -860,6 +878,7 @@ module.exports = {
860
878
  ],
861
879
  'scss/dollar-variable-first-in-block': [true, { ignore: ['comments', 'imports'] }],
862
880
  'scss/dollar-variable-no-missing-interpolation': true,
881
+ 'scss/dollar-variable-no-namespaced-assignment': true,
863
882
  'scss/dollar-variable-pattern': '^[a-z]+(-[a-z]+)*$',
864
883
  'scss/double-slash-comment-empty-line-before': [
865
884
  'always',
@@ -0,0 +1,273 @@
1
+ /**
2
+ * @file Fork of `stylelint-high-performance-animation` rule.
3
+ *
4
+ * @license MIT
5
+ * @see https://github.com/kristerkari/stylelint-high-performance-animation
6
+ */
7
+
8
+ const valueParser = require('postcss-value-parser');
9
+ /** @type {(declaration: import('postcss').Declaration) => number} */
10
+ // @ts-expect-error -- No declaration file.
11
+ const declarationValueIndex = require('stylelint/lib/utils/declarationValueIndex');
12
+
13
+ const stylelint = require('stylelint');
14
+
15
+ const ruleName = 'plugin/no-low-performance-animation-properties';
16
+
17
+ const messages = stylelint.utils.ruleMessages(ruleName, {
18
+ rejected: (type, property) => `Unexpected use of low performance ${type} property (${property}).`
19
+ });
20
+
21
+ /**
22
+ * Function which ensures that a given `value` is of type "string".
23
+ *
24
+ * @param {any} value - Any value which should be ensured to be a string.
25
+ * @returns {boolean} - True if the value is a string, false otherwise.
26
+ */
27
+ const isString = (value) => (typeof value === 'string');
28
+
29
+ // https://drafts.csswg.org/css-timing/
30
+ const cssLinearTimingFunctions = ['linear'];
31
+ const cssCubicBezierTimingFunctions = [
32
+ 'ease',
33
+ 'ease-in',
34
+ 'ease-out',
35
+ 'ease-in-out',
36
+ 'cubic-bezier'
37
+ ];
38
+ const cssStepTimingFunctions = ['step-start', 'step-end', 'steps'];
39
+ const cssFramesTimingFunctions = ['frames'];
40
+ const cssTimingFunctions = [
41
+ ...cssLinearTimingFunctions,
42
+ ...cssCubicBezierTimingFunctions,
43
+ ...cssStepTimingFunctions,
44
+ ...cssFramesTimingFunctions
45
+ ];
46
+ const cssTimingFunctionsRE = new RegExp(`^(${cssTimingFunctions.join('|')}).*`, 'u');
47
+
48
+ const propertiesThatCauseLayout = [
49
+ 'position',
50
+ 'top',
51
+ 'bottom',
52
+ 'left',
53
+ 'right',
54
+ 'width',
55
+ 'height',
56
+ 'min-height',
57
+ 'max-height',
58
+ 'max-width',
59
+ 'min-width',
60
+ 'padding',
61
+ 'padding-bottom',
62
+ 'padding-left',
63
+ 'padding-right',
64
+ 'padding-top',
65
+ 'margin',
66
+ 'margin-bottom',
67
+ 'margin-left',
68
+ 'margin-right',
69
+ 'margin-top',
70
+ 'display',
71
+ 'border-width',
72
+ 'border-spacing',
73
+ 'border-collapse',
74
+ 'border',
75
+ 'font',
76
+ 'font-size',
77
+ 'font-family',
78
+ 'font-weight',
79
+ 'font-style',
80
+ 'float',
81
+ 'overflow-y',
82
+ 'overflow-x',
83
+ 'overflow',
84
+ 'line-height',
85
+ 'vertical-align',
86
+ 'clear',
87
+ 'white-space',
88
+ 'list-style',
89
+ 'list-style-type',
90
+ 'zoom',
91
+ 'content',
92
+ 'box-sizing',
93
+ 'text-shadow',
94
+ 'text-align',
95
+ 'text-indent',
96
+ 'text-transform',
97
+ 'text-overflow',
98
+ 'word-wrap',
99
+ 'letter-spacing',
100
+ 'appearance',
101
+ 'direction'
102
+ ];
103
+
104
+ const propsThatCausePaint = [
105
+ 'color',
106
+ 'border-color',
107
+ 'border-style',
108
+ 'border-radius',
109
+ 'visibility',
110
+ 'text-decoration',
111
+ 'background',
112
+ 'background-color',
113
+ 'background-size',
114
+ 'background-image',
115
+ 'background-position',
116
+ 'background-repeat',
117
+ 'outline',
118
+ 'outline-style',
119
+ 'outline-width',
120
+ 'outline-color',
121
+ 'box-shadow'
122
+ ];
123
+
124
+ /**
125
+ * Get blacklisted properties.
126
+ *
127
+ * @param {string} ignore - Property name.
128
+ * @returns {string[]} - Array of blacklisted properties.
129
+ */
130
+ const getBlacklist = (ignore) => {
131
+ if (ignore === 'paint-properties') {
132
+ return propertiesThatCauseLayout;
133
+ }
134
+
135
+ return propertiesThatCauseLayout.concat(propsThatCausePaint);
136
+ };
137
+
138
+ /**
139
+ * Returns the input string stripped of its vendor prefix.
140
+ *
141
+ * @param {string} property - String with or without vendor prefix.
142
+ * @returns {string} String name without vendor prefixes.
143
+ *
144
+ * @example
145
+ * unprefixed('-moz-tab-size') //=> 'tab-size'
146
+ */
147
+ const unprefixed = (property) => property.replace(/^-\w+-/u, '');
148
+
149
+ module.exports = stylelint.createPlugin(
150
+ ruleName,
151
+ (actual, options) => (cssRoot, result) => {
152
+ const validOptions = stylelint.utils.validateOptions(
153
+ result,
154
+ ruleName,
155
+ { actual },
156
+ {
157
+ actual: options,
158
+ possible: {
159
+ ignore: ['paint-properties'],
160
+ ignoreProperties: [isString]
161
+ },
162
+ optional: true
163
+ }
164
+ );
165
+
166
+ if (!validOptions) { return; }
167
+
168
+ // @ts-expect-error -- Property 'ignore' comes from an index signature, so it must be accessed with ['ignore'].
169
+ const blacklist = getBlacklist(options.ignore);
170
+ // @ts-expect-error -- Property 'ignoreProperties' comes from an index signature, so it must be accessed with ['ignoreProperties'].
171
+ const ignored = (options.ignoreProperties ? options.ignoreProperties : []);
172
+
173
+ cssRoot.walkDecls('transition-property', (decl) => {
174
+ valueParser(decl.value).walk((node) => {
175
+ const value = unprefixed(node.value);
176
+
177
+ if (
178
+ node.type === 'word' &&
179
+ !ignored.includes(value) &&
180
+ (blacklist.includes(value) || value === 'all')
181
+ ) {
182
+ const index = declarationValueIndex(decl) + node.sourceIndex;
183
+
184
+ stylelint.utils.report({
185
+ ruleName,
186
+ result,
187
+ node: decl,
188
+ message: messages.rejected('transition', node.value),
189
+ index
190
+ });
191
+ }
192
+ });
193
+ });
194
+
195
+ cssRoot.walkDecls('transition', (decl) => {
196
+ /** @type {{ index: number; value: string; }[]} */
197
+ const nodes = [];
198
+
199
+ valueParser(decl.value).walk((node) => {
200
+ if (node.type === 'word' || node.type === 'function') {
201
+ nodes.push({
202
+ index: node.sourceIndex,
203
+ value: node.value
204
+ });
205
+ }
206
+
207
+ return false;
208
+ });
209
+
210
+ if (!ignored.includes('all')) {
211
+ const transitionProp = nodes.filter((node) => {
212
+ const isUnit = valueParser.unit(node.value);
213
+ const isTimingFunction = cssTimingFunctionsRE.test(node.value);
214
+
215
+ if (isUnit || isTimingFunction) {
216
+ return false;
217
+ }
218
+
219
+ return node;
220
+ });
221
+
222
+ if (nodes.length > 0 && transitionProp.length === 0) {
223
+ stylelint.utils.report({
224
+ ruleName,
225
+ result,
226
+ node: decl,
227
+ message: messages.rejected('transition', 'all'),
228
+ index: declarationValueIndex(decl) + nodes[0].index
229
+ });
230
+
231
+ return;
232
+ }
233
+ }
234
+
235
+ for (const property of nodes) {
236
+ const index = declarationValueIndex(decl) + property.index;
237
+ const value = unprefixed(property.value);
238
+
239
+ if (
240
+ !ignored.includes(value) &&
241
+ (blacklist.includes(value) || value === 'all')
242
+ ) {
243
+ stylelint.utils.report({
244
+ ruleName,
245
+ result,
246
+ node: decl,
247
+ message: messages.rejected('transition', property.value),
248
+ index
249
+ });
250
+ }
251
+ }
252
+ });
253
+
254
+ cssRoot.walkAtRules(/^keyframes$/iu, (atRuleKeyframes) => {
255
+ atRuleKeyframes.walkDecls((decl) => {
256
+ const value = unprefixed(decl.prop);
257
+
258
+ if (!ignored.includes(value) && blacklist.includes(value)) {
259
+ stylelint.utils.report({
260
+ ruleName,
261
+ result,
262
+ node: decl,
263
+ message: messages.rejected('animation', decl.prop)
264
+ });
265
+ }
266
+ });
267
+ });
268
+ }
269
+ );
270
+
271
+ // @ts-expect-error -- Cannot assign to 'ruleName' because it is a read-only property.
272
+ module.exports.ruleName = ruleName;
273
+ module.exports.messages = messages;
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * @file Fork of `stylelint-selector-tag-no-without-class` rule.
3
3
  *
4
+ * @license MIT
4
5
  * @see https://github.com/Moxio/stylelint-selector-tag-no-without-class
5
6
  */
6
7