linter-bundle 7.9.0 → 7.11.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 +21 -2
- package/eslint/jest.mjs +7 -2
- package/markdownlint/base.json +2 -1
- package/package.json +4 -10
- package/stylelint/index.mjs +10 -8
- package/stylelint/plugins/stylelint-selector-tag-no-without-class.js +106 -11
package/CHANGELOG.md
CHANGED
|
@@ -6,7 +6,24 @@ 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.
|
|
9
|
+
[Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v7.11.0...HEAD)
|
|
10
|
+
|
|
11
|
+
## [7.11.0] - 2025-11-19
|
|
12
|
+
|
|
13
|
+
- [eslint] Update `eslint-plugin-jsdoc`from `61.2.1` to `61.3.0`
|
|
14
|
+
- [eslint/jest] Report Jest version detection output only once (instead of once per thread)
|
|
15
|
+
- [stylelint] Added "transform-box", "transition-behavior" and "interpolate-size" to `order/properties-order` rule, and moved "content-visibility" behind "display", and "box-sizing" behind "all"
|
|
16
|
+
|
|
17
|
+
[Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v7.10.0...v7.11.0)
|
|
18
|
+
|
|
19
|
+
## [7.10.0] - 2025-11-19
|
|
20
|
+
|
|
21
|
+
- [eslint] Updated `@stylistic/eslint-plugin` from `5.6.0` to `5.6.1`
|
|
22
|
+
- [markdown] Updated `markdownlint-cli` from `0.45.0` to `0.46.0``
|
|
23
|
+
- [markdown] Added but disabled [`MD060 - Table column style`](https://github.com/DavidAnson/markdownlint/blob/main/doc/md060.md) rule
|
|
24
|
+
- [stylelint] Added configurable `allowCombinators` option to the `plugin/selector-tag-no-without-class` rule and enabled `>`, `+`, `~` combinators for CSS Modules to avoid false positives
|
|
25
|
+
|
|
26
|
+
[Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v7.9.0...v7.10.0)
|
|
10
27
|
|
|
11
28
|
## [7.9.0] - 2025-11-18
|
|
12
29
|
|
|
@@ -52,6 +69,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
|
52
69
|
- [stylelint] Ignore property casing for `composes` in `value-keyword-case`rule
|
|
53
70
|
- [stylelint] Add `composes` to the ignored property list of the `scss/property-no-unknown` rule
|
|
54
71
|
|
|
72
|
+
[Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v7.8.0...v7.9.0)
|
|
73
|
+
|
|
55
74
|
## [7.8.0] - 2025-08-21
|
|
56
75
|
|
|
57
76
|
### Changed
|
|
@@ -1657,7 +1676,7 @@ Beside these changes:
|
|
|
1657
1676
|
### Changed
|
|
1658
1677
|
|
|
1659
1678
|
- [eslint] Updated `@typescript-eslint` from v4.24.0 to v4.25.0
|
|
1660
|
-
- [eslint] Updated `eslint-plugin-jsdoc` from v34.8.2 to v35.0.0
|
|
1679
|
+
- [eslint] Updated `eslint-plugin-jsdoc` from v34.8.2 to v35.0.0
|
|
1661
1680
|
- [eslint] Activated `ignoreNonDOM` option for [`jsx-a11y/no-autofocus`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-autofocus.md) rule
|
|
1662
1681
|
|
|
1663
1682
|
[Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v1.20.0...v1.21.0)
|
package/eslint/jest.mjs
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { createRequire } from 'node:module';
|
|
6
|
+
import { isMainThread } from 'node:worker_threads';
|
|
6
7
|
|
|
7
8
|
import jestPlugin from 'eslint-plugin-jest';
|
|
8
9
|
import globals from 'globals';
|
|
@@ -165,12 +166,16 @@ async function getJestVersion () {
|
|
|
165
166
|
const jest = ('default' in jestModule ? jestModule.default : jestModule);
|
|
166
167
|
const version = jest.getVersion().split('.')[0];
|
|
167
168
|
|
|
168
|
-
|
|
169
|
+
if (isMainThread) {
|
|
170
|
+
process.stdout.write(`Detected Jest version: ${version}\n\n`);
|
|
171
|
+
}
|
|
169
172
|
|
|
170
173
|
return version;
|
|
171
174
|
}
|
|
172
175
|
catch {
|
|
173
|
-
|
|
176
|
+
if (isMainThread) {
|
|
177
|
+
process.stderr.write('No Jest version detected\n\n');
|
|
178
|
+
}
|
|
174
179
|
|
|
175
180
|
return 'detect';
|
|
176
181
|
}
|
package/markdownlint/base.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "linter-bundle",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.11.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": [
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"_test-stylelint": "node ./test-stylelint.js"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@stylistic/eslint-plugin": "5.6.
|
|
45
|
+
"@stylistic/eslint-plugin": "5.6.1",
|
|
46
46
|
"eslint": "9.39.1",
|
|
47
47
|
"eslint-formatter-unix": "9.0.1",
|
|
48
48
|
"eslint-import-resolver-typescript": "4.4.4",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"eslint-plugin-functional": "9.0.2",
|
|
52
52
|
"eslint-plugin-import": "2.32.0",
|
|
53
53
|
"eslint-plugin-jest": "29.1.0",
|
|
54
|
-
"eslint-plugin-jsdoc": "61.
|
|
54
|
+
"eslint-plugin-jsdoc": "61.3.0",
|
|
55
55
|
"eslint-plugin-jsx-a11y": "6.10.2",
|
|
56
56
|
"eslint-plugin-n": "17.23.1",
|
|
57
57
|
"eslint-plugin-promise": "7.2.1",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"eslint-plugin-react-hooks": "7.0.1",
|
|
60
60
|
"eslint-plugin-unicorn": "62.0.0",
|
|
61
61
|
"globals": "16.5.0",
|
|
62
|
-
"markdownlint-cli": "0.
|
|
62
|
+
"markdownlint-cli": "0.46.0",
|
|
63
63
|
"micromatch": "4.0.8",
|
|
64
64
|
"postcss-scss": "4.0.9",
|
|
65
65
|
"stylelint": "16.25.0",
|
|
@@ -81,11 +81,5 @@
|
|
|
81
81
|
"@types/node": "24.10.1",
|
|
82
82
|
"stylelint-find-new-rules": "5.0.0",
|
|
83
83
|
"typescript": "5.9.3"
|
|
84
|
-
},
|
|
85
|
-
"overrides": {
|
|
86
|
-
"glob": "12.0.0"
|
|
87
|
-
},
|
|
88
|
-
"resolutions": {
|
|
89
|
-
"glob": "12.0.0"
|
|
90
84
|
}
|
|
91
85
|
}
|
package/stylelint/index.mjs
CHANGED
|
@@ -130,7 +130,7 @@ export default {
|
|
|
130
130
|
*
|
|
131
131
|
* @see https://github.com/Moxio/stylelint-selector-tag-no-without-class
|
|
132
132
|
*/
|
|
133
|
-
'plugin/selector-tag-no-without-class': ['/./']
|
|
133
|
+
'plugin/selector-tag-no-without-class': [['/./'], { allowCombinators: ['>', '+', '~'] }]
|
|
134
134
|
}
|
|
135
135
|
},
|
|
136
136
|
{
|
|
@@ -577,14 +577,15 @@ export default {
|
|
|
577
577
|
'order/properties-order': [
|
|
578
578
|
[
|
|
579
579
|
{
|
|
580
|
-
groupName: 'Reset',
|
|
580
|
+
groupName: 'Reset & Defaults',
|
|
581
581
|
emptyLineBefore: 'always',
|
|
582
582
|
noEmptyLineBetween: true,
|
|
583
583
|
properties: [
|
|
584
|
-
'all'
|
|
584
|
+
'all',
|
|
585
|
+
'box-sizing',
|
|
586
|
+
'interpolate-size'
|
|
585
587
|
]
|
|
586
588
|
},
|
|
587
|
-
|
|
588
589
|
{
|
|
589
590
|
groupName: 'Performance Optimizations',
|
|
590
591
|
emptyLineBefore: 'always',
|
|
@@ -611,6 +612,7 @@ export default {
|
|
|
611
612
|
noEmptyLineBetween: true,
|
|
612
613
|
properties: [
|
|
613
614
|
'display',
|
|
615
|
+
'content-visibility',
|
|
614
616
|
'visibility',
|
|
615
617
|
|
|
616
618
|
'appearance',
|
|
@@ -635,9 +637,7 @@ export default {
|
|
|
635
637
|
'inset-block-end',
|
|
636
638
|
'inset-inline',
|
|
637
639
|
'inset-inline-start',
|
|
638
|
-
'inset-inline-end'
|
|
639
|
-
|
|
640
|
-
'box-sizing'
|
|
640
|
+
'inset-inline-end'
|
|
641
641
|
]
|
|
642
642
|
},
|
|
643
643
|
{
|
|
@@ -829,6 +829,7 @@ export default {
|
|
|
829
829
|
properties: [
|
|
830
830
|
'transform',
|
|
831
831
|
'transform-origin',
|
|
832
|
+
'transform-box',
|
|
832
833
|
'transform-style',
|
|
833
834
|
'backface-visibility',
|
|
834
835
|
'perspective',
|
|
@@ -844,7 +845,8 @@ export default {
|
|
|
844
845
|
'transition-property',
|
|
845
846
|
'transition-duration',
|
|
846
847
|
'transition-timing-function',
|
|
847
|
-
'transition-delay'
|
|
848
|
+
'transition-delay',
|
|
849
|
+
'transition-behavior'
|
|
848
850
|
]
|
|
849
851
|
},
|
|
850
852
|
{
|
|
@@ -22,26 +22,121 @@ const messages = stylelint.utils.ruleMessages(ruleName, {
|
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
// @ts-expect-error -- Parameter 'primaryOption' implicitly has an 'any' type.
|
|
25
|
-
function rule (primaryOption) {
|
|
25
|
+
function rule (primaryOption, secondaryOptions = {}) {
|
|
26
26
|
// @ts-expect-error -- Parameter 'root' implicitly has an 'any' type. / Parameter 'result' implicitly has an 'any' type.
|
|
27
27
|
return (root, result) => {
|
|
28
|
-
const validOptions = stylelint.utils.validateOptions(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
const validOptions = stylelint.utils.validateOptions(
|
|
29
|
+
result,
|
|
30
|
+
ruleName,
|
|
31
|
+
{
|
|
32
|
+
actual: primaryOption,
|
|
33
|
+
possible: [(string) => (typeof string === 'string' || Object.prototype.toString.call(string) === '[object String]')]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
actual: secondaryOptions,
|
|
37
|
+
possible: {
|
|
38
|
+
allowCombinators: [' ', '+', '>', '~', '||']
|
|
39
|
+
},
|
|
40
|
+
optional: true
|
|
41
|
+
}
|
|
42
|
+
);
|
|
32
43
|
|
|
33
44
|
if (!validOptions) {
|
|
34
45
|
return;
|
|
35
46
|
}
|
|
36
47
|
|
|
48
|
+
/** @type {{ allowCombinators?: string | string[] }} */
|
|
49
|
+
const typedSecondaryOptions = secondaryOptions;
|
|
50
|
+
const allowCombinatorsOption = typedSecondaryOptions.allowCombinators;
|
|
51
|
+
const allowCombinatorValues = allowCombinatorsOption === undefined ? [] : (Array.isArray(allowCombinatorsOption) ? allowCombinatorsOption : [allowCombinatorsOption]);
|
|
52
|
+
/** @type {string[]} */
|
|
53
|
+
const normalizedAllowedCombinators = [];
|
|
54
|
+
for (const combinator of allowCombinatorValues) {
|
|
55
|
+
if (combinator.length === 0) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
normalizedAllowedCombinators.push(normalizeCombinatorValue(combinator));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const allowedCombinators = new Set(normalizedAllowedCombinators);
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @param {string | undefined} value
|
|
66
|
+
* @returns {string}
|
|
67
|
+
*/
|
|
68
|
+
function normalizeCombinatorValue (value) {
|
|
69
|
+
if (typeof value !== 'string') {
|
|
70
|
+
return '';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return value.trim() === '' ? ' ' : value.trim();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @param {import('postcss-selector-parser').Selector} selectorNode
|
|
78
|
+
*/
|
|
79
|
+
function splitSelectorIntoSegments (selectorNode) {
|
|
80
|
+
/** @type {{ nodes: import('postcss-selector-parser').Node[], leadingCombinator?: string }[]} */
|
|
81
|
+
const segments = [];
|
|
82
|
+
/** @type {import('postcss-selector-parser').Node[]} */
|
|
83
|
+
let currentSegment = [];
|
|
84
|
+
/** @type {string | undefined} */
|
|
85
|
+
let leadingCombinator;
|
|
86
|
+
|
|
87
|
+
function pushCurrentSegment () {
|
|
88
|
+
if (currentSegment.length === 0) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const segmentNodes = currentSegment;
|
|
93
|
+
currentSegment = [];
|
|
94
|
+
|
|
95
|
+
/** @type {{ nodes: import('postcss-selector-parser').Node[], leadingCombinator?: string }} */
|
|
96
|
+
const segment = { nodes: segmentNodes };
|
|
97
|
+
|
|
98
|
+
if (leadingCombinator !== undefined) {
|
|
99
|
+
segment.leadingCombinator = leadingCombinator;
|
|
100
|
+
leadingCombinator = undefined;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
segments.push(segment);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
selectorNode.each((/** @type {import('postcss-selector-parser').Node} */ child) => {
|
|
107
|
+
if (child.type === 'combinator') {
|
|
108
|
+
pushCurrentSegment();
|
|
109
|
+
leadingCombinator = normalizeCombinatorValue(child.value);
|
|
110
|
+
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
currentSegment.push(child);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
pushCurrentSegment();
|
|
118
|
+
|
|
119
|
+
return segments;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @param {string | undefined} leadingCombinator
|
|
124
|
+
*/
|
|
125
|
+
function shouldIgnoreSegment (leadingCombinator) {
|
|
126
|
+
if (!leadingCombinator || allowedCombinators.size === 0) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return allowedCombinators.has(leadingCombinator);
|
|
131
|
+
}
|
|
132
|
+
|
|
37
133
|
// @ts-expect-error -- Parameter 'selectorNode' implicitly has an 'any' type. / Parameter 'ruleNode' implicitly has an 'any' type.
|
|
38
134
|
function checkSelector (selectorNode, ruleNode) {
|
|
39
|
-
|
|
40
|
-
const combinedSegments = selectorNode.split((node) => (node.type === 'combinator'));
|
|
135
|
+
const segments = splitSelectorIntoSegments(selectorNode);
|
|
41
136
|
|
|
42
|
-
for (const segment of
|
|
137
|
+
for (const segment of segments) {
|
|
43
138
|
let unqualifiedTagNode;
|
|
44
|
-
for (const node of segment) {
|
|
139
|
+
for (const node of segment.nodes) {
|
|
45
140
|
if (node.type === 'tag' && matchesStringOrRegExp(node.value, primaryOption)) {
|
|
46
141
|
unqualifiedTagNode = node;
|
|
47
142
|
}
|
|
@@ -50,13 +145,13 @@ function rule (primaryOption) {
|
|
|
50
145
|
}
|
|
51
146
|
}
|
|
52
147
|
|
|
53
|
-
if (unqualifiedTagNode) {
|
|
148
|
+
if (unqualifiedTagNode && !shouldIgnoreSegment(segment.leadingCombinator)) {
|
|
54
149
|
stylelint.utils.report({
|
|
55
150
|
ruleName,
|
|
56
151
|
result,
|
|
57
152
|
node: ruleNode,
|
|
58
153
|
message: messages.unexpected(unqualifiedTagNode.value),
|
|
59
|
-
word: unqualifiedTagNode
|
|
154
|
+
word: unqualifiedTagNode.value
|
|
60
155
|
});
|
|
61
156
|
}
|
|
62
157
|
}
|