From: thecodewarrior Date: Thu, 22 May 2025 00:41:27 +0000 (-0700) Subject: fix(compiler-sfc): add scoping tag to trailing universal selector (#12918) X-Git-Tag: v3.5.15~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=949df808809fd7cccf7718797beab0654aa68302;p=thirdparty%2Fvuejs%2Fcore.git fix(compiler-sfc): add scoping tag to trailing universal selector (#12918) close #12906 --- diff --git a/packages/compiler-sfc/__tests__/compileStyle.spec.ts b/packages/compiler-sfc/__tests__/compileStyle.spec.ts index 78fd52425e..70c6af557a 100644 --- a/packages/compiler-sfc/__tests__/compileStyle.spec.ts +++ b/packages/compiler-sfc/__tests__/compileStyle.spec.ts @@ -493,7 +493,31 @@ describe('SFC style preprocessors', () => { }" `) 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; }" `) }) diff --git a/packages/compiler-sfc/src/style/pluginScoped.ts b/packages/compiler-sfc/src/style/pluginScoped.ts index d0aaddd767..4845d8eee3 100644 --- a/packages/compiler-sfc/src/style/pluginScoped.ts +++ b/packages/compiler-sfc/src/style/pluginScoped.ts @@ -102,6 +102,7 @@ function rewriteSelector( 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 => { @@ -216,17 +217,21 @@ function rewriteSelector( 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 } }) @@ -274,6 +279,20 @@ function rewriteSelector( 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) + } } }