Skip to content

Commit

Permalink
Add CSS Nesting support (fixes #79)
Browse files Browse the repository at this point in the history
- Added `NestingSelector` node type for `&` (a nesting selector) in selectors
- Added `@nest` at-rule
- Changed behaviour for `@media` inside a `Rule` to parse its block content as a `Declaration` first
- Changed `DeclarationList` behaviour to follow the rules for `Rule`'s block
  • Loading branch information
lahmatiy committed Aug 15, 2022
1 parent 50004d5 commit 041239e
Show file tree
Hide file tree
Showing 19 changed files with 1,420 additions and 20 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
@@ -1,3 +1,11 @@
## next

- Added [CSS Nesting](https://www.w3.org/TR/css-nesting-1/) support:
- Added `NestingSelector` node type for `&` (a nesting selector) in selectors
- Added `@nest` at-rule
- Changed behaviour for `@media` inside a `Rule` to parse its block content as a `Declaration` first
- Changed `DeclarationList` behaviour to follow the rules for `Rule`'s block

## 2.2.1 (August 14, 2022)

- Fixed a regression added in `2.2.0` for at-rule syntax matching when at-rule has no prelude
Expand Down
9 changes: 9 additions & 0 deletions docs/ast.md
Expand Up @@ -33,6 +33,7 @@ Interactively explore the AST with [AST Explorer](https://astexplorer.net/#/gist
- [MediaFeature](#mediafeature)
- [MediaQuery](#mediaquery)
- [MediaQueryList](#mediaquerylist)
- [NestingSelector](#nestingselector)
- [Nth](#nth)
- [Number](#number)
- [Operator](#operator)
Expand Down Expand Up @@ -380,6 +381,14 @@ Used for [the An+B microsyntax](https://drafts.csswg.org/css-syntax/#anb-microsy
}
```

### NestingSelector

```js
{
type: "NestingSelector"
}
```

### Nth

```js
Expand Down
52 changes: 52 additions & 0 deletions fixtures/ast/atrule/atrule/nest.json
@@ -0,0 +1,52 @@
{
"single media type": {
"source": "@nest .bar:not(&) {}",
"generate": "@nest.bar:not(&){}",
"ast": {
"type": "Atrule",
"name": "nest",
"prelude": {
"type": "AtrulePrelude",
"children": [
{
"type": "SelectorList",
"children": [
{
"type": "Selector",
"children": [
{
"type": "ClassSelector",
"name": "bar"
},
{
"type": "PseudoClassSelector",
"name": "not",
"children": [
{
"type": "SelectorList",
"children": [
{
"type": "Selector",
"children": [
{
"type": "NestingSelector"
}
]
}
]
}
]
}
]
}
]
}
]
},
"block": {
"type": "Block",
"children": []
}
}
}
}
261 changes: 261 additions & 0 deletions fixtures/ast/declarationList/nesting.json
@@ -0,0 +1,261 @@
{
"basic": {
"source": " color: blue; &:hover { color: green; } @nest :not(&) { color: red; } ",
"generate": "color:blue;&:hover{color:green}@nest :not(&){color:red}",
"ast": {
"type": "DeclarationList",
"children": [
{
"type": "Declaration",
"important": false,
"property": "color",
"value": {
"type": "Value",
"children": [
{
"type": "Identifier",
"name": "blue"
}
]
}
},
{
"type": "Rule",
"prelude": {
"type": "SelectorList",
"children": [
{
"type": "Selector",
"children": [
{
"type": "NestingSelector"
},
{
"type": "PseudoClassSelector",
"name": "hover",
"children": null
}
]
}
]
},
"block": {
"type": "Block",
"children": [
{
"type": "Declaration",
"important": false,
"property": "color",
"value": {
"type": "Value",
"children": [
{
"type": "Identifier",
"name": "green"
}
]
}
}
]
}
},
{
"type": "Atrule",
"name": "nest",
"prelude": {
"type": "AtrulePrelude",
"children": [
{
"type": "SelectorList",
"children": [
{
"type": "Selector",
"children": [
{
"type": "PseudoClassSelector",
"name": "not",
"children": [
{
"type": "SelectorList",
"children": [
{
"type": "Selector",
"children": [
{
"type": "NestingSelector"
}
]
}
]
}
]
}
]
}
]
}
]
},
"block": {
"type": "Block",
"children": [
{
"type": "Declaration",
"important": false,
"property": "color",
"value": {
"type": "Value",
"children": [
{
"type": "Identifier",
"name": "red"
}
]
}
}
]
}
}
]
}
},
"nested @media": {
"source": " color: blue; @media (orientation: landscape) { color: red; @media (min-width: 1024px) { color: green; } } ",
"generate": "color:blue;@media (orientation:landscape){color:red;@media (min-width:1024px){color:green}}",
"ast": {
"type": "DeclarationList",
"children": [
{
"type": "Declaration",
"important": false,
"property": "color",
"value": {
"type": "Value",
"children": [
{
"type": "Identifier",
"name": "blue"
}
]
}
},
{
"type": "Atrule",
"name": "media",
"prelude": {
"type": "AtrulePrelude",
"children": [
{
"type": "MediaQueryList",
"children": [
{
"type": "MediaQuery",
"children": [
{
"type": "MediaFeature",
"name": "orientation",
"value": {
"type": "Identifier",
"name": "landscape"
}
}
]
}
]
}
]
},
"block": {
"type": "Block",
"children": [
{
"type": "Declaration",
"important": false,
"property": "color",
"value": {
"type": "Value",
"children": [
{
"type": "Identifier",
"name": "red"
}
]
}
},
{
"type": "Atrule",
"name": "media",
"prelude": {
"type": "AtrulePrelude",
"children": [
{
"type": "MediaQueryList",
"children": [
{
"type": "MediaQuery",
"children": [
{
"type": "MediaFeature",
"name": "min-width",
"value": {
"type": "Dimension",
"value": "1024",
"unit": "px"
}
}
]
}
]
}
]
},
"block": {
"type": "Block",
"children": [
{
"type": "Declaration",
"important": false,
"property": "color",
"value": {
"type": "Value",
"children": [
{
"type": "Identifier",
"name": "green"
}
]
}
}
]
}
}
]
}
}
]
}
},
"don't parse nested rule when it not started with &": {
"source": ".bar & { color: green; }; div:hover { color: red; }",
"generate": ".bar & { color: green; };div:hover { color: red; }",
"ast": {

"type": "DeclarationList",
"children": [
{
"type": "Raw",
"value": ".bar & { color: green; };"
},
{
"type": "Declaration",
"important": false,
"property": "div",
"value": {
"type": "Raw",
"value": "hover { color: red; }"
}
}
]
}
}
}

0 comments on commit 041239e

Please sign in to comment.