}"
`)
expect(compileScoped(`.foo * { color: red; }`)).toMatchInlineSnapshot(`
- ".foo[data-v-test] * { color: red;
+ ".foo[data-v-test] [data-v-test] { color: red;
+ }"
+ `)
+ expect(compileScoped(`.foo :active { color: red; }`))
+ .toMatchInlineSnapshot(`
+ ".foo[data-v-test] :active { color: red;
+ }"
+ `)
+ expect(compileScoped(`.foo *:active { color: red; }`))
+ .toMatchInlineSnapshot(`
+ ".foo[data-v-test] [data-v-test]:active { color: red;
+ }"
+ `)
+ expect(compileScoped(`.foo * .bar { color: red; }`)).toMatchInlineSnapshot(`
+ ".foo * .bar[data-v-test] { color: red;
+ }"
+ `)
+ expect(compileScoped(`:last-child * { color: red; }`))
+ .toMatchInlineSnapshot(`
+ "[data-v-test]:last-child [data-v-test] { color: red;
+ }"
+ `)
+ expect(compileScoped(`:last-child *:active { color: red; }`))
+ .toMatchInlineSnapshot(`
+ "[data-v-test]:last-child [data-v-test]:active { color: red;
}"
`)
})
slotted = false,
) {
let node: selectorParser.Node | null = null
+ let starNode: selectorParser.Node | null = null
let shouldInject = !deep
// find the last child node to insert attribute selector
selector.each(n => {
return false
}
}
- // .foo * -> .foo[xxxxxxx] *
- if (node) return
+ // store the universal selector so it can be rewritten later
+ // .foo * -> .foo[xxxxxxx] [xxxxxxx]
+ starNode = n
}
if (
- (n.type !== 'pseudo' && n.type !== 'combinator') ||
+ (n.type !== 'pseudo' &&
+ n.type !== 'combinator' &&
+ n.type !== 'universal') ||
(n.type === 'pseudo' &&
(n.value === ':is' || n.value === ':where') &&
!node)
) {
node = n
+ starNode = null
}
})
quoteMark: `"`,
}),
)
+ // Used for trailing universal selectors (#12906)
+ // `.foo * {}` -> `.foo[xxxxxxx] [xxxxxxx] {}`
+ if (starNode) {
+ selector.insertBefore(
+ starNode,
+ selectorParser.attribute({
+ attribute: idToAdd,
+ value: idToAdd,
+ raws: {},
+ quoteMark: `"`,
+ }),
+ )
+ selector.removeChild(starNode)
+ }
}
}