Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add selector-not-notation #5975

Merged
merged 1 commit into from Mar 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/user-guide/rules/list.md
Expand Up @@ -198,6 +198,7 @@ Within each cateogory, the rules are grouped by the [_thing_](http://apps.workfl
- [`selector-nested-pattern`](../../../lib/rules/selector-nested-pattern/README.md): Specify a pattern for the selectors of rules nested within rules.
- [`selector-no-qualifying-type`](../../../lib/rules/selector-no-qualifying-type/README.md): Disallow qualifying a selector by type.
- [`selector-no-vendor-prefix`](../../../lib/rules/selector-no-vendor-prefix/README.md): Disallow vendor prefixes for selectors (Autofixable).
- [`selector-not-notation`](../../../lib/rules/selector-not-notation/README.md): Specify simple or complex notation for `:not()` pseudo-classes (Autofixable).
- [`selector-pseudo-class-allowed-list`](../../../lib/rules/selector-pseudo-class-allowed-list/README.md): Specify a list of allowed pseudo-class selectors.
- [`selector-pseudo-class-disallowed-list`](../../../lib/rules/selector-pseudo-class-disallowed-list/README.md): Specify a list of disallowed pseudo-class selectors.
- [`selector-pseudo-element-allowed-list`](../../../lib/rules/selector-pseudo-element-allowed-list/README.md): Specify a list of allowed pseudo-element selectors.
Expand Down
1 change: 1 addition & 0 deletions lib/rules/index.js
Expand Up @@ -214,6 +214,7 @@ const rules = {
'selector-nested-pattern': importLazy('./selector-nested-pattern'),
'selector-no-qualifying-type': importLazy('./selector-no-qualifying-type'),
'selector-no-vendor-prefix': importLazy('./selector-no-vendor-prefix'),
'selector-not-notation': importLazy('./selector-not-notation'),
'selector-pseudo-class-allowed-list': importLazy('./selector-pseudo-class-allowed-list'),
'selector-pseudo-class-case': importLazy('./selector-pseudo-class-case'),
'selector-pseudo-class-disallowed-list': importLazy('./selector-pseudo-class-disallowed-list'),
Expand Down
75 changes: 75 additions & 0 deletions lib/rules/selector-not-notation/README.md
@@ -0,0 +1,75 @@
# selector-not-notation

Mouvedia marked this conversation as resolved.
Show resolved Hide resolved
Specify simple or complex notation for `:not()` pseudo-classes.

<!-- prettier-ignore -->
```css
a:not(.foo, .bar) {}
/** ↑
* This notation */
```

In Selectors Level 3, only a single _simple selector_ was allowed as the argument to `:not()`, whereas Selectors Level 4 allows a _selector list_.

Use:

- `"complex"` to author modern Selectors Level 4 CSS
- `"simple"` for backwards compatibility with older browsers

The [`fix` option](../../../docs/user-guide/usage/options.md#fix) option can automatically fix most of the problems reported by this rule.

## Options

`string`: `"simple"|"complex"`

### `"simple"`

The following patterns are considered problems:

<!-- prettier-ignore -->
```css
:not(a, div) {}
```

<!-- prettier-ignore -->
```css
:not(a.foo) {}
```

The following patterns are _not_ considered problems:

<!-- prettier-ignore -->
```css
:not(a):not(div) {}
```

<!-- prettier-ignore -->
```css
:not(a) {}
```

### `"complex"`

The following pattern is considered a problem:

<!-- prettier-ignore -->
```css
:not(a):not(div) {}
```

The following patterns are _not_ considered problems:

<!-- prettier-ignore -->
```css
:not(a, div) {}
```

<!-- prettier-ignore -->
```css
:not(a.foo) {}
```

<!-- prettier-ignore -->
```css
:not(a).foo:not(:empty) {}
```
117 changes: 117 additions & 0 deletions lib/rules/selector-not-notation/__tests__/index.js
@@ -0,0 +1,117 @@
'use strict';

const { messages, ruleName } = require('..');

testRule({
ruleName,
config: ['simple'],
fix: true,

accept: [
{
code: ':not() {}',
},
{
code: ':not( a ) {}',
},
{
code: ':nOt(a) {}',
},
{
code: ':not(*) {}',
},
{
code: ':not(:link) {}',
},
{
code: ':not(.foo) {}',
},
{
code: ':not([title]) {}',
},
],

reject: [
{
code: ':not(:not()) {}',
unfixable: true,
message: messages.expected('simple'),
line: 1,
column: 1,
},
{
code: ':not(::before) {}',
unfixable: true,
message: messages.expected('simple'),
line: 1,
column: 1,
},
{
code: ':not(:first-line) {}',
unfixable: true,
message: messages.expected('simple'),
line: 1,
column: 1,
},
{
code: ':not(a, div) {}',
fixed: ':not(a):not(div) {}',
message: messages.expected('simple'),
line: 1,
column: 1,
},
{
code: ':not(a ,) {}',
fixed: ':not(a) {}',
message: messages.expected('simple'),
line: 1,
column: 1,
},
{
code: ':not(a.foo) {}',
unfixable: true,
message: messages.expected('simple'),
line: 1,
column: 1,
},
],
});

testRule({
ruleName,
config: ['complex'],
fix: true,

accept: [
{
code: ':not()::after {}',
},
{
code: ':not(a, div) {}',
},
{
code: ':not(a.foo) {}',
},
{
code: ':not(a).foo:not(:empty) {}',
},
],

reject: [
{
code: ':not( .foo ,:hover ):not(a,div) {}',
fixed: ':not(.foo, :hover, a, div) {}',
message: messages.expected('complex'),
line: 1,
column: 21,
},
{
code: ':not():not(a) {}',
fixed: ':not(a) {}',
message: messages.expected('complex'),
line: 1,
column: 7,
skip: true,
Mouvedia marked this conversation as resolved.
Show resolved Hide resolved
},
],
});