@@ -136,9 +136,10 @@ function truncate(node) {
136
136
* @param {Compiler.Css.Rule } rule
137
137
* @param {Compiler.AST.RegularElement | Compiler.AST.SvelteElement } element
138
138
* @param {Compiler.Css.StyleSheet } stylesheet
139
+ * @param {boolean } [contains_render_tag]
139
140
* @returns {boolean }
140
141
*/
141
- function apply_selector ( relative_selectors , rule , element , stylesheet ) {
142
+ function apply_selector ( relative_selectors , rule , element , stylesheet , contains_render_tag ) {
142
143
const parent_selectors = relative_selectors . slice ( ) ;
143
144
const relative_selector = parent_selectors . pop ( ) ;
144
145
@@ -152,7 +153,19 @@ function apply_selector(relative_selectors, rule, element, stylesheet) {
152
153
) ;
153
154
154
155
if ( ! possible_match ) {
155
- return false ;
156
+ contains_render_tag ??= element . fragment . nodes . some ( ( node ) => node . type === 'RenderTag' ) ;
157
+ if ( contains_render_tag ) {
158
+ // If the element contains a render tag then we assume the selector might match something inside the rendered snippet
159
+ // and traverse the blocks upwards to see if the present blocks match our node further upwards.
160
+ // (We could do more static analysis and check the render tag reference to see if this snippet block continues
161
+ // with elements that actually match the selector, but that would be a lot of work for little gain)
162
+ const possible = apply_selector ( parent_selectors , rule , element , stylesheet , true ) ;
163
+ if ( possible ) return true ; // e.g `div span` matched for element `<div>{@render tag()}</div>`
164
+ // Continue checking if a parent element might match the selector.
165
+ // Example: Selector is `p span`, which matches `<p><strong>{@render tag()}</strong></p>` and we're currently at `strong`
166
+ } else {
167
+ return false ;
168
+ }
156
169
}
157
170
158
171
if ( relative_selector . combinator ) {
@@ -171,6 +184,13 @@ function apply_selector(relative_selectors, rule, element, stylesheet) {
171
184
crossed_component_boundary = true ;
172
185
}
173
186
187
+ if ( parent . type === 'SnippetBlock' ) {
188
+ // We assume the snippet might be rendered in a place where the parent selectors match.
189
+ // (We could do more static analysis and check the render tag reference to see if this snippet block continues
190
+ // with elements that actually match the selector, but that would be a lot of work for little gain)
191
+ return true ;
192
+ }
193
+
174
194
if ( parent . type === 'RegularElement' || parent . type === 'SvelteElement' ) {
175
195
if ( apply_selector ( parent_selectors , rule , parent , stylesheet ) ) {
176
196
// TODO the `name === ' '` causes false positives, but removing it causes false negatives...
@@ -222,6 +242,10 @@ function apply_selector(relative_selectors, rule, element, stylesheet) {
222
242
}
223
243
}
224
244
245
+ // We got to the end of this under the assumption higher up might start matching,
246
+ // but turns out it didn't - therefore the selector doesn't apply after all.
247
+ if ( contains_render_tag ) return false ;
248
+
225
249
// if this is the left-most non-global selector, mark it — we want
226
250
// `x y z {...}` to become `x.blah y z.blah {...}`
227
251
const parent = parent_selectors [ parent_selectors . length - 1 ] ;
0 commit comments