postcss-nested 5.0.5 → 6.0.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/README.md +8 -113
- package/index.d.ts +25 -14
- package/index.js +245 -94
- package/package.json +4 -4
- package/CHANGELOG.md +0 -110
package/README.md
CHANGED
|
@@ -59,10 +59,12 @@ html {
|
|
|
59
59
|
|
|
60
60
|
Related plugins:
|
|
61
61
|
|
|
62
|
+
* Use [`postcss-atroot`] for `@at-root` at-rule to move nested child
|
|
63
|
+
to the CSS root.
|
|
62
64
|
* Use [`postcss-current-selector`] **after** this plugin if you want
|
|
63
|
-
to use current selector in properties or variables values.
|
|
65
|
+
to use current selector in properties or variables values.
|
|
64
66
|
* Use [`postcss-nested-ancestors`] **before** this plugin if you want
|
|
65
|
-
to reference any ancestor element directly in your selectors with `^&`.
|
|
67
|
+
to reference any ancestor element directly in your selectors with `^&`.
|
|
66
68
|
|
|
67
69
|
Alternatives:
|
|
68
70
|
|
|
@@ -75,121 +77,14 @@ Alternatives:
|
|
|
75
77
|
alt="Sponsored by Evil Martians" width="236" height="54">
|
|
76
78
|
</a>
|
|
77
79
|
|
|
80
|
+
[`postcss-atroot`]: https://github.com/OEvgeny/postcss-atroot
|
|
78
81
|
[`postcss-current-selector`]: https://github.com/komlev/postcss-current-selector
|
|
79
82
|
[`postcss-nested-ancestors`]: https://github.com/toomuchdesign/postcss-nested-ancestors
|
|
80
83
|
[`postcss-nested-props`]: https://github.com/jedmao/postcss-nested-props
|
|
81
|
-
[`postcss-nesting`]: https://github.com/
|
|
84
|
+
[`postcss-nesting`]: https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-nesting
|
|
82
85
|
[CSSWG draft]: https://drafts.csswg.org/css-nesting-1/
|
|
83
86
|
[PostCSS]: https://github.com/postcss/postcss
|
|
84
87
|
|
|
85
88
|
|
|
86
|
-
##
|
|
87
|
-
|
|
88
|
-
**Step 1:** Install plugin:
|
|
89
|
-
|
|
90
|
-
```sh
|
|
91
|
-
npm install --save-dev postcss postcss-nested
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
**Step 2:** Check your project for existing PostCSS config: `postcss.config.js`
|
|
95
|
-
in the project root, `"postcss"` section in `package.json`
|
|
96
|
-
or `postcss` in bundle config.
|
|
97
|
-
|
|
98
|
-
If you do not use PostCSS, add it according to [official docs]
|
|
99
|
-
and set this plugin in settings.
|
|
100
|
-
|
|
101
|
-
**Step 3:** Add the plugin to plugins list:
|
|
102
|
-
|
|
103
|
-
```diff
|
|
104
|
-
module.exports = {
|
|
105
|
-
plugins: [
|
|
106
|
-
+ require('postcss-nested'),
|
|
107
|
-
require('autoprefixer')
|
|
108
|
-
]
|
|
109
|
-
}
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
[official docs]: https://github.com/postcss/postcss#usage
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
## Options
|
|
116
|
-
|
|
117
|
-
### `bubble`
|
|
118
|
-
|
|
119
|
-
By default, plugin will bubble only `@media` and `@supports` at-rules.
|
|
120
|
-
You can add your custom at-rules to this list by `bubble` option:
|
|
121
|
-
|
|
122
|
-
```js
|
|
123
|
-
postcss([ require('postcss-nested')({ bubble: ['phone'] }) ])
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
```css
|
|
127
|
-
/* input */
|
|
128
|
-
a {
|
|
129
|
-
color: white;
|
|
130
|
-
@phone {
|
|
131
|
-
color: black;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
/* output */
|
|
135
|
-
a {
|
|
136
|
-
color: white;
|
|
137
|
-
}
|
|
138
|
-
@phone {
|
|
139
|
-
a {
|
|
140
|
-
color: black;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
### `unwrap`
|
|
147
|
-
|
|
148
|
-
By default, plugin will unwrap only `@font-face`, `@keyframes` and `@document`
|
|
149
|
-
at-rules. You can add your custom at-rules to this list by `unwrap` option:
|
|
150
|
-
|
|
151
|
-
```js
|
|
152
|
-
postcss([ require('postcss-nested')({ unwrap: ['phone'] }) ])
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
```css
|
|
156
|
-
/* input */
|
|
157
|
-
a {
|
|
158
|
-
color: white;
|
|
159
|
-
@phone {
|
|
160
|
-
color: black;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
/* output */
|
|
164
|
-
a {
|
|
165
|
-
color: white;
|
|
166
|
-
}
|
|
167
|
-
@phone {
|
|
168
|
-
color: black;
|
|
169
|
-
}
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
### `preserveEmpty`
|
|
174
|
-
|
|
175
|
-
By default, plugin will strip out any empty selector generated by intermediate
|
|
176
|
-
nesting levels. You can set `preserveEmpty` to `true` to preserve them.
|
|
177
|
-
|
|
178
|
-
```css
|
|
179
|
-
.a {
|
|
180
|
-
.b {
|
|
181
|
-
color: black;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
Will be compiled to:
|
|
187
|
-
|
|
188
|
-
```css
|
|
189
|
-
.a { }
|
|
190
|
-
.a .b {
|
|
191
|
-
color: black;
|
|
192
|
-
}
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
This is especially useful if you want to export the empty classes with `postcss-modules`.
|
|
89
|
+
## Docs
|
|
90
|
+
Read **[full docs](https://github.com/postcss/postcss-nested#readme)** on GitHub.
|
package/index.d.ts
CHANGED
|
@@ -1,30 +1,41 @@
|
|
|
1
|
-
// Original definitions (@types/postcss-nested)
|
|
1
|
+
// Original definitions (@types/postcss-nested)
|
|
2
|
+
// by Maxim Vorontsov <https://github.com/VorontsovMaxim>
|
|
2
3
|
|
|
3
|
-
import { PluginCreator } from 'postcss'
|
|
4
|
+
import { PluginCreator } from 'postcss'
|
|
4
5
|
|
|
5
6
|
declare namespace nested {
|
|
6
7
|
interface Options {
|
|
7
8
|
/**
|
|
8
|
-
* By default, plugin will bubble only
|
|
9
|
-
*
|
|
9
|
+
* By default, plugin will bubble only `@media`, `@supports` and `@layer`
|
|
10
|
+
* at-rules. Use this option to add your custom at-rules to this list.
|
|
10
11
|
*/
|
|
11
|
-
bubble?: string[]
|
|
12
|
+
bubble?: string[]
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
|
-
* By default, plugin will unwrap only
|
|
15
|
-
* You can add your custom at-rules
|
|
15
|
+
* By default, plugin will unwrap only `@font-face`, `@keyframes`,
|
|
16
|
+
* and `@document` at-rules. You can add your custom at-rules
|
|
17
|
+
* to this list by this option.
|
|
16
18
|
*/
|
|
17
|
-
unwrap?: string[]
|
|
19
|
+
unwrap?: string[]
|
|
18
20
|
|
|
19
21
|
/**
|
|
20
|
-
* By default, plugin will strip out any empty selector generated
|
|
21
|
-
* levels. You can set this option to true
|
|
22
|
+
* By default, plugin will strip out any empty selector generated
|
|
23
|
+
* by intermediate nesting levels. You can set this option to `true`
|
|
24
|
+
* to preserve them.
|
|
22
25
|
*/
|
|
23
|
-
preserveEmpty?: boolean
|
|
26
|
+
preserveEmpty?: boolean
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The plugin supports the SCSS custom at-rule `@at-root` which breaks
|
|
30
|
+
* rule blocks out of their nested position. If you want, you can choose
|
|
31
|
+
* a new custom name for this rule in your code.
|
|
32
|
+
*/
|
|
33
|
+
rootRuleName?: string
|
|
24
34
|
}
|
|
25
35
|
|
|
26
|
-
type Nested = PluginCreator<Options
|
|
36
|
+
type Nested = PluginCreator<Options>
|
|
27
37
|
}
|
|
28
38
|
|
|
29
|
-
declare const nested: nested.Nested
|
|
30
|
-
|
|
39
|
+
declare const nested: nested.Nested
|
|
40
|
+
|
|
41
|
+
export = nested
|
package/index.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
+
const { Rule, AtRule } = require('postcss')
|
|
1
2
|
let parser = require('postcss-selector-parser')
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Run a selector string through postcss-selector-parser
|
|
6
|
+
*/
|
|
7
|
+
function parse(rawSelector, rule) {
|
|
4
8
|
let nodes
|
|
5
|
-
let saver = parser(parsed => {
|
|
6
|
-
nodes = parsed
|
|
7
|
-
})
|
|
8
9
|
try {
|
|
9
|
-
|
|
10
|
+
parser(parsed => {
|
|
11
|
+
nodes = parsed
|
|
12
|
+
}).processSync(rawSelector)
|
|
10
13
|
} catch (e) {
|
|
11
|
-
if (
|
|
14
|
+
if (rawSelector.includes(':')) {
|
|
12
15
|
throw rule ? rule.error('Missed semicolon') : e
|
|
13
16
|
} else {
|
|
14
17
|
throw rule ? rule.error(e.message) : e
|
|
@@ -17,19 +20,27 @@ function parse (str, rule) {
|
|
|
17
20
|
return nodes.at(0)
|
|
18
21
|
}
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Replaces the "&" token in a node's selector with the parent selector
|
|
25
|
+
* similar to what SCSS does.
|
|
26
|
+
*
|
|
27
|
+
* Mutates the nodes list
|
|
28
|
+
*/
|
|
29
|
+
function interpolateAmpInSelector(nodes, parent) {
|
|
21
30
|
let replaced = false
|
|
22
|
-
nodes.each(
|
|
23
|
-
if (
|
|
24
|
-
let clonedParent = parent.clone()
|
|
25
|
-
if (
|
|
26
|
-
|
|
31
|
+
nodes.each(node => {
|
|
32
|
+
if (node.type === 'nesting') {
|
|
33
|
+
let clonedParent = parent.clone({})
|
|
34
|
+
if (node.value !== '&') {
|
|
35
|
+
node.replaceWith(
|
|
36
|
+
parse(node.value.replace('&', clonedParent.toString()))
|
|
37
|
+
)
|
|
27
38
|
} else {
|
|
28
|
-
|
|
39
|
+
node.replaceWith(clonedParent)
|
|
29
40
|
}
|
|
30
41
|
replaced = true
|
|
31
|
-
} else if (
|
|
32
|
-
if (
|
|
42
|
+
} else if ('nodes' in node && node.nodes) {
|
|
43
|
+
if (interpolateAmpInSelector(node, parent)) {
|
|
33
44
|
replaced = true
|
|
34
45
|
}
|
|
35
46
|
}
|
|
@@ -37,89 +48,228 @@ function replace (nodes, parent) {
|
|
|
37
48
|
return replaced
|
|
38
49
|
}
|
|
39
50
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Combines parent and child selectors, in a SCSS-like way
|
|
53
|
+
*/
|
|
54
|
+
function mergeSelectors(parent, child) {
|
|
55
|
+
let merged = []
|
|
56
|
+
parent.selectors.forEach(sel => {
|
|
57
|
+
let parentNode = parse(sel, parent)
|
|
58
|
+
|
|
59
|
+
child.selectors.forEach(selector => {
|
|
60
|
+
if (!selector) {
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
let node = parse(selector, child)
|
|
64
|
+
let replaced = interpolateAmpInSelector(node, parentNode)
|
|
65
|
+
if (!replaced) {
|
|
66
|
+
node.prepend(parser.combinator({ value: ' ' }))
|
|
67
|
+
node.prepend(parentNode.clone({}))
|
|
54
68
|
}
|
|
69
|
+
merged.push(node.toString())
|
|
55
70
|
})
|
|
56
71
|
})
|
|
57
|
-
return
|
|
72
|
+
return merged
|
|
58
73
|
}
|
|
59
74
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
75
|
+
/**
|
|
76
|
+
* Move a child and its preceeding comment(s) to after "after"
|
|
77
|
+
*/
|
|
78
|
+
function breakOut(child, after) {
|
|
79
|
+
let prev = child.prev()
|
|
80
|
+
after.after(child)
|
|
81
|
+
while (prev && prev.type === 'comment') {
|
|
82
|
+
let nextPrev = prev.prev()
|
|
83
|
+
after.after(prev)
|
|
84
|
+
prev = nextPrev
|
|
66
85
|
}
|
|
86
|
+
return child
|
|
67
87
|
}
|
|
68
88
|
|
|
69
|
-
function
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
child.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
89
|
+
function createFnAtruleChilds(bubble) {
|
|
90
|
+
return function atruleChilds(rule, atrule, bubbling, mergeSels = bubbling) {
|
|
91
|
+
let children = []
|
|
92
|
+
atrule.each(child => {
|
|
93
|
+
if (child.type === 'rule' && bubbling) {
|
|
94
|
+
if (mergeSels) {
|
|
95
|
+
child.selectors = mergeSelectors(rule, child)
|
|
96
|
+
}
|
|
97
|
+
} else if (child.type === 'atrule' && child.nodes) {
|
|
98
|
+
if (bubble[child.name]) {
|
|
99
|
+
atruleChilds(rule, child, mergeSels)
|
|
100
|
+
} else if (atrule[rootRuleMergeSel] !== false) {
|
|
101
|
+
children.push(child)
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
children.push(child)
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
if (bubbling) {
|
|
108
|
+
if (children.length) {
|
|
109
|
+
let clone = rule.clone({ nodes: [] })
|
|
110
|
+
for (let child of children) {
|
|
111
|
+
clone.append(child)
|
|
112
|
+
}
|
|
113
|
+
atrule.prepend(clone)
|
|
87
114
|
}
|
|
88
|
-
atrule.prepend(clone)
|
|
89
115
|
}
|
|
90
116
|
}
|
|
91
117
|
}
|
|
92
118
|
|
|
93
|
-
function pickDeclarations
|
|
119
|
+
function pickDeclarations(selector, declarations, after) {
|
|
94
120
|
let parent = new Rule({
|
|
95
121
|
selector,
|
|
96
122
|
nodes: []
|
|
97
123
|
})
|
|
98
|
-
|
|
99
|
-
for (let declaration of declarations) {
|
|
100
|
-
parent.append(declaration)
|
|
101
|
-
}
|
|
102
|
-
|
|
124
|
+
parent.append(declarations)
|
|
103
125
|
after.after(parent)
|
|
104
126
|
return parent
|
|
105
127
|
}
|
|
106
128
|
|
|
107
|
-
function atruleNames
|
|
129
|
+
function atruleNames(defaults, custom) {
|
|
108
130
|
let list = {}
|
|
109
|
-
for (let
|
|
110
|
-
list[
|
|
131
|
+
for (let name of defaults) {
|
|
132
|
+
list[name] = true
|
|
111
133
|
}
|
|
112
134
|
if (custom) {
|
|
113
|
-
for (let
|
|
114
|
-
|
|
115
|
-
list[name] = true
|
|
135
|
+
for (let name of custom) {
|
|
136
|
+
list[name.replace(/^@/, '')] = true
|
|
116
137
|
}
|
|
117
138
|
}
|
|
118
139
|
return list
|
|
119
140
|
}
|
|
120
141
|
|
|
142
|
+
function parseRootRuleParams(params) {
|
|
143
|
+
params = params.trim()
|
|
144
|
+
let braceBlock = params.match(/^\((.*)\)$/)
|
|
145
|
+
if (!braceBlock) {
|
|
146
|
+
return { type: 'basic', selector: params }
|
|
147
|
+
}
|
|
148
|
+
let bits = braceBlock[1].match(/^(with(?:out)?):(.+)$/)
|
|
149
|
+
if (bits) {
|
|
150
|
+
let allowlist = bits[1] === 'with'
|
|
151
|
+
let rules = Object.fromEntries(
|
|
152
|
+
bits[2]
|
|
153
|
+
.trim()
|
|
154
|
+
.split(/\s+/)
|
|
155
|
+
.map(name => [name, true])
|
|
156
|
+
)
|
|
157
|
+
if (allowlist && rules.all) {
|
|
158
|
+
return { type: 'noop' }
|
|
159
|
+
}
|
|
160
|
+
let escapes = rule => !!rules[rule]
|
|
161
|
+
if (rules.all) {
|
|
162
|
+
escapes = () => true
|
|
163
|
+
} else if (allowlist) {
|
|
164
|
+
escapes = rule => (rule === 'all' ? false : !rules[rule])
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
type: 'withrules',
|
|
169
|
+
escapes
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
// Unrecognized brace block
|
|
173
|
+
return { type: 'unknown' }
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function getAncestorRules(leaf) {
|
|
177
|
+
let lineage = []
|
|
178
|
+
let parent = leaf.parent
|
|
179
|
+
|
|
180
|
+
while (parent && parent instanceof AtRule) {
|
|
181
|
+
lineage.push(parent)
|
|
182
|
+
parent = parent.parent
|
|
183
|
+
}
|
|
184
|
+
return lineage
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function unwrapRootRule(rule) {
|
|
188
|
+
let escapes = rule[rootRuleEscapes]
|
|
189
|
+
|
|
190
|
+
if (!escapes) {
|
|
191
|
+
rule.after(rule.nodes)
|
|
192
|
+
} else {
|
|
193
|
+
let nodes = rule.nodes
|
|
194
|
+
|
|
195
|
+
let topEscaped
|
|
196
|
+
let topEscapedIdx = -1
|
|
197
|
+
let breakoutLeaf
|
|
198
|
+
let breakoutRoot
|
|
199
|
+
let clone
|
|
200
|
+
|
|
201
|
+
let lineage = getAncestorRules(rule)
|
|
202
|
+
lineage.forEach((parent, i) => {
|
|
203
|
+
if (escapes(parent.name)) {
|
|
204
|
+
topEscaped = parent
|
|
205
|
+
topEscapedIdx = i
|
|
206
|
+
breakoutRoot = clone
|
|
207
|
+
} else {
|
|
208
|
+
let oldClone = clone
|
|
209
|
+
clone = parent.clone({ nodes: [] })
|
|
210
|
+
oldClone && clone.append(oldClone)
|
|
211
|
+
breakoutLeaf = breakoutLeaf || clone
|
|
212
|
+
}
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
if (!topEscaped) {
|
|
216
|
+
rule.after(nodes)
|
|
217
|
+
} else if (!breakoutRoot) {
|
|
218
|
+
topEscaped.after(nodes)
|
|
219
|
+
} else {
|
|
220
|
+
let leaf = breakoutLeaf
|
|
221
|
+
leaf.append(nodes)
|
|
222
|
+
topEscaped.after(breakoutRoot)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (rule.next() && topEscaped) {
|
|
226
|
+
let restRoot
|
|
227
|
+
lineage.slice(0, topEscapedIdx + 1).forEach((parent, i, arr) => {
|
|
228
|
+
let oldRoot = restRoot
|
|
229
|
+
restRoot = parent.clone({ nodes: [] })
|
|
230
|
+
oldRoot && restRoot.append(oldRoot)
|
|
231
|
+
|
|
232
|
+
let nextSibs = []
|
|
233
|
+
let _child = arr[i - 1] || rule
|
|
234
|
+
let next = _child.next()
|
|
235
|
+
while (next) {
|
|
236
|
+
nextSibs.push(next)
|
|
237
|
+
next = next.next()
|
|
238
|
+
}
|
|
239
|
+
restRoot.append(nextSibs)
|
|
240
|
+
})
|
|
241
|
+
restRoot && (breakoutRoot || nodes[nodes.length - 1]).after(restRoot)
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
rule.remove()
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const rootRuleMergeSel = Symbol('rootRuleMergeSel')
|
|
249
|
+
const rootRuleEscapes = Symbol('rootRuleEscapes')
|
|
250
|
+
|
|
251
|
+
function normalizeRootRule(rule) {
|
|
252
|
+
let { params } = rule
|
|
253
|
+
let { type, selector, escapes } = parseRootRuleParams(params)
|
|
254
|
+
if (type === 'unknown') {
|
|
255
|
+
throw rule.error(
|
|
256
|
+
`Unknown @${rule.name} parameter ${JSON.stringify(params)}`
|
|
257
|
+
)
|
|
258
|
+
}
|
|
259
|
+
if (type === 'basic' && selector) {
|
|
260
|
+
let selectorBlock = new Rule({ selector, nodes: rule.nodes })
|
|
261
|
+
rule.removeAll()
|
|
262
|
+
rule.append(selectorBlock)
|
|
263
|
+
}
|
|
264
|
+
rule[rootRuleEscapes] = escapes
|
|
265
|
+
rule[rootRuleMergeSel] = escapes ? !escapes('all') : type === 'noop'
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const hasRootRule = Symbol('hasRootRule')
|
|
269
|
+
|
|
121
270
|
module.exports = (opts = {}) => {
|
|
122
|
-
let bubble = atruleNames(['media', 'supports'], opts.bubble)
|
|
271
|
+
let bubble = atruleNames(['media', 'supports', 'layer'], opts.bubble)
|
|
272
|
+
let atruleChilds = createFnAtruleChilds(bubble)
|
|
123
273
|
let unwrap = atruleNames(
|
|
124
274
|
[
|
|
125
275
|
'document',
|
|
@@ -130,11 +280,20 @@ module.exports = (opts = {}) => {
|
|
|
130
280
|
],
|
|
131
281
|
opts.unwrap
|
|
132
282
|
)
|
|
283
|
+
let rootRuleName = (opts.rootRuleName || 'at-root').replace(/^@/, '')
|
|
133
284
|
let preserveEmpty = opts.preserveEmpty
|
|
134
285
|
|
|
135
286
|
return {
|
|
136
287
|
postcssPlugin: 'postcss-nested',
|
|
137
|
-
|
|
288
|
+
|
|
289
|
+
Once(root) {
|
|
290
|
+
root.walkAtRules(rootRuleName, node => {
|
|
291
|
+
normalizeRootRule(node)
|
|
292
|
+
root[hasRootRule] = true
|
|
293
|
+
})
|
|
294
|
+
},
|
|
295
|
+
|
|
296
|
+
Rule(rule) {
|
|
138
297
|
let unwrapped = false
|
|
139
298
|
let after = rule
|
|
140
299
|
let copyDeclarations = false
|
|
@@ -143,48 +302,33 @@ module.exports = (opts = {}) => {
|
|
|
143
302
|
rule.each(child => {
|
|
144
303
|
if (child.type === 'rule') {
|
|
145
304
|
if (declarations.length) {
|
|
146
|
-
after = pickDeclarations(rule.selector, declarations, after
|
|
305
|
+
after = pickDeclarations(rule.selector, declarations, after)
|
|
147
306
|
declarations = []
|
|
148
307
|
}
|
|
149
308
|
|
|
150
309
|
copyDeclarations = true
|
|
151
310
|
unwrapped = true
|
|
152
|
-
child.selectors =
|
|
153
|
-
after =
|
|
154
|
-
after.after(child)
|
|
155
|
-
after = child
|
|
311
|
+
child.selectors = mergeSelectors(rule, child)
|
|
312
|
+
after = breakOut(child, after)
|
|
156
313
|
} else if (child.type === 'atrule') {
|
|
157
314
|
if (declarations.length) {
|
|
158
|
-
after = pickDeclarations(rule.selector, declarations, after
|
|
315
|
+
after = pickDeclarations(rule.selector, declarations, after)
|
|
159
316
|
declarations = []
|
|
160
317
|
}
|
|
161
|
-
|
|
162
|
-
if (child.name === 'at-root') {
|
|
318
|
+
if (child.name === rootRuleName) {
|
|
163
319
|
unwrapped = true
|
|
164
|
-
atruleChilds(rule, child,
|
|
165
|
-
|
|
166
|
-
let nodes = child.nodes
|
|
167
|
-
if (child.params) {
|
|
168
|
-
nodes = new Rule({ selector: child.params, nodes })
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
after.after(nodes)
|
|
172
|
-
after = nodes
|
|
173
|
-
child.remove()
|
|
320
|
+
atruleChilds(rule, child, true, child[rootRuleMergeSel])
|
|
321
|
+
after = breakOut(child, after)
|
|
174
322
|
} else if (bubble[child.name]) {
|
|
175
323
|
copyDeclarations = true
|
|
176
324
|
unwrapped = true
|
|
177
325
|
atruleChilds(rule, child, true)
|
|
178
|
-
after =
|
|
179
|
-
after.after(child)
|
|
180
|
-
after = child
|
|
326
|
+
after = breakOut(child, after)
|
|
181
327
|
} else if (unwrap[child.name]) {
|
|
182
328
|
copyDeclarations = true
|
|
183
329
|
unwrapped = true
|
|
184
330
|
atruleChilds(rule, child, false)
|
|
185
|
-
after =
|
|
186
|
-
after.after(child)
|
|
187
|
-
after = child
|
|
331
|
+
after = breakOut(child, after)
|
|
188
332
|
} else if (copyDeclarations) {
|
|
189
333
|
declarations.push(child)
|
|
190
334
|
}
|
|
@@ -194,13 +338,20 @@ module.exports = (opts = {}) => {
|
|
|
194
338
|
})
|
|
195
339
|
|
|
196
340
|
if (declarations.length) {
|
|
197
|
-
after = pickDeclarations(rule.selector, declarations, after
|
|
341
|
+
after = pickDeclarations(rule.selector, declarations, after)
|
|
198
342
|
}
|
|
199
343
|
|
|
200
344
|
if (unwrapped && preserveEmpty !== true) {
|
|
201
345
|
rule.raws.semicolon = true
|
|
202
346
|
if (rule.nodes.length === 0) rule.remove()
|
|
203
347
|
}
|
|
348
|
+
},
|
|
349
|
+
|
|
350
|
+
RootExit(root) {
|
|
351
|
+
if (root[hasRootRule]) {
|
|
352
|
+
root.walkAtRules(rootRuleName, unwrapRootRule)
|
|
353
|
+
root[hasRootRule] = false
|
|
354
|
+
}
|
|
204
355
|
}
|
|
205
356
|
}
|
|
206
357
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "postcss-nested",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "PostCSS plugin to unwrap nested rules like how Sass does it",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"postcss",
|
|
@@ -13,16 +13,16 @@
|
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"repository": "postcss/postcss-nested",
|
|
15
15
|
"engines": {
|
|
16
|
-
"node": ">=
|
|
16
|
+
"node": ">=12.0"
|
|
17
17
|
},
|
|
18
18
|
"funding": {
|
|
19
19
|
"type": "opencollective",
|
|
20
20
|
"url": "https://opencollective.com/postcss/"
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {
|
|
23
|
-
"postcss": "^8.
|
|
23
|
+
"postcss": "^8.2.14"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"postcss-selector-parser": "^6.0.
|
|
26
|
+
"postcss-selector-parser": "^6.0.10"
|
|
27
27
|
}
|
|
28
28
|
}
|
package/CHANGELOG.md
DELETED
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
# Change Log
|
|
2
|
-
This project adheres to [Semantic Versioning](http://semver.org/).
|
|
3
|
-
|
|
4
|
-
## 5.0.5
|
|
5
|
-
* Fixed `,` at the tail (by Jesse de Boer).
|
|
6
|
-
|
|
7
|
-
## 5.0.4
|
|
8
|
-
* Fixed nested `&` at the tail (by Raphael Luba).
|
|
9
|
-
* Fixed docs (by Samuel Charpentier).
|
|
10
|
-
|
|
11
|
-
## 5.0.3
|
|
12
|
-
* Fixed compability with Autoprefixer by adding `@-webkit-keyframes` support.
|
|
13
|
-
|
|
14
|
-
## 5.0.2
|
|
15
|
-
* Fixed compatibility with `postcss-mixins` by moving to visitor API.
|
|
16
|
-
|
|
17
|
-
## 5.0.1
|
|
18
|
-
* Fixed PostCSS 8.1 compatibility.
|
|
19
|
-
* Added funding links.
|
|
20
|
-
|
|
21
|
-
## 5.0
|
|
22
|
-
* Moved to PostCSS 8.
|
|
23
|
-
* Moved `postcss` to `peerDependencies`.
|
|
24
|
-
|
|
25
|
-
## 4.2.3
|
|
26
|
-
* Fixed declarations after nested rule and before at-rule (by Rodion Demikhov).
|
|
27
|
-
|
|
28
|
-
## 4.2.2
|
|
29
|
-
* Fixed wrong specificity order of declarations (by Rodion Demikhov).
|
|
30
|
-
|
|
31
|
-
## 4.2.1
|
|
32
|
-
* Fix TypeScript definitions (by Avi Vahl).
|
|
33
|
-
|
|
34
|
-
## 4.2
|
|
35
|
-
* Add `@at-root` support (by Jason Quense).
|
|
36
|
-
|
|
37
|
-
## 4.1.2
|
|
38
|
-
* Improve error messsage on broken selector
|
|
39
|
-
|
|
40
|
-
## 4.1.1
|
|
41
|
-
* Add `&(:hover)` support (by Ben Delarre).
|
|
42
|
-
|
|
43
|
-
## 4.1
|
|
44
|
-
* Add `unwrap` option.
|
|
45
|
-
|
|
46
|
-
## 4.0
|
|
47
|
-
* Use PostCSS 7 (by Aleks Hudochenkov).
|
|
48
|
-
* Remove Node.js 4 support.
|
|
49
|
-
|
|
50
|
-
## 3.0
|
|
51
|
-
* Add `@font-face` to bubbling at-rules (by Valeriy Komlev).
|
|
52
|
-
* Add special logic for `@font-face` bubbling (by Phanindra Pydisetty).
|
|
53
|
-
* Use PostCSS selector parser 3.0.
|
|
54
|
-
|
|
55
|
-
## 2.1.2
|
|
56
|
-
* Fix replacing multiple `&`.
|
|
57
|
-
|
|
58
|
-
## 2.1.1
|
|
59
|
-
* Fix `:not(&)` support.
|
|
60
|
-
|
|
61
|
-
## 2.1
|
|
62
|
-
* Add `preserveEmpty` option (by Federico Zivolo).
|
|
63
|
-
|
|
64
|
-
## 2.0.4
|
|
65
|
-
* Fix finding `&` in some selectors (by Stepan Mikhaylyuk).
|
|
66
|
-
|
|
67
|
-
## 2.0.3
|
|
68
|
-
* Doesn’t replace `&` inside string (by Paul Kiddle).
|
|
69
|
-
|
|
70
|
-
## 2.0.2
|
|
71
|
-
* Fix comments moving regression.
|
|
72
|
-
|
|
73
|
-
## 2.0.1
|
|
74
|
-
* Fix rules order regression (by Dmitry Vibe).
|
|
75
|
-
|
|
76
|
-
## 2.0
|
|
77
|
-
* Use PostCSS 6 API.
|
|
78
|
-
|
|
79
|
-
## 1.0.1
|
|
80
|
-
* Clean up npm package.
|
|
81
|
-
|
|
82
|
-
## 1.0
|
|
83
|
-
* Use PostCSS 5.0 API.
|
|
84
|
-
* Do not add spaces to selector in compressed CSS.
|
|
85
|
-
* Move nodes with its comment above.
|
|
86
|
-
|
|
87
|
-
## 0.3.2
|
|
88
|
-
* Fix `@supports` at-rule support (by Ben Briggs).
|
|
89
|
-
|
|
90
|
-
## 0.3.1
|
|
91
|
-
* Pass PostCSS Plugin Guidelines.
|
|
92
|
-
|
|
93
|
-
## 0.3
|
|
94
|
-
* Do not unwrap custom at-rules.
|
|
95
|
-
* Add `bubble` option to unwrap some custom at-rules.
|
|
96
|
-
* Support PostCSS 4.1 API.
|
|
97
|
-
* Fix last semicolon after unwrapping.
|
|
98
|
-
|
|
99
|
-
## 0.2.2
|
|
100
|
-
* Module returns function to have common PostCSS API.
|
|
101
|
-
|
|
102
|
-
## 0.2.1
|
|
103
|
-
* Add comma support to selectors unwrap.
|
|
104
|
-
|
|
105
|
-
## 0.2
|
|
106
|
-
* Use PostCSS 4.0.
|
|
107
|
-
* Fix indent, when move rules to other parent.
|
|
108
|
-
|
|
109
|
-
## 0.1
|
|
110
|
-
* Initial release.
|