Skip to content

Commit b478202

Browse files
jrmltjeddy3ybiquitous
authored
Add ignoreAtRules: [] to no-invalid-position-declaration (#8781)
Co-authored-by: Richard Hallows <jeddy3@users.noreply.github.com> Co-authored-by: Masafumi Koba <473530+ybiquitous@users.noreply.github.com>
1 parent c604f91 commit b478202

File tree

5 files changed

+130
-7
lines changed

5 files changed

+130
-7
lines changed

lib/rules/no-invalid-position-declaration/README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,53 @@ a { --foo: red; }
6060
}
6161
}
6262
```
63+
64+
<!-- prettier-ignore -->
65+
```css
66+
a {
67+
@media all {
68+
color: red;
69+
}
70+
}
71+
```
72+
73+
## Optional secondary options
74+
75+
### `ignoreAtRules`
76+
77+
```json
78+
{ "ignoreAtRules": ["array", "of", "at-rules", "/regex/"] }
79+
```
80+
81+
Ignore nesting at-rules within specified at-rules.
82+
83+
Given:
84+
85+
```json
86+
{
87+
"no-invalid-position-declaration": [
88+
true,
89+
{ "ignoreAtRules": ["--foo", "/^--bar-/"] }
90+
]
91+
}
92+
```
93+
94+
The following patterns are _not_ considered problems:
95+
96+
<!-- prettier-ignore -->
97+
```css
98+
@--foo {
99+
@media all {
100+
color: red;
101+
}
102+
}
103+
```
104+
105+
<!-- prettier-ignore -->
106+
```css
107+
@--bar-baz qux {
108+
@layer foo {
109+
color: red;
110+
}
111+
}
112+
```

lib/rules/no-invalid-position-declaration/__tests__/index.mjs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,3 +352,36 @@ testRule({
352352
},
353353
],
354354
});
355+
356+
testRule({
357+
ruleName,
358+
config: [true, { ignoreAtRules: ['--foo', '/^--bar-/'] }],
359+
360+
accept: [
361+
{
362+
code: '@--foo { @media all { color: red; } }',
363+
},
364+
{
365+
code: '@--bar-baz qux { @media all { color: red; } }',
366+
},
367+
],
368+
369+
reject: [
370+
{
371+
code: '@foo { @media all { color: red; } }',
372+
message: messages.rejected,
373+
line: 1,
374+
column: 21,
375+
endLine: 1,
376+
endColumn: 32,
377+
},
378+
{
379+
code: '@--bar { @media all { color: red; } }',
380+
message: messages.rejected,
381+
line: 1,
382+
column: 23,
383+
endLine: 1,
384+
endColumn: 34,
385+
},
386+
],
387+
});

lib/rules/no-invalid-position-declaration/index.cjs

Lines changed: 23 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/rules/no-invalid-position-declaration/index.mjs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { isAtRule, isRule } from '../../utils/typeGuards.mjs';
2+
import { isRegExp, isString } from '../../utils/validateTypes.mjs';
23
import findNodeUpToRoot from '../../utils/findNodeUpToRoot.mjs';
34
import isInDocument from '../../utils/isInDocument.mjs';
45
import isStandardSyntaxDeclaration from '../../utils/isStandardSyntaxDeclaration.mjs';
56
import { nestingSupportedAtKeywords } from '../../reference/atKeywords.mjs';
7+
import optionsMatches from '../../utils/optionsMatches.mjs';
68
import report from '../../utils/report.mjs';
79
import ruleMessages from '../../utils/ruleMessages.mjs';
810
import validateOptions from '../../utils/validateOptions.mjs';
@@ -18,12 +20,27 @@ const meta = {
1820
};
1921

2022
/** @type {import('stylelint').CoreRules[ruleName]} */
21-
const rule = (primary) => {
23+
const rule = (primary, secondaryOptions) => {
2224
return (root, result) => {
23-
const validOptions = validateOptions(result, ruleName, { actual: primary });
25+
const validOptions = validateOptions(
26+
result,
27+
ruleName,
28+
{ actual: primary, possible: [true] },
29+
{
30+
actual: secondaryOptions,
31+
possible: {
32+
ignoreAtRules: [isString, isRegExp],
33+
},
34+
optional: true,
35+
},
36+
);
2437

2538
if (!validOptions) return;
2639

40+
/** @type {(node: import('postcss').Node) => boolean} */
41+
const isIgnoredAtRule = (node) =>
42+
isAtRule(node) && optionsMatches(secondaryOptions, 'ignoreAtRules', node.name);
43+
2744
root.walkDecls((decl) => {
2845
// Skip checking declarations in embedded styles
2946
if (isInDocument(decl)) return;
@@ -42,7 +59,10 @@ const rule = (primary) => {
4259

4360
// Nesting-supported at-rules only allow declarations when nested inside a rule
4461
if (nestingSupportedAtKeywords.has(atRuleName)) {
45-
const parentRule = findNodeUpToRoot(decl, ({ type }) => type === 'rule');
62+
const parentRule = findNodeUpToRoot(
63+
decl,
64+
(node) => isRule(node) || isIgnoredAtRule(node),
65+
);
4666

4767
if (parentRule) return;
4868
} else {

types/stylelint/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -804,7 +804,7 @@ declare namespace stylelint {
804804
true,
805805
{ ignoreAtRules: OneOrMany<StringOrRegex> }
806806
>;
807-
'no-invalid-position-declaration': CoreRule<true>;
807+
'no-invalid-position-declaration': CoreRule<true, { ignoreAtRules: OneOrMany<StringOrRegex> }>;
808808
'no-irregular-whitespace': CoreRule<true>;
809809
'no-unknown-animations': CoreRule<true, {}, RejectedMessage<[name: string]>>;
810810
'no-unknown-custom-media': CoreRule<true, {}, RejectedMessage<[name: string]>>;

0 commit comments

Comments
 (0)