Skip to content

Commit 04da87b

Browse files
fix: prevent invalid :global usage (#12474)
* fix: prevent invalid `:global` usage Error when it's not at the end of a selector closes #12437 * fix validation * fix * fix types --------- Co-authored-by: Rich Harris <[email protected]>
1 parent bc9907a commit 04da87b

File tree

5 files changed

+55
-10
lines changed

5 files changed

+55
-10
lines changed

packages/svelte/messages/compile-errors/style.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222

2323
> A :global {...} block cannot modify an existing selector
2424
25+
## css_global_block_invalid_placement
26+
27+
> A :global {...} block can only appear at the end of a selector sequence (did you mean to use :global(...) instead?)
28+
2529
## css_global_invalid_placement
2630

2731
> :global(...) can be at the start or end of a selector sequence, but not in the middle

packages/svelte/src/compiler/errors.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,15 @@ export function css_global_block_invalid_modifier(node) {
470470
e(node, "css_global_block_invalid_modifier", "A :global {...} block cannot modify an existing selector");
471471
}
472472

473+
/**
474+
* A :global {...} block can only appear at the end of a selector sequence (did you mean to use :global(...) instead?)
475+
* @param {null | number | NodeLike} node
476+
* @returns {never}
477+
*/
478+
export function css_global_block_invalid_placement(node) {
479+
e(node, "css_global_block_invalid_placement", "A :global {...} block can only appear at the end of a selector sequence (did you mean to use :global(...) instead?)");
480+
}
481+
473482
/**
474483
* :global(...) can be at the start or end of a selector sequence, but not in the middle
475484
* @param {null | number | NodeLike} node

packages/svelte/src/compiler/phases/2-analyze/css/css-analyze.js

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ import { merge } from '../../visitors.js';
1616
* >} CssVisitors
1717
*/
1818

19-
/** @param {Css.RelativeSelector} relative_selector */
19+
/**
20+
* True if is `:global(...)` or `:global`
21+
* @param {Css.RelativeSelector} relative_selector
22+
* @returns {relative_selector is Css.RelativeSelector & { selectors: [Css.PseudoClassSelector, ...Array<Css.PseudoClassSelector | Css.PseudoElementSelector>] }}
23+
*/
2024
function is_global(relative_selector) {
2125
const first = relative_selector.selectors[0];
2226

@@ -135,16 +139,26 @@ const validation_visitors = {
135139

136140
context.next();
137141
},
138-
ComplexSelector(node, context) {
139-
// ensure `:global(...)` is not used in the middle of a selector
142+
ComplexSelector(node) {
140143
{
141-
const a = node.children.findIndex((child) => !is_global(child));
142-
const b = node.children.findLastIndex((child) => !is_global(child));
143-
144-
if (a !== b) {
145-
for (let i = a; i <= b; i += 1) {
146-
if (is_global(node.children[i])) {
147-
e.css_global_invalid_placement(node.children[i].selectors[0]);
144+
const global = node.children.find(is_global);
145+
146+
if (global) {
147+
const idx = node.children.indexOf(global);
148+
149+
if (global.selectors[0].args === null && idx !== node.children.length - 1) {
150+
// ensure `:global` is only at the end of a selector
151+
e.css_global_block_invalid_placement(global.selectors[0]);
152+
} else if (
153+
global.selectors[0].args !== null &&
154+
idx !== 0 &&
155+
idx !== node.children.length - 1
156+
) {
157+
// ensure `:global(...)` is not used in the middle of a selector (but multiple `global(...)` in sequence are ok)
158+
for (let i = idx + 1; i < node.children.length; i++) {
159+
if (!is_global(node.children[i])) {
160+
e.css_global_invalid_placement(global.selectors[0]);
161+
}
148162
}
149163
}
150164
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
error: {
5+
code: 'css_global_block_invalid_placement',
6+
message:
7+
'A :global {...} block can only appear at the end of a selector sequence (did you mean to use :global(...) instead?)',
8+
position: [50, 57]
9+
}
10+
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<style>
2+
/* ok */
3+
.x :global {
4+
}
5+
/* not ok */
6+
:global .x {
7+
}
8+
</style>

0 commit comments

Comments
 (0)