linter-bundle 7.5.0 → 7.7.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.
@@ -104,8 +104,33 @@
104
104
  },
105
105
  "additionalProperties": false
106
106
  },
107
+ "css": {
108
+ "type": "object",
109
+ "properties": {
110
+ "verbose": {
111
+ "type": "boolean"
112
+ },
113
+ "timing": {
114
+ "type": "boolean"
115
+ },
116
+ "git": {
117
+ "type": "boolean"
118
+ },
119
+ "include": {
120
+ "type": "array",
121
+ "items": {
122
+ "type": "string"
123
+ }
124
+ },
125
+ "patternPrefix": {
126
+ "type": "string"
127
+ }
128
+ },
129
+ "additionalProperties": false
130
+ },
107
131
  "sass": {
108
132
  "type": "object",
133
+ "deprecated": true,
109
134
  "properties": {
110
135
  "verbose": {
111
136
  "type": "boolean"
package/CHANGELOG.md CHANGED
@@ -6,10 +6,75 @@ 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/v7.5.0...HEAD)
9
+ [Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v7.7.0...HEAD)
10
+
11
+ ## [7.7.0] - 2025-07-25
12
+
13
+ ### Breaking changes
14
+
15
+ - [general] Drop support for Node.js version less than 20.12.0, 21.*.* and 23.*.* as some of the ESLint plugins are not supporting them anymore
16
+ - [eslint] Removed deprecated `@stylistic/eslint-plugin-jsx` plugin
17
+
18
+ ### Changed
19
+
20
+ - [eslint] Updated `eslint` from `9.26.0` to `9.31.0`
21
+ - [eslint] Updated `eslint-import-resolver-typescript` from `4.3.4` to `4.4.4`
22
+ - [eslint] Updated `eslint-plugin-functional` from `9.0.1` to `9.0.2`
23
+ - [eslint] Updated `eslint-plugin-import` from `2.31.0` to `2.32.0`
24
+ - [eslint] Updated `eslint-plugin-jest` from `28.11.0` to `29.0.1`
25
+ - [eslint] Updated `eslint-plugin-jsdoc` from `50.6.17` to `51.4.1`
26
+ - [eslint] Updated `eslint-plugin-n` from `17.18.0` to `17.21.0`
27
+ - [eslint] Updated `eslint-plugin-unicorn` from `59.0.1` to `60.0.0`
28
+ - [eslint] Updated `globals` from `16.1.0` to `16.3.0`
29
+ - [eslint] Updated `@stylistic/eslint-plugin` from `4.2.0` to `5.2.2`
30
+ - [eslint] Updated `typescript-eslint` from `8.32.1` to `8.38.0`
31
+ - [markdownlint] Updated `markdownlint-cli` from `0.44.0` to `0.45.0`
32
+ - [stylelint] Updated `stylelint` from `16.19.1` to `16.22.0`
33
+ - [stylelint] Updated `stylelint-scss` from `6.12.0` to `6.12.1`
34
+ - [eslint] Added [`no-unassigned-vars`](https://github.com/eslint/eslint/blob/main/docs/src/rules/no-unassigned-vars.md) rule
35
+ - [eslint] Added [`unicorn/prefer-class-fields`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-class-fields.md) rule
36
+ - [eslint] Added [`unicorn/no-array-reverse`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-array-reverse.md) rule
37
+ - [eslint] Added [`unicorn/require-module-specifiers`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/require-module-specifiers.md) rule
38
+ - [eslint] Added [`unicorn/no-useless-error-capture-stack-trace`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-error-capture-stack-trace.md) rule
39
+ - [eslint] Added [`jest/prefer-ending-with-an-expect`](https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/prefer-ending-with-an-expect.md) rule
40
+ - [eslint] Added but disabled [`import/enforce-node-protocol-usage`](https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/enforce-node-protocol-usage.md) rule, as this is covered by `unicorn/prefer-node-protocol`
41
+ - [eslint] Added but disabled [`n/no-top-level-await`](https://github.com/eslint-community/eslint-plugin-n/blob/master/docs/rules/no-top-level-await.md) rule as it conflicts with `unicorn/prefer-top-level-await`
42
+ - [eslint] Rename `@stylistic/func-call-spacing` to `@stylistic/function-call-spacing`
43
+ - [stylelint] Activate `custom-property-empty-line-before` rule and `ignore` `"after-custom-property"`
44
+
45
+ [Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v7.6.0...v7.7.0)
46
+
47
+ ## [7.6.0] - 2025-05-14
48
+
49
+ ### Changed
50
+
51
+ - [general] Added support for `.css` files in ESLint and Stylelint rules
52
+ - [eslint] Updated `eslint` from `9.24.0` to `9.26.0`
53
+ - [eslint] Updated `eslint-import-resolver-typescript` from `4.3.2` to `4.3.4`
54
+ - [eslint] Updated `eslint-plugin-jsdoc` from `50.6.9` to `50.6.17`
55
+ - [eslint] Updated `eslint-plugin-n` from `17.17.0` to `17.18.0`
56
+ - [eslint] Updated `eslint-plugin-unicorn` from `58.0.0` to `59.0.1`
57
+ - [eslint] Updated `globals` from `16.0.0` to `16.1.0`
58
+ - [eslint] Updated `typescript-eslint` from `8.29.1` to `8.32.1`
59
+ - [stylelint] Updated `stylelint` from `16.18.0` to `16.19.1`
60
+ - [stylelint] Updated `stylelint-order` from `6.0.4` to `7.0.0`
61
+ - [stylelint] Updated `stylelint-scss` from `6.11.1` to `6.12.0`
62
+ - [eslint] Renamed `unicorn/no-array-push-push` rule to `prefer-single-call`
63
+ - [eslint] Renamed `unicorn/no-length-as-slice-end` rule to `no-unnecessary-slice-end`
64
+ - [eslint] Added but disabled [`unicorn/prefer-import-meta-properties`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-import-meta-properties.md) rule
65
+ - [eslint] Added [`unicorn/no-unnecessary-array-flat-depth`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unnecessary-array-flat-depth.md) rule
66
+ - [eslint] Added [`unicorn/no-unnecessary-array-splice-count`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unnecessary-array-splice-count.md) rule
67
+ - [eslint] Activated [`unicorn/prefer-event-target`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-event-target.md) rule
68
+ - [eslint] Activated [`unicorn/prefer-top-level-await`](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-top-level-await.md) rule
69
+ - [eslint] Added [`@typescript-eslint/no-unnecessary-type-conversion`](https://typescript-eslint.io/rules/no-unnecessary-type-conversion/) rule
70
+ - [stylelint] Activated [`selector-not-notation`](https://stylelint.io/user-guide/rules/selector-not-notation/) rule with "complex" option
71
+
72
+ [Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v7.5.0...v7.6.0)
10
73
 
11
74
  ## [7.5.0] - 2025-04-08
12
75
 
76
+ ### Changed
77
+
13
78
  - [eslint] Updated `eslint` from `9.23.0` to `9.24.0`
14
79
  - [eslint] Updated `eslint-import-resolver-typescript` from `4.2.2` to `4.3.2`
15
80
  - [eslint] Updated `eslint-plugin-jsdoc` from `50.6.8` to `50.6.9`
@@ -26,13 +91,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
26
91
 
27
92
  [Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v7.4.0...v7.5.0)
28
93
 
29
- ### Changed
30
-
31
- - [eslint] Updated `eslint` from `9.22.0` to `9.23.0`
32
- - [eslint/react] Activated `allowExpressions` of the `@typescript-eslint/explicit-function-return-type`rule also for the React overrides
33
-
34
- [Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v7.3.0...v7.4.0)
35
-
36
94
  ## [7.4.0] - 2025-03-23
37
95
 
38
96
  ### Changed
@@ -126,7 +184,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
126
184
  - [eslint] The prefixes "override-" has been removed from the specialized rule files and the suffix `.cjs` has been replaced by `.mjs`
127
185
  - [stylelint] The stylelint configuration has been renamed from `linter-bundle/stylelint.cjs` to `linter-bundle/stylelint.mjs`
128
186
  - [stylelint] As the interface for rules changed slightly, I had to remove some auto-fixes for the previously forked stylistic rules.
129
- - [general] Drop support for Node.js version less than v20.9.0 and v21.1.0 as a lot of ESLint plugins are not supporting them
187
+ - [general] Drop support for Node.js version less than v20.9.0 and v21.1.0 as a lot of the ESLint plugins are not supporting them
130
188
 
131
189
  ### Fixed
132
190
 
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  Ready-to use bundle of linting tools, containing configurations for
10
10
 
11
11
  - [ESLint](https://eslint.org/): JavaScript (Node.js); TypeScript, React (Browser)
12
- - [stylelint](https://stylelint.io/): SCSS (Browser)
12
+ - [stylelint](https://stylelint.io/): CSS, SCSS (Browser)
13
13
  - [markdownlint](https://github.com/DavidAnson/markdownlint): Markdown
14
14
  - [better-npm-audit](https://www.npmjs.com/package/better-npm-audit): Security audit using `npm`
15
15
  - [improved-yarn-audit](https://www.npmjs.com/package/improved-yarn-audit): Security audit using `yarn`
@@ -84,8 +84,8 @@ npm install linter-bundle --save-dev
84
84
  ```json
85
85
  {
86
86
  "scripts": {
87
- "lint": "lint tsc ts sass md audit",
88
- "lint-different-configurations": "lint tsc --tsconfig=./path1/tsconfig.json tsc --tsconfig=./path2/tsconfig.json ts sass md audit"
87
+ "lint": "lint tsc ts css md audit",
88
+ "lint-different-configurations": "lint tsc --tsconfig=./path1/tsconfig.json tsc --tsconfig=./path2/tsconfig.json ts css md audit"
89
89
  }
90
90
  }
91
91
  ```
@@ -224,8 +224,8 @@ The file itself, and any of the options is optional.
224
224
  }
225
225
  }
226
226
  },
227
- "sass": {
228
- "include": ["./included/*.ts"],
227
+ "css": {
228
+ "include": ["./included/*.css"],
229
229
  "patternPrefix": "(my-prefix|another-prefix)"
230
230
  },
231
231
  "md": {
@@ -405,9 +405,9 @@ export default {
405
405
  },
406
406
 
407
407
  /**
408
- * Configuration, specific to the `sass` command.
408
+ * Configuration, specific to the `css` command.
409
409
  */
410
- sass: {
410
+ css: {
411
411
  /**
412
412
  * `verbose`, `timing` and `git` are the same as in the root node.
413
413
  */
@@ -420,7 +420,7 @@ export default {
420
420
  *
421
421
  * @type {string[]}
422
422
  */
423
- include: ['./included/*.ts'],
423
+ include: ['./included/*.css'],
424
424
 
425
425
  /**
426
426
  * The prefix used for the 'custom-media-pattern' (`@media (--my-prefix-foo)`) and 'custom-property-pattern' (`var(--my-prefix-bar)`) rule.
@@ -444,7 +444,7 @@ export default {
444
444
  *
445
445
  * @type {string[]}
446
446
  */
447
- include: ['./included/*.ts']
447
+ include: ['./included/*.md']
448
448
  },
449
449
 
450
450
  /**
@@ -532,7 +532,7 @@ The command line arguments are separated in groups. Here are some examples:
532
532
 
533
533
  ```sh
534
534
  # Run File restrictions, TypeScript compiler, ESLint, Stylelint, Markdownlint, and audit in the given order, using the default configuration
535
- lint files tsc ts sass md audit
535
+ lint files tsc ts css md audit
536
536
 
537
537
  # Run ESLint and Audit, and show their terminal output even on success
538
538
  lint --verbose ts audit
@@ -593,12 +593,12 @@ Argument | Description | Example
593
593
  `--include` | Patterns with files which should be considered | `--include="./cypress/**/*.ts"`
594
594
  `--exclude` | Patterns with files which should not be considered. Can be used multiple times for different patterns. Used as `--ignore-pattern` argument for ESLint. | `--exclude="cypress" --exclude=".storybook"`
595
595
 
596
- ### `lint sass`
596
+ ### `lint css`
597
597
 
598
598
  Will execute:
599
599
 
600
600
  ```sh
601
- stylelint "src/**/*.scss" --formatter unix --report-needless-disables --report-invalid-scope-disables --report-descriptionless-disables
601
+ stylelint "src/**/*.{css,scss}" --formatter unix --report-needless-disables --report-invalid-scope-disables --report-descriptionless-disables
602
602
  ```
603
603
 
604
604
  ### `lint md`
@@ -668,7 +668,8 @@ To ensure the stylelint plugins are correctly loaded, you need to adjust the set
668
668
  ```json
669
669
  {
670
670
  "stylelint.enable": true,
671
- "stylelint.validate": [
671
+ "stylelint.validate": [,
672
+ "css",
672
673
  "scss"
673
674
  ],
674
675
  "css.validate": false,
@@ -702,6 +703,9 @@ To visualize the max line-length rules in VSCode, you can activate rulers, by ad
702
703
  "[markdown]": {
703
704
  "editor.rulers": [300]
704
705
  },
706
+ "[css]": {
707
+ "editor.rulers": [160]
708
+ },
705
709
  "[scss]": {
706
710
  "editor.rulers": [160]
707
711
  },
package/TODO.md CHANGED
@@ -0,0 +1,68 @@
1
+ <!-- markdownlint-disable -->
2
+
3
+ - Dateien ignorieren, die nicht zu git hochgeladen werden.
4
+ z.B. sollte der Markdownlinter die TODO.md ignorieren
5
+
6
+ Aktivierung dieser Regeln: https://eslint.style/packages/plus
7
+
8
+ shared-settings für linter-bundle custom settings verwenden?
9
+ https://eslint.org/blog/2022/08/new-config-system-part-2/#shared-settings-are-exactly-the-same
10
+
11
+ ---
12
+
13
+ - Aktuell sind die Versionen von den Audit-Tools hardcodiert in der lint.js hinterlegt:
14
+ 'better-npm-audit@3.7.3',
15
+ 'improved-yarn-audit@3.0.0',
16
+ Das sollte irgendwo hinterlegt werden, so z.B. check-outdated drauf zugreifen kann. (z.B. die optionalDependencies? Sind diese nach dem regulären Installieren noch vorhanden und lassen sich entsprechend auslesen? Werden diese von check-outdated geprüft?)
17
+
18
+ - Timing funktioniert nicht - siehe HexEd.it-core
19
+
20
+ - Wie erreichen wir auto-completion in der .linter-bundle.js datei?
21
+ .linter-bundle.json vielleicht mit Schema-Datei?
22
+
23
+ <!-- markdownlint-disable -->
24
+
25
+ - Bereiche in Readme aufklappbar machen:
26
+ <details>
27
+ summary>yarn</summary>
28
+
29
+ ```shell
30
+ yarn add click-to-react-component
31
+ ```
32
+ </details>
33
+
34
+ - Make git diff-branch configurable
35
+ on GitHub Actions this could be used:
36
+ - run: git diff --name-only -z origin/${GITHUB_BASE_REF}
37
+ Is there a variable with includes origin/ already?
38
+
39
+ Some tools like Gatsby ship deprecated dependencies of eslint and @typescript-eslint.
40
+ Since npm installs packages alphabetically, the outdated `gatsby` dependencies are installed in the `node_modules` root, instead of the newer `linter-bundle` dependencies. Since the old versions often do not support new rules or new options, this may cause linting to fail with errors like this:
41
+
42
+ ```bash
43
+ Error while loading rule 'import/no-unused-modules': .eslintrc.js » ./node_modules/linter-bundle/eslint/index.js:
44
+ Configuration for rule "@typescript-eslint/no-throw-literal" is invalid:
45
+ Value [{"allowThrowingAny":false,"allowThrowingUnknown":true}] should NOT have more than 0 items.
46
+ ```
47
+
48
+ To solve such problems, npm supports [`overrides`](https://docs.npmjs.com/cli/v8/configuring-npm/package-json#overrides) as of version [8.3](https://github.com/npm/cli/releases/tag/v8.3.0), while yarn supports [`resolutions`](https://classic.yarnpkg.com/en/docs/selective-version-resolutions/).
49
+
50
+ By using the `enforce-deps` option, linter-bundle will ensure the right versions of the dependencies are installed, and if not it automatically write these options to your package.json and then run an `npm i` or `yarn`, before starting the linting to ensure that the correct dependency versions are installed.
51
+
52
+ ```json
53
+ "overrides": {
54
+ "@typescript-eslint/eslint-plugin": "$linter-bundle",
55
+ "@typescript-eslint/parser": "$linter-bundle",
56
+ "eslint": "$linter-bundle"
57
+ }
58
+ ```
59
+
60
+ - Option to lint only changed files in Git
61
+ - [lint-staged](https://github.com/okonet/lint-staged)
62
+ - [affected](https://www.npmjs.com/package/affected)
63
+ - [git-affected-files](https://www.npmjs.com/package/git-affected-files)
64
+ - [affected-files](https://www.npmjs.com/package/affected-files)
65
+ - [is-affected](https://www.npmjs.com/package/is-affected)
66
+
67
+ - Find stylelint rule which checks for wrong values like:
68
+ `padding-top: 3px 3px 0;`
package/eslint/index.mjs CHANGED
@@ -9,7 +9,6 @@ import stylisticPlugin from '@stylistic/eslint-plugin';
9
9
  // @ts-expect-error -- There are no type definitions for this plugin
10
10
  import eslintCommentsPlugin from 'eslint-plugin-eslint-comments';
11
11
  import functionalPlugin from 'eslint-plugin-functional';
12
- // @ts-expect-error -- There are no type definitions for this plugin
13
12
  import importPlugin from 'eslint-plugin-import';
14
13
  // @ts-expect-error -- There are no type definitions for this plugin
15
14
  import jsxA11YPlugin from 'eslint-plugin-jsx-a11y';
@@ -346,6 +345,7 @@ export default [
346
345
  'no-this-before-super': 'error',
347
346
  'no-throw-literal': 'off', // Covered by @typescript-eslint/no-throw-literal
348
347
  'no-trailing-spaces': 'error',
348
+ 'no-unassigned-vars': 'error',
349
349
  'no-undef-init': 'error',
350
350
  'no-undef': 'off', // Covered by TypeScript
351
351
  'no-undefined': 'off', // @todo "Using the void operator to generate the value of undefined if necessary." should be disableable
@@ -452,7 +452,7 @@ export default [
452
452
  '@stylistic/brace-style': ['error', 'stroustrup', { allowSingleLine: true }],
453
453
  '@stylistic/comma-dangle': ['error', { generics: 'ignore' }],
454
454
  '@stylistic/comma-spacing': 'error',
455
- '@stylistic/func-call-spacing': 'error',
455
+ '@stylistic/function-call-spacing': 'error',
456
456
  '@stylistic/indent': [
457
457
  'error',
458
458
  'tab',
@@ -782,6 +782,7 @@ export default [
782
782
  '@typescript-eslint/no-unnecessary-type-arguments': 'error',
783
783
  '@typescript-eslint/no-unnecessary-type-assertion': 'error',
784
784
  '@typescript-eslint/no-unnecessary-type-constraint': 'error',
785
+ '@typescript-eslint/no-unnecessary-type-conversion': 'error',
785
786
  '@typescript-eslint/no-unnecessary-type-parameters': 'error',
786
787
  '@typescript-eslint/no-unsafe-argument': 'error',
787
788
  '@typescript-eslint/no-unsafe-assignment': 'error',
@@ -921,6 +922,7 @@ export default [
921
922
  'import/no-self-import': 'error',
922
923
  'import/no-unassigned-import': ['error', {
923
924
  allow: [
925
+ '**/*.css',
924
926
  '**/*.scss',
925
927
  'jest-extended'
926
928
  ]
@@ -1030,6 +1032,12 @@ export default [
1030
1032
  namespace: true,
1031
1033
  named: false
1032
1034
  },
1035
+ './styles.module.css': {
1036
+ unassigned: false,
1037
+ default: false,
1038
+ namespace: true,
1039
+ named: false
1040
+ },
1033
1041
  './styles.module.scss': {
1034
1042
  unassigned: false,
1035
1043
  default: false,
@@ -1044,8 +1052,8 @@ export default [
1044
1052
  'unicorn/no-array-callback-reference': 'off', // If I use functions, they are the best option for this use-case
1045
1053
  'unicorn/no-array-for-each': 'error',
1046
1054
  'unicorn/no-array-method-this-argument': 'error',
1047
- 'unicorn/no-array-push-push': 'error',
1048
1055
  'unicorn/no-array-reduce': ['error', { allowSimpleOperations: true }],
1056
+ 'unicorn/no-array-reverse': 'error',
1049
1057
  'unicorn/no-await-expression-member': 'error',
1050
1058
  'unicorn/no-console-spaces': 'error',
1051
1059
  'unicorn/no-document-cookie': 'error',
@@ -1056,7 +1064,6 @@ export default [
1056
1064
  'unicorn/no-invalid-fetch-options': 'error',
1057
1065
  'unicorn/no-invalid-remove-event-listener': 'error',
1058
1066
  'unicorn/no-keyword-prefix': 'off',
1059
- 'unicorn/no-length-as-slice-end': 'error',
1060
1067
  'unicorn/no-lonely-if': 'off', // Sometimes the code is clearer if-conditions are not combined
1061
1068
  'unicorn/no-magic-array-flat-depth': 'error',
1062
1069
  'unicorn/no-named-default': 'error',
@@ -1072,11 +1079,15 @@ export default [
1072
1079
  'unicorn/no-thenable': 'error',
1073
1080
  'unicorn/no-this-assignment': 'error',
1074
1081
  'unicorn/no-typeof-undefined': 'error',
1082
+ 'unicorn/no-unnecessary-array-flat-depth': 'error',
1083
+ 'unicorn/no-unnecessary-array-splice-count': 'error',
1075
1084
  'unicorn/no-unnecessary-await': 'error',
1076
1085
  'unicorn/no-unnecessary-polyfills': 'error',
1086
+ 'unicorn/no-unnecessary-slice-end': 'error',
1077
1087
  'unicorn/no-unreadable-array-destructuring': 'error',
1078
1088
  'unicorn/no-unreadable-iife': 'error',
1079
1089
  'unicorn/no-unused-properties': 'error',
1090
+ 'unicorn/no-useless-error-capture-stack-trace': 'error',
1080
1091
  'unicorn/no-useless-fallback-in-spread': 'error',
1081
1092
  'unicorn/no-useless-promise-resolve-reject': 'error',
1082
1093
  'unicorn/no-useless-length-check': 'error',
@@ -1094,6 +1105,7 @@ export default [
1094
1105
  'unicorn/prefer-array-some': 'error',
1095
1106
  'unicorn/prefer-at': 'off', // @todo Disabled for now, since `at` is not supported by TypeScript type definitions yet.
1096
1107
  'unicorn/prefer-blob-reading-methods': 'off', // @todo Disabled for now, since it's only supported in Safari 14+. Activate in 2025
1108
+ 'unicorn/prefer-class-fields': 'error',
1097
1109
  'unicorn/prefer-code-point': 'error',
1098
1110
  'unicorn/prefer-date-now': 'error',
1099
1111
  'unicorn/prefer-default-parameters': 'error',
@@ -1101,9 +1113,10 @@ export default [
1101
1113
  'unicorn/prefer-dom-node-dataset': 'off', // `setAttribute` is faster than `dataset`. See https://www.measurethat.net/Benchmarks/Show/7740/0/classname-vs-setattribute-vs-classlist-vs-dataset
1102
1114
  'unicorn/prefer-dom-node-remove': 'error',
1103
1115
  'unicorn/prefer-dom-node-text-content': 'error',
1104
- 'unicorn/prefer-event-target': 'off', // @todo Disabled for now, since `EventTarget` requires Node.js 16. Activate in 2025
1116
+ 'unicorn/prefer-event-target': 'error',
1105
1117
  'unicorn/prefer-export-from': ['error', { ignoreUsedVariables: true }],
1106
1118
  'unicorn/prefer-global-this': 'off', // This makes only sense if the same code may run on the server-side. Often the auto-fixing of this rule doesn't make sense
1119
+ 'unicorn/prefer-import-meta-properties': 'off', // @todo Regarding `n/no-unsupported-features/node-builtins` it's still an experimental feature, so check back in 2026
1107
1120
  'unicorn/prefer-includes': 'error',
1108
1121
  'unicorn/prefer-json-parse-buffer': 'off', // TypeScript states that string needs to be used as of the ES specification. @see https://github.com/microsoft/TypeScript/issues/11842
1109
1122
  'unicorn/prefer-keyboard-event-key': 'error',
@@ -1116,7 +1129,6 @@ export default [
1116
1129
  'unicorn/prefer-native-coercion-functions': 'off',
1117
1130
  'unicorn/prefer-negative-index': 'error',
1118
1131
  'unicorn/prefer-number-properties': 'error',
1119
- 'unicorn/prefer-object-has-own': 'off', // Not widely supported yet. Can be activated in 2024
1120
1132
  'unicorn/prefer-object-from-entries': 'error',
1121
1133
  'unicorn/prefer-optional-catch-binding': 'error',
1122
1134
  'unicorn/prefer-prototype-methods': 'error',
@@ -1124,6 +1136,7 @@ export default [
1124
1136
  'unicorn/prefer-reflect-apply': 'error',
1125
1137
  'unicorn/prefer-set-has': 'error',
1126
1138
  'unicorn/prefer-set-size': 'error',
1139
+ 'unicorn/prefer-single-call': 'error',
1127
1140
  'unicorn/prefer-spread': 'off', // @todo Disabled till there a solution for the warning, that `slice()` on Typed-Arrays should be replaced (which is not possible). @see https://github.com/sindresorhus/eslint-plugin-unicorn/issues/1064
1128
1141
  'unicorn/prefer-string-raw': 'off', // The overhead of writing String.raw`...` is not worth the inconsistency in writing strings
1129
1142
  'unicorn/prefer-string-replace-all': 'off', // @todo Available since 2020 in browsers. Should this be preferred?
@@ -1133,12 +1146,13 @@ export default [
1133
1146
  'unicorn/prefer-structured-clone': 'error',
1134
1147
  'unicorn/prefer-switch': 'error',
1135
1148
  'unicorn/prefer-ternary': 'off', // We prefer readability over saving a few chars
1136
- 'unicorn/prefer-top-level-await': 'off', // @todo Available since 2021. Activate in 2024
1149
+ 'unicorn/prefer-top-level-await': 'error',
1137
1150
  'unicorn/prefer-regexp-test': 'error',
1138
1151
  'unicorn/prefer-type-error': 'error',
1139
1152
  'unicorn/prevent-abbreviations': ['error', { ignore: ['args', 'i', 'j', 'i18n', /[Rr]ef/u, /[Pp]arams/u, /[Pp]rops/u] }],
1140
1153
  'unicorn/relative-url-style': 'error',
1141
1154
  'unicorn/require-array-join-separator': 'error',
1155
+ 'unicorn/require-module-specifiers': 'error',
1142
1156
  'unicorn/require-number-to-fixed-digits-argument': 'error',
1143
1157
  'unicorn/require-post-message-target-origin': 'off', // False-positive with Workers which don't support a `targetOrigin`
1144
1158
  'unicorn/string-content': 'off', // Breaks code (e.g. imports with `...` in Next.js or GraphQL template strings),
@@ -45,6 +45,7 @@ export default [
45
45
  *
46
46
  * @see https://github.com/import-js/eslint-plugin-import
47
47
  */
48
+ 'import/enforce-node-protocol-usage': 'off', // Covered by unicorn/prefer-node-protocol
48
49
  'import/no-commonjs': 'off',
49
50
  'import/no-import-module-exports': 'error',
50
51
  'import/no-internal-modules': 'off',
@@ -82,6 +83,7 @@ export default [
82
83
  'n/no-unsupported-features/es-builtins': 'error',
83
84
  'n/no-unsupported-features/es-syntax': 'error',
84
85
  'n/no-unsupported-features/node-builtins': 'error',
86
+ 'n/no-top-level-await': 'off', // Conflicts with unicorn/prefer-await
85
87
  'n/prefer-global/buffer': 'error',
86
88
  'n/prefer-global/console': 'error',
87
89
  'n/prefer-global/process': 'error',
package/eslint/jest.mjs CHANGED
@@ -96,6 +96,7 @@ export default [
96
96
  'jest/prefer-hooks-on-top': 'error',
97
97
  'jest/prefer-comparison-matcher': 'error',
98
98
  'jest/prefer-each': 'error',
99
+ 'jest/prefer-ending-with-an-expect': 'error',
99
100
  'jest/prefer-equality-matcher': 'error',
100
101
  'jest/prefer-importing-jest-globals': 'error',
101
102
  'jest/prefer-jest-mocked': 'error',
package/eslint/react.mjs CHANGED
@@ -2,7 +2,6 @@
2
2
  * @file Settings for React code in TypeScript (TSX) files.
3
3
  */
4
4
 
5
- import stylisticJSXPlugin from '@stylistic/eslint-plugin-jsx';
6
5
  import reactPlugin from 'eslint-plugin-react';
7
6
  import * as reactHooksPlugin from 'eslint-plugin-react-hooks';
8
7
 
@@ -13,8 +12,7 @@ export default [
13
12
  {
14
13
  plugins: {
15
14
  'react-hooks': reactHooksPlugin,
16
- 'react': reactPlugin,
17
- '@stylistic/jsx': stylisticJSXPlugin
15
+ 'react': reactPlugin
18
16
  }
19
17
  },
20
18
  {
@@ -36,14 +36,17 @@ export default [
36
36
  }
37
37
  },
38
38
  {
39
- files: ['**/*.scss.d.ts'],
39
+ files: [
40
+ '**/*.css.d.ts',
41
+ '**/*.scss.d.ts'
42
+ ],
40
43
  rules: {
41
44
  /**
42
45
  * eslint
43
46
  *
44
47
  * @see https://eslint.org/docs/rules/
45
48
  */
46
- 'linebreak-style': 'off' // Ignore for automatically generated .scss.d.ts files, since that does not affect the project.
49
+ 'linebreak-style': 'off' // Ignore for automatically generated .(s)css.d.ts files, since that does not affect the project.
47
50
  }
48
51
  }
49
52
  ];
@@ -58,6 +58,10 @@ export interface LinterBundleConfig {
58
58
  /* eslint-enable @typescript-eslint/naming-convention */
59
59
  };
60
60
  };
61
+ css?: {
62
+ patternPrefix?: string;
63
+ };
64
+ /** @deprecated */
61
65
  sass?: {
62
66
  patternPrefix?: string;
63
67
  };
package/lint.js CHANGED
@@ -23,7 +23,7 @@ const require = createRequire(import.meta.url);
23
23
  const dirname = path.dirname(fileURLToPath(import.meta.url));
24
24
 
25
25
  /**
26
- * @typedef {'files' | 'tsc' | 'ts' | 'sass' | 'md' | 'audit'} TaskNames
26
+ * @typedef {'files' | 'tsc' | 'ts' | 'css' | 'sass' | 'md' | 'audit'} TaskNames
27
27
  * @typedef {Partial<Record<string, (string | boolean)[]>>} TaskConfig
28
28
  * @typedef {import('./helper/run-process.js').ProcessResult} ProcessResult
29
29
  * @typedef {{ taskName: TaskNames; taskConfig: TaskConfig; }} TaskNameAndConfig
@@ -52,6 +52,7 @@ await (async () => {
52
52
  case 'ts':
53
53
  return runESLintTask(taskName, taskConfig);
54
54
 
55
+ case 'css':
55
56
  case 'sass':
56
57
  return runStylelintTask(taskName, taskConfig);
57
58
 
@@ -214,7 +215,7 @@ async function runESLintTask (taskName, taskConfig) {
214
215
  }
215
216
 
216
217
  /**
217
- * Runs the `sass` task.
218
+ * Runs the `css` task.
218
219
  *
219
220
  * @param {TaskNameAndConfig['taskName']} taskName - Name of the task as used in the command line
220
221
  * @param {TaskNameAndConfig['taskConfig']} taskConfig - Configuration of the task
@@ -227,7 +228,7 @@ async function runStylelintTask (taskName, taskConfig) {
227
228
  verbose: getConfigValue(taskName, taskConfig, 'verbose')
228
229
  };
229
230
 
230
- const includes = await getIncludes(newTaskConfig, 'src/**/*.scss');
231
+ const includes = await getIncludes(newTaskConfig, 'src/**/*.{css,scss}');
231
232
 
232
233
  if (!includes) {
233
234
  return generateDummyJobOutput(taskName, newTaskConfig, {
@@ -415,7 +416,7 @@ async function validateEnvironment () {
415
416
  * @throws {Error} If no task has be specified in the arguments
416
417
  */
417
418
  function getTasksToRun (argv) {
418
- const TASKS = new Set(['tsc', 'ts', 'sass', 'md', 'audit', 'files']);
419
+ const TASKS = new Set(['tsc', 'ts', 'css', 'sass', 'md', 'audit', 'files']);
419
420
  const ARG_REGEXP = /^--([^=]+)(?:=(.+))?$/u;
420
421
 
421
422
  /** @type {TaskNameAndConfig | null} */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linter-bundle",
3
- "version": "7.5.0",
3
+ "version": "7.7.0",
4
4
  "type": "module",
5
5
  "description": "Ready-to use bundle of linting tools, containing configurations for ESLint, stylelint and markdownlint.",
6
6
  "keywords": [
@@ -15,7 +15,8 @@
15
15
  "react",
16
16
  "react-hooks",
17
17
  "unicorn",
18
- "scss"
18
+ "scss",
19
+ "css"
19
20
  ],
20
21
  "author": "Jens Duttke <github@duttke.de> (https://github.com/jens-duttke)",
21
22
  "license": "MIT",
@@ -23,7 +24,7 @@
23
24
  "lint": "lint.js"
24
25
  },
25
26
  "engines": {
26
- "node": "^20.9.0 || >=21.1.0"
27
+ "node": "^20.12.0 || ^22.0.0 || >=24.0.0"
27
28
  },
28
29
  "repository": {
29
30
  "type": "git",
@@ -41,34 +42,33 @@
41
42
  "_test-stylelint": "node ./test-stylelint.js"
42
43
  },
43
44
  "dependencies": {
44
- "@stylistic/eslint-plugin": "4.2.0",
45
- "@stylistic/eslint-plugin-jsx": "4.2.0",
46
- "eslint": "9.24.0",
45
+ "@stylistic/eslint-plugin": "5.2.2",
46
+ "eslint": "9.31.0",
47
47
  "eslint-formatter-unix": "8.40.0",
48
- "eslint-import-resolver-typescript": "4.3.2",
48
+ "eslint-import-resolver-typescript": "4.4.4",
49
49
  "eslint-import-resolver-webpack": "0.13.10",
50
50
  "eslint-plugin-eslint-comments": "3.2.0",
51
- "eslint-plugin-functional": "9.0.1",
52
- "eslint-plugin-import": "2.31.0",
53
- "eslint-plugin-jest": "28.11.0",
54
- "eslint-plugin-jsdoc": "50.6.9",
51
+ "eslint-plugin-functional": "9.0.2",
52
+ "eslint-plugin-import": "2.32.0",
53
+ "eslint-plugin-jest": "29.0.1",
54
+ "eslint-plugin-jsdoc": "51.4.1",
55
55
  "eslint-plugin-jsx-a11y": "6.10.2",
56
- "eslint-plugin-n": "17.17.0",
56
+ "eslint-plugin-n": "17.21.0",
57
57
  "eslint-plugin-promise": "7.2.1",
58
58
  "eslint-plugin-react": "7.37.5",
59
59
  "eslint-plugin-react-hooks": "5.2.0",
60
- "eslint-plugin-unicorn": "58.0.0",
61
- "globals": "16.0.0",
62
- "markdownlint-cli": "0.44.0",
60
+ "eslint-plugin-unicorn": "60.0.0",
61
+ "globals": "16.3.0",
62
+ "markdownlint-cli": "0.45.0",
63
63
  "micromatch": "4.0.8",
64
64
  "postcss-scss": "4.0.9",
65
- "stylelint": "16.18.0",
65
+ "stylelint": "16.22.0",
66
66
  "stylelint-declaration-block-no-ignored-properties": "2.8.0",
67
67
  "stylelint-high-performance-animation": "1.11.0",
68
- "stylelint-order": "6.0.4",
69
- "stylelint-scss": "6.11.1",
68
+ "stylelint-order": "7.0.0",
69
+ "stylelint-scss": "6.12.1",
70
70
  "stylelint-use-logical-spec": "5.0.1",
71
- "typescript-eslint": "8.29.1"
71
+ "typescript-eslint": "8.38.0"
72
72
  },
73
73
  "peerDependencies": {
74
74
  "@typescript-eslint/utils": "*",
@@ -78,7 +78,7 @@
78
78
  "devDependencies": {
79
79
  "@types/eslint": "9.6.1",
80
80
  "@types/micromatch": "4.0.9",
81
- "@types/node": "22.14.0",
81
+ "@types/node": "24.1.0",
82
82
  "stylelint-find-new-rules": "5.0.0",
83
83
  "typescript": "5.8.3"
84
84
  }
@@ -4,6 +4,8 @@
4
4
 
5
5
  const { linterBundleConfig } = await import('../helper/linter-bundle-config.js');
6
6
 
7
+ linterBundleConfig.css = (linterBundleConfig.sass ?? linterBundleConfig.css ?? {});
8
+
7
9
  export default {
8
10
  reportNeedlessDisables: true,
9
11
  reportInvalidScopeDisables: true,
@@ -130,6 +132,95 @@ export default {
130
132
  */
131
133
  'plugin/selector-tag-no-without-class': ['/./']
132
134
  }
135
+ },
136
+ {
137
+ files: ['**/*.scss'],
138
+ rules: {
139
+ /**
140
+ * stylelint
141
+ *
142
+ * @see https://github.com/stylelint/stylelint/tree/master/lib/rules
143
+ */
144
+ 'at-rule-no-unknown': null, // scss/at-rule-no-unknown
145
+ 'declaration-property-value-no-unknown': null, // Covered by scss/declaration-property-value-no-unknown
146
+ 'function-no-unknown': null, // Implemented by scss/function-no-unknown
147
+ 'property-no-unknown': null, // Covered by scss/property-no-unknown
148
+
149
+ /**
150
+ * stylelint-scss
151
+ *
152
+ * @see https://www.npmjs.com/package/stylelint-scss
153
+ */
154
+ 'scss/at-each-key-value-single-line': true,
155
+ 'scss/at-else-closing-brace-newline-after': 'always-last-in-chain',
156
+ 'scss/at-else-closing-brace-space-after': 'never-intermediate',
157
+ 'scss/at-else-empty-line-before': 'never',
158
+ 'scss/at-else-if-parentheses-space-before': 'always',
159
+ 'scss/at-extend-no-missing-placeholder': true,
160
+ 'scss/function-calculation-no-interpolation': true,
161
+ 'scss/at-function-named-arguments': ['never', { ignoreFunctions: ['scale-color', 'color.scale'] }],
162
+ 'scss/at-function-parentheses-space-before': 'always',
163
+ 'scss/at-function-pattern': '^[a-z]+(-[a-z]+)*$',
164
+ 'scss/at-if-closing-brace-newline-after': 'always-last-in-chain',
165
+ 'scss/at-if-closing-brace-space-after': 'never-intermediate',
166
+ 'scss/at-if-no-null': true,
167
+ 'scss/at-mixin-argumentless-call-parentheses': 'never',
168
+ 'scss/at-mixin-named-arguments': ['always', { ignore: ['single-argument'] }],
169
+ 'scss/at-mixin-no-risky-nesting-selector': true,
170
+ 'scss/at-mixin-parentheses-space-before': 'always',
171
+ 'scss/at-mixin-pattern': '^[a-z]+(-[a-z]+)*$',
172
+ 'scss/at-root-no-redundant': true,
173
+ 'scss/at-rule-conditional-no-parentheses': true,
174
+ 'scss/at-rule-no-unknown': true,
175
+ 'scss/at-use-no-unnamespaced': true,
176
+ 'scss/comment-no-loud': true,
177
+ 'scss/declaration-nested-properties-no-divided-groups': true,
178
+ 'scss/declaration-nested-properties': 'never',
179
+ 'scss/declaration-property-value-no-unknown': [
180
+ true,
181
+ {
182
+ ignoreProperties: {
183
+ 'initial-value': /.+/u,
184
+ 'grid-template-areas': /^\([^\u0000]+\)$/u, // Whole block wrapped in parentheses.
185
+ '/.+/': /((^|\s)\$[a-z])|/ui // SCSS variables
186
+ }
187
+ }
188
+ ],
189
+ 'scss/dimension-no-non-numeric-values': true,
190
+ 'scss/dollar-variable-colon-space-after': 'always',
191
+ 'scss/dollar-variable-colon-space-before': 'never',
192
+ 'scss/dollar-variable-empty-line-before': [
193
+ 'always',
194
+ {
195
+ except: ['first-nested', 'after-comment', 'after-dollar-variable']
196
+ }
197
+ ],
198
+ 'scss/dollar-variable-empty-line-after': [
199
+ 'always',
200
+ {
201
+ except: ['last-nested', 'before-dollar-variable'],
202
+ ignore: ['before-comment', 'inside-single-line-block']
203
+ }
204
+ ],
205
+ 'scss/dollar-variable-first-in-block': [true, { ignore: ['comments', 'imports'] }],
206
+ 'scss/dollar-variable-no-missing-interpolation': true,
207
+ 'scss/dollar-variable-no-namespaced-assignment': true,
208
+ 'scss/dollar-variable-pattern': '^[a-z]+(-[a-z]+)*$',
209
+ 'scss/function-color-channel': true,
210
+ 'scss/function-color-relative': true,
211
+ 'scss/function-no-unknown': [true, { ignoreFunctions: [/^custom-/u] }],
212
+ 'scss/function-quote-no-quoted-strings-inside': true,
213
+ 'scss/function-unquote-no-unquoted-strings-inside': true,
214
+ 'scss/load-partial-extension': 'always',
215
+ 'scss/map-keys-quotes': 'always',
216
+ 'scss/media-feature-value-dollar-variable': 'never',
217
+ 'scss/no-duplicate-dollar-variables': true,
218
+ 'scss/no-duplicate-mixins': true,
219
+ 'scss/no-global-function-names': true,
220
+ 'scss/no-unused-private-members': true,
221
+ 'scss/percent-placeholder-pattern': '^[a-z]+(-[a-z]+)*$',
222
+ 'scss/selector-no-union-class-name': true
223
+ }
133
224
  }
134
225
  ],
135
226
  rules: {
@@ -157,7 +248,7 @@ export default {
157
248
  }
158
249
  ],
159
250
  'at-rule-no-deprecated': true,
160
- 'at-rule-no-unknown': null, // scss/at-rule-no-unknown
251
+ 'at-rule-no-unknown': true,
161
252
  'at-rule-no-vendor-prefix': true,
162
253
  'at-rule-prelude-no-invalid': true,
163
254
  'at-rule-property-required-list': [{
@@ -170,7 +261,7 @@ export default {
170
261
  ignore: ['with-var-inside']
171
262
  }
172
263
  ],
173
- 'color-hex-alpha': null, // @todo Not widely supported yet. Activate in 2024.
264
+ 'color-hex-alpha': null, // Alpha values should only be used if necessary
174
265
  'color-hex-length': 'short',
175
266
  'color-named': 'never',
176
267
  'color-no-hex': true,
@@ -186,11 +277,16 @@ export default {
186
277
  'comment-pattern': /^[^\s].+[^\s]$/u,
187
278
  'comment-whitespace-inside': 'always',
188
279
  'comment-word-disallowed-list': null,
189
- 'container-name-pattern': (linterBundleConfig.sass?.patternPrefix ? `${linterBundleConfig.sass.patternPrefix}-[a-z][a-zA-Z]+(-[a-z][a-zA-Z]+\\d*)+` : null),
190
- 'custom-media-pattern': (linterBundleConfig.sass?.patternPrefix ? `${linterBundleConfig.sass.patternPrefix}-[a-z][a-zA-Z]+(-[a-z][a-zA-Z]+\\d*)+` : null),
191
- 'custom-property-empty-line-before': null, // Empty lines between custom properties are optional
280
+ 'container-name-pattern': (linterBundleConfig.css.patternPrefix ? `${linterBundleConfig.css.patternPrefix}-[a-z][a-zA-Z]+(-[a-z][a-zA-Z]+\\d*)+` : null),
281
+ 'custom-media-pattern': (linterBundleConfig.css.patternPrefix ? `${linterBundleConfig.css.patternPrefix}-[a-z][a-zA-Z]+(-[a-z][a-zA-Z]+\\d*)+` : null),
282
+ 'custom-property-empty-line-before': [
283
+ 'always',
284
+ {
285
+ ignore: ['after-custom-property']
286
+ }
287
+ ],
192
288
  'custom-property-no-missing-var-function': true,
193
- 'custom-property-pattern': (linterBundleConfig.sass?.patternPrefix ? `${linterBundleConfig.sass.patternPrefix}-[a-z][a-zA-Z]+(-[a-z][a-zA-Z]+\\d*)*` : null),
289
+ 'custom-property-pattern': (linterBundleConfig.css.patternPrefix ? `${linterBundleConfig.css.patternPrefix}-[a-z][a-zA-Z]+(-[a-z][a-zA-Z]+\\d*)*` : null),
194
290
  'declaration-block-no-duplicate-custom-properties': true,
195
291
  'declaration-block-no-duplicate-properties': [
196
292
  true,
@@ -228,7 +324,7 @@ export default {
228
324
  'declaration-property-value-allowed-list': null,
229
325
  'declaration-property-value-disallowed-list': null,
230
326
  'declaration-property-value-keyword-no-deprecated': true,
231
- 'declaration-property-value-no-unknown': null, // Covered by scss/declaration-property-value-no-unknown
327
+ 'declaration-property-value-no-unknown': true,
232
328
  'font-family-name-quotes': 'always-where-recommended',
233
329
  'font-family-no-duplicate-names': true,
234
330
  'font-family-no-missing-generic-family-keyword': true,
@@ -238,7 +334,7 @@ export default {
238
334
  'function-disallowed-list': null,
239
335
  'function-linear-gradient-no-nonstandard-direction': true,
240
336
  'function-name-case': 'lower',
241
- 'function-no-unknown': null, // Implemented by scss/function-no-unknown
337
+ 'function-no-unknown': true,
242
338
  'function-url-no-scheme-relative': true,
243
339
  'function-url-quotes': 'always',
244
340
  'function-url-scheme-disallowed-list': null,
@@ -250,7 +346,7 @@ export default {
250
346
  'keyframe-declaration-no-important': true,
251
347
  'keyframe-selector-notation': 'percentage',
252
348
  'keyframes-name-pattern': String.raw`^[a-z]+(-[a-z]+)*\d*$`,
253
- 'layer-name-pattern': (linterBundleConfig.sass?.patternPrefix ? `${linterBundleConfig.sass.patternPrefix}-[a-z][a-zA-Z]+(-[a-z][a-zA-Z]+\\d*)+` : null),
349
+ 'layer-name-pattern': (linterBundleConfig.css.patternPrefix ? `${linterBundleConfig.css.patternPrefix}-[a-z][a-zA-Z]+(-[a-z][a-zA-Z]+\\d*)+` : null),
254
350
  'length-zero-no-unit': true,
255
351
  'max-nesting-depth': 6,
256
352
  'media-feature-name-allowed-list': null,
@@ -279,7 +375,7 @@ export default {
279
375
  'font', // Shorthand property is to complex
280
376
  'grid-gap' // @deprecated Use gap.
281
377
  ],
282
- 'property-no-unknown': null, // Covered by scss/property-no-unknown
378
+ 'property-no-unknown': true,
283
379
  'property-no-vendor-prefix': true,
284
380
  'rule-selector-property-disallowed-list': null,
285
381
  'rule-empty-line-before': [
@@ -316,7 +412,7 @@ export default {
316
412
  'selector-nested-pattern': null,
317
413
  'selector-no-qualifying-type': [true, { ignore: ['attribute', 'class'] }],
318
414
  'selector-no-vendor-prefix': true,
319
- 'selector-not-notation': null, // 'complex', @todo Reactivate in 2024. Disabled for now, because it depends on the project if modern Selectors Level 4 CSS can be used.
415
+ 'selector-not-notation': 'complex',
320
416
  'selector-pseudo-class-allowed-list': null,
321
417
  'selector-pseudo-class-disallowed-list': null,
322
418
  'selector-pseudo-class-no-unknown': [true, { ignorePseudoClasses: ['global'] }],
@@ -950,68 +1046,56 @@ export default {
950
1046
  *
951
1047
  * @see https://www.npmjs.com/package/stylelint-scss
952
1048
  */
953
- 'scss/at-each-key-value-single-line': true,
954
- 'scss/at-else-closing-brace-newline-after': 'always-last-in-chain',
955
- 'scss/at-else-closing-brace-space-after': 'never-intermediate',
956
- 'scss/at-else-empty-line-before': 'never',
957
- 'scss/at-else-if-parentheses-space-before': 'always',
958
- 'scss/at-extend-no-missing-placeholder': true,
959
- 'scss/function-calculation-no-interpolation': true,
960
- 'scss/at-function-named-arguments': ['never', { ignoreFunctions: ['scale-color', 'color.scale'] }],
961
- 'scss/at-function-parentheses-space-before': 'always',
962
- 'scss/at-function-pattern': '^[a-z]+(-[a-z]+)*$',
963
- 'scss/at-if-closing-brace-newline-after': 'always-last-in-chain',
964
- 'scss/at-if-closing-brace-space-after': 'never-intermediate',
965
- 'scss/at-if-no-null': true,
1049
+ 'scss/at-each-key-value-single-line': null,
1050
+ 'scss/at-else-closing-brace-newline-after': null,
1051
+ 'scss/at-else-closing-brace-space-after': null,
1052
+ 'scss/at-else-empty-line-before': null,
1053
+ 'scss/at-else-if-parentheses-space-before': null,
1054
+ 'scss/at-extend-no-missing-placeholder': null,
1055
+ 'scss/function-calculation-no-interpolation': null,
1056
+ 'scss/at-function-named-arguments': null,
1057
+ 'scss/at-function-parentheses-space-before': null,
1058
+ 'scss/at-function-pattern': null,
1059
+ 'scss/at-if-closing-brace-newline-after': null,
1060
+ 'scss/at-if-closing-brace-space-after': null,
1061
+ 'scss/at-if-no-null': null,
966
1062
  'scss/at-import-partial-extension-allowed-list': null,
967
1063
  'scss/at-import-partial-extension-disallowed-list': null,
968
- 'scss/at-mixin-argumentless-call-parentheses': 'never',
969
- 'scss/at-mixin-named-arguments': ['always', { ignore: ['single-argument'] }],
970
- 'scss/at-mixin-no-risky-nesting-selector': true,
971
- 'scss/at-mixin-parentheses-space-before': 'always',
972
- 'scss/at-mixin-pattern': '^[a-z]+(-[a-z]+)*$',
973
- 'scss/at-root-no-redundant': true,
974
- 'scss/at-rule-conditional-no-parentheses': true,
975
- 'scss/at-rule-no-unknown': true,
976
- 'scss/at-use-no-unnamespaced': true,
1064
+ 'scss/at-mixin-argumentless-call-parentheses': null,
1065
+ 'scss/at-mixin-named-arguments': null,
1066
+ 'scss/at-mixin-no-risky-nesting-selector': null,
1067
+ 'scss/at-mixin-parentheses-space-before': null,
1068
+ 'scss/at-mixin-pattern': null,
1069
+ 'scss/at-root-no-redundant': null,
1070
+ 'scss/at-rule-conditional-no-parentheses': null,
1071
+ 'scss/at-rule-no-unknown': null,
1072
+ 'scss/at-use-no-unnamespaced': null,
977
1073
  'scss/at-use-no-redundant-alias': null,
978
1074
  'scss/block-no-redundant-nesting': null,
979
1075
  'scss/comment-no-empty': true,
980
- 'scss/comment-no-loud': true,
981
- 'scss/declaration-nested-properties-no-divided-groups': true,
982
- 'scss/declaration-nested-properties': 'never',
1076
+ 'scss/comment-no-loud': null,
1077
+ 'scss/declaration-nested-properties-no-divided-groups': null,
1078
+ 'scss/declaration-nested-properties': null,
983
1079
  'scss/declaration-property-value-no-unknown': [
984
1080
  true,
985
1081
  {
986
1082
  ignoreProperties: {
987
1083
  'initial-value': /.+/u,
988
- 'grid-template-areas': /^\([^\u0000]+\)$/u, // Whole block wrapped in parentheses.
989
- '/.+/': /((^|\s)\$[a-z])|/ui // SCSS variables
1084
+ 'grid-template-areas': /^\([^\u0000]+\)$/u // Whole block wrapped in parentheses.
990
1085
  }
991
1086
  }
992
1087
  ],
993
- 'scss/dimension-no-non-numeric-values': true,
1088
+ 'scss/dimension-no-non-numeric-values': null,
994
1089
  'scss/dollar-variable-colon-newline-after': null,
995
- 'scss/dollar-variable-colon-space-after': 'always',
996
- 'scss/dollar-variable-colon-space-before': 'never',
1090
+ 'scss/dollar-variable-colon-space-after': null,
1091
+ 'scss/dollar-variable-colon-space-before': null,
997
1092
  'scss/dollar-variable-default': null,
998
- 'scss/dollar-variable-empty-line-before': [
999
- 'always',
1000
- {
1001
- except: ['first-nested', 'after-comment', 'after-dollar-variable']
1002
- }
1003
- ],
1004
- 'scss/dollar-variable-empty-line-after': [
1005
- 'always',
1006
- {
1007
- except: ['last-nested', 'before-dollar-variable'],
1008
- ignore: ['before-comment', 'inside-single-line-block']
1009
- }
1010
- ],
1011
- 'scss/dollar-variable-first-in-block': [true, { ignore: ['comments', 'imports'] }],
1012
- 'scss/dollar-variable-no-missing-interpolation': true,
1013
- 'scss/dollar-variable-no-namespaced-assignment': true,
1014
- 'scss/dollar-variable-pattern': '^[a-z]+(-[a-z]+)*$',
1093
+ 'scss/dollar-variable-empty-line-before': null,
1094
+ 'scss/dollar-variable-empty-line-after': null,
1095
+ 'scss/dollar-variable-first-in-block': null,
1096
+ 'scss/dollar-variable-no-missing-interpolation': null,
1097
+ 'scss/dollar-variable-no-namespaced-assignment': null,
1098
+ 'scss/dollar-variable-pattern': null,
1015
1099
  'scss/double-slash-comment-empty-line-before': [
1016
1100
  'always',
1017
1101
  {
@@ -1021,31 +1105,31 @@ export default {
1021
1105
  ],
1022
1106
  'scss/double-slash-comment-inline': null,
1023
1107
  'scss/double-slash-comment-whitespace-inside': 'always',
1024
- 'scss/function-color-channel': true,
1025
- 'scss/function-color-relative': true,
1108
+ 'scss/function-color-channel': null,
1109
+ 'scss/function-color-relative': null,
1026
1110
  'scss/function-disallowed-list': null,
1027
- 'scss/function-no-unknown': [true, { ignoreFunctions: [/^custom-/u] }],
1028
- 'scss/function-quote-no-quoted-strings-inside': true,
1029
- 'scss/function-unquote-no-unquoted-strings-inside': true,
1111
+ 'scss/function-no-unknown': null,
1112
+ 'scss/function-quote-no-quoted-strings-inside': null,
1113
+ 'scss/function-unquote-no-unquoted-strings-inside': null,
1030
1114
  'scss/load-no-partial-leading-underscore': null,
1031
- 'scss/load-partial-extension': 'always',
1032
- 'scss/map-keys-quotes': 'always',
1033
- 'scss/media-feature-value-dollar-variable': 'never',
1115
+ 'scss/load-partial-extension': null,
1116
+ 'scss/map-keys-quotes': null,
1117
+ 'scss/media-feature-value-dollar-variable': null,
1034
1118
  'scss/no-dollar-variables': null,
1035
- 'scss/no-duplicate-dollar-variables': true,
1119
+ 'scss/no-duplicate-dollar-variables': null,
1036
1120
  'scss/no-duplicate-load-rules': true,
1037
- 'scss/no-duplicate-mixins': true,
1038
- 'scss/no-global-function-names': true,
1039
- 'scss/no-unused-private-members': true,
1121
+ 'scss/no-duplicate-mixins': null,
1122
+ 'scss/no-global-function-names': null,
1123
+ 'scss/no-unused-private-members': null,
1040
1124
  'scss/operator-no-newline-after': true,
1041
1125
  'scss/operator-no-newline-before': true,
1042
1126
  'scss/operator-no-unspaced': true,
1043
1127
  'scss/partial-no-import': null,
1044
- 'scss/percent-placeholder-pattern': '^[a-z]+(-[a-z]+)*$',
1128
+ 'scss/percent-placeholder-pattern': null,
1045
1129
  'scss/property-no-unknown': true,
1046
1130
  'scss/selector-nest-combinators': null, // Sometimes nesting does not make sense
1047
1131
  'scss/selector-no-redundant-nesting-selector': true,
1048
- 'scss/selector-no-union-class-name': true,
1132
+ 'scss/selector-no-union-class-name': null,
1049
1133
 
1050
1134
  /**
1051
1135
  * stylelint-selector-no-empty
@@ -41,8 +41,8 @@ export default function declarationColonSpaceChecker (options) {
41
41
  report({
42
42
  message,
43
43
  node: decl,
44
- index: decl.prop.toString().length + 1,
45
- endIndex: decl.prop.toString().length + 1,
44
+ index: decl.prop.length + 1,
45
+ endIndex: decl.prop.length + 1,
46
46
  result: options.result,
47
47
  ruleName: options.checkedRuleName,
48
48
  fix: (options.fix ? () => options.fix(decl, i) : undefined)
@@ -197,7 +197,7 @@ function getCheckBefore (valueNode) {
197
197
  function getCheckAfter (valueNode) {
198
198
  let after = '';
199
199
 
200
- for (const node of [...valueNode.nodes].reverse()) {
200
+ for (const node of [...valueNode.nodes].toReversed()) {
201
201
  if (node.type === 'comment') {
202
202
  continue;
203
203
  }
@@ -277,7 +277,7 @@ function fixAfterForAlways (valueNode, newline) {
277
277
  function fixAfterForNever (valueNode) {
278
278
  valueNode.after = '';
279
279
 
280
- for (const node of [...valueNode.nodes].reverse()) {
280
+ for (const node of [...valueNode.nodes].toReversed()) {
281
281
  if (node.type === 'comment') {
282
282
  continue;
283
283
  }
@@ -233,7 +233,7 @@ const rule = (primary, _secondaryOptions) => (root, result) => {
233
233
  * @returns {string}
234
234
  */
235
235
  function removeIndices (str, indices) {
236
- for (const index of indices.reverse()) {
236
+ for (const index of indices.toReversed()) {
237
237
  str = str.slice(0, index) + str.slice(index + 1);
238
238
  }
239
239
 
@@ -78,7 +78,7 @@ const rule = (primary, _secondaryOptions, context) => {
78
78
 
79
79
  if (fixData) {
80
80
  for (const [decl, commaIndices] of fixData.entries()) {
81
- for (const index of commaIndices.sort((a, b) => a - b).reverse()) {
81
+ for (const index of commaIndices.toSorted((a, b) => a - b).toReversed()) {
82
82
  const value = getDeclarationValue(decl);
83
83
  const valueIndex = index - declarationValueIndex(decl);
84
84
  const beforeValue = value.slice(0, valueIndex + 1);
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
 
3
- import configurationError from 'stylelint/lib/utils/configurationError.mjs';
3
+ import { ConfigurationError } from 'stylelint/lib/utils/errors.mjs';
4
4
  import isSingleLineString from 'stylelint/lib/utils/isSingleLineString.mjs';
5
5
  import isWhitespace from 'stylelint/lib/utils/isWhitespace.mjs';
6
6
  import { assertFunction, isNullish } from 'stylelint/lib/utils/validateTypes.mjs';
@@ -144,7 +144,7 @@ export default function whitespaceChecker (targetWhitespace, expectation, messag
144
144
  rejectBefore(messages.rejectedBeforeMultiLine);
145
145
  break;
146
146
  default:
147
- throw configurationError(`Unknown expectation "${expectation}"`);
147
+ throw new ConfigurationError(`Unknown expectation "${expectation}"`);
148
148
  }
149
149
  }
150
150
 
@@ -191,7 +191,7 @@ export default function whitespaceChecker (targetWhitespace, expectation, messag
191
191
  rejectAfter(messages.rejectedAfterMultiLine);
192
192
  break;
193
193
  default:
194
- throw configurationError(`Unknown expectation "${expectation}"`);
194
+ throw new ConfigurationError(`Unknown expectation "${expectation}"`);
195
195
  }
196
196
  }
197
197
 
@@ -1,70 +0,0 @@
1
- /**
2
- * @file CommonJS loader for `linter-bundle-config.js`.
3
- *
4
- * This module has to be CommonJS as it is only used by `eslint` which does not support ESModules.
5
- *
6
- * This workaround is necessary to load async ESModules in sync CommonJS code.
7
- */
8
-
9
- const { Worker, isMainThread, parentPort } = require('node:worker_threads');
10
-
11
- if (isMainThread) {
12
- const worker = new Worker(__filename);
13
-
14
- const sizeSharedArrayBuffer = new SharedArrayBuffer(4);
15
- const sizeInt32 = new Int32Array(sizeSharedArrayBuffer);
16
-
17
- worker.postMessage({ sizeInt32 });
18
-
19
- if (Atomics.wait(sizeInt32, 0, 0, 10_000) !== 'ok') {
20
- throw new Error('No size received');
21
- }
22
-
23
- const dataSharedArrayBuffer = new SharedArrayBuffer((Math.ceil(sizeInt32[0] / 4) << 2));
24
- const dataInt32 = new Int32Array(dataSharedArrayBuffer);
25
-
26
- worker.postMessage({ dataInt32 });
27
-
28
- if (Atomics.wait(dataInt32, 0, 0, 250) !== 'ok') {
29
- throw new Error('No data received');
30
- }
31
-
32
- void worker.terminate();
33
-
34
- const textDecoder = new TextDecoder('utf8');
35
- const content = textDecoder.decode(new Uint8Array(dataSharedArrayBuffer).slice(0, sizeInt32[0]));
36
-
37
- // @ts-expect-error TypeScript complains about the ESModule import, but correctly resolves it and applies the type.
38
- /** @type {import('./linter-bundle-config.js')} */
39
- module.exports = JSON.parse(content);
40
- }
41
- else {
42
- /** @type {Uint8Array} */
43
- let content;
44
-
45
- /**
46
- * Handles requests from the main thread.
47
- *
48
- * @param {{ sizeInt32?: Int32Array; dataInt32?: Int32Array; }} data - Data received from the main thread
49
- * @returns {Promise<void>}
50
- */
51
- const onData = async (data) => {
52
- if (data.sizeInt32) {
53
- const json = JSON.stringify(await import('./linter-bundle-config.js'));
54
-
55
- const textEncoder = new TextEncoder();
56
-
57
- content = textEncoder.encode(json);
58
-
59
- Atomics.store(data.sizeInt32, 0, content.byteLength);
60
- Atomics.notify(data.sizeInt32, 0);
61
- }
62
- else if (data.dataInt32) {
63
- new Uint8Array(data.dataInt32.buffer).set(content);
64
-
65
- Atomics.notify(data.dataInt32, 0);
66
- }
67
- };
68
-
69
- parentPort?.on('message', onData);
70
- }