|
|
@@ -1,4 +1,10 @@
|
|
|
-import type { AtRule, PluginCreator, Rule } from 'postcss'
|
|
|
+import {
|
|
|
+ type AtRule,
|
|
|
+ type Container,
|
|
|
+ type Document,
|
|
|
+ type PluginCreator,
|
|
|
+ Rule,
|
|
|
+} from 'postcss'
|
|
|
import selectorParser from 'postcss-selector-parser'
|
|
|
import { warn } from '../warn'
|
|
|
|
|
|
@@ -71,21 +77,32 @@ function processRule(id: string, rule: Rule) {
|
|
|
return
|
|
|
}
|
|
|
processedRules.add(rule)
|
|
|
+ let deep = false
|
|
|
+ let parent: Document | Container | undefined = rule.parent
|
|
|
+ while (parent && parent.type !== 'root') {
|
|
|
+ if ((parent as any).__deep) {
|
|
|
+ deep = true
|
|
|
+ break
|
|
|
+ }
|
|
|
+ parent = parent.parent
|
|
|
+ }
|
|
|
rule.selector = selectorParser(selectorRoot => {
|
|
|
selectorRoot.each(selector => {
|
|
|
- rewriteSelector(id, selector, selectorRoot)
|
|
|
+ rewriteSelector(id, rule, selector, selectorRoot, deep)
|
|
|
})
|
|
|
}).processSync(rule.selector)
|
|
|
}
|
|
|
|
|
|
function rewriteSelector(
|
|
|
id: string,
|
|
|
+ rule: Rule,
|
|
|
selector: selectorParser.Selector,
|
|
|
selectorRoot: selectorParser.Root,
|
|
|
+ deep: boolean,
|
|
|
slotted = false,
|
|
|
) {
|
|
|
let node: selectorParser.Node | null = null
|
|
|
- let shouldInject = true
|
|
|
+ let shouldInject = !deep
|
|
|
// find the last child node to insert attribute selector
|
|
|
selector.each(n => {
|
|
|
// DEPRECATED ">>>" and "/deep/" combinator
|
|
|
@@ -107,6 +124,7 @@ function rewriteSelector(
|
|
|
// deep: inject [id] attribute at the node before the ::v-deep
|
|
|
// combinator.
|
|
|
if (value === ':deep' || value === '::v-deep') {
|
|
|
+ ;(rule as any).__deep = true
|
|
|
if (n.nodes.length) {
|
|
|
// .foo ::v-deep(.bar) -> .foo[xxxxxxx] .bar
|
|
|
// replace the current node with ::v-deep's inner selector
|
|
|
@@ -147,7 +165,14 @@ function rewriteSelector(
|
|
|
// instead.
|
|
|
// ::v-slotted(.foo) -> .foo[xxxxxxx-s]
|
|
|
if (value === ':slotted' || value === '::v-slotted') {
|
|
|
- rewriteSelector(id, n.nodes[0], selectorRoot, true /* slotted */)
|
|
|
+ rewriteSelector(
|
|
|
+ id,
|
|
|
+ rule,
|
|
|
+ n.nodes[0],
|
|
|
+ selectorRoot,
|
|
|
+ deep,
|
|
|
+ true /* slotted */,
|
|
|
+ )
|
|
|
let last: selectorParser.Selector['nodes'][0] = n
|
|
|
n.nodes[0].each(ss => {
|
|
|
selector.insertAfter(last, ss)
|
|
|
@@ -206,11 +231,27 @@ function rewriteSelector(
|
|
|
}
|
|
|
})
|
|
|
|
|
|
+ if (rule.nodes.some(node => node.type === 'rule')) {
|
|
|
+ const deep = (rule as any).__deep
|
|
|
+ const decls = rule.nodes.filter(node => node.type === 'decl')
|
|
|
+ if (!deep && decls.length) {
|
|
|
+ for (const decl of decls) {
|
|
|
+ rule.removeChild(decl)
|
|
|
+ }
|
|
|
+ const hostRule = new Rule({
|
|
|
+ nodes: decls,
|
|
|
+ selector: '&',
|
|
|
+ })
|
|
|
+ rule.prepend(hostRule)
|
|
|
+ }
|
|
|
+ shouldInject = deep
|
|
|
+ }
|
|
|
+
|
|
|
if (node) {
|
|
|
const { type, value } = node as selectorParser.Node
|
|
|
if (type === 'pseudo' && (value === ':is' || value === ':where')) {
|
|
|
;(node as selectorParser.Pseudo).nodes.forEach(value =>
|
|
|
- rewriteSelector(id, value, selectorRoot, slotted),
|
|
|
+ rewriteSelector(id, rule, value, selectorRoot, deep, slotted),
|
|
|
)
|
|
|
shouldInject = false
|
|
|
}
|