diff --git a/packages/svelte/messages/compile-errors/style.md b/packages/svelte/messages/compile-errors/style.md index c23b6cac76..49a0d5a08d 100644 --- a/packages/svelte/messages/compile-errors/style.md +++ b/packages/svelte/messages/compile-errors/style.md @@ -22,6 +22,10 @@ > A :global {...} block cannot modify an existing selector +## 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?) + ## css_global_invalid_placement > :global(...) can be at the start or end of a selector sequence, but not in the middle diff --git a/packages/svelte/src/compiler/errors.js b/packages/svelte/src/compiler/errors.js index b092e262db..d1ac6fed55 100644 --- a/packages/svelte/src/compiler/errors.js +++ b/packages/svelte/src/compiler/errors.js @@ -470,6 +470,15 @@ export function css_global_block_invalid_modifier(node) { e(node, "css_global_block_invalid_modifier", "A :global {...} block cannot modify an existing selector"); } +/** + * A :global {...} block can only appear at the end of a selector sequence (did you mean to use :global(...) instead?) + * @param {null | number | NodeLike} node + * @returns {never} + */ +export function css_global_block_invalid_placement(node) { + 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?)"); +} + /** * :global(...) can be at the start or end of a selector sequence, but not in the middle * @param {null | number | NodeLike} node diff --git a/packages/svelte/src/compiler/phases/2-analyze/css/css-analyze.js b/packages/svelte/src/compiler/phases/2-analyze/css/css-analyze.js index a832a65e59..bf7b745baf 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/css/css-analyze.js +++ b/packages/svelte/src/compiler/phases/2-analyze/css/css-analyze.js @@ -16,7 +16,11 @@ import { merge } from '../../visitors.js'; * >} CssVisitors */ -/** @param {Css.RelativeSelector} relative_selector */ +/** + * True if is `:global(...)` or `:global` + * @param {Css.RelativeSelector} relative_selector + * @returns {relative_selector is Css.RelativeSelector & { selectors: [Css.PseudoClassSelector, ...Css.Selector[]] }} + */ function is_global(relative_selector) { const first = relative_selector.selectors[0]; @@ -135,17 +139,23 @@ const validation_visitors = { context.next(); }, - ComplexSelector(node, context) { - // ensure `:global(...)` is not used in the middle of a selector + ComplexSelector(node) { { - const a = node.children.findIndex((child) => !is_global(child)); - const b = node.children.findLastIndex((child) => !is_global(child)); - - if (a !== b) { - for (let i = a; i <= b; i += 1) { - if (is_global(node.children[i])) { - e.css_global_invalid_placement(node.children[i].selectors[0]); - } + const global = node.children.find(is_global); + + if (global) { + const idx = node.children.indexOf(global); + + // ensure `:global` is only at the end of a selector + if (global.selectors[0].args === null && idx !== node.children.length - 1) { + e.css_global_block_invalid_placement(global.selectors[0]); + } else if ( + // ensure `:global(...)` is not used in the middle of a selector + global.selectors[0].args !== null && + idx !== 0 && + idx !== node.children.length - 1 + ) { + e.css_global_invalid_placement(global.selectors[0]); } } } diff --git a/packages/svelte/tests/compiler-errors/samples/css-global-block-invalid-selector/_config.js b/packages/svelte/tests/compiler-errors/samples/css-global-block-invalid-selector/_config.js new file mode 100644 index 0000000000..0eb061e41e --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/css-global-block-invalid-selector/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + error: { + code: 'css_global_block_invalid_placement', + message: + 'A :global {...} block can only appear at the end of a selector sequence (did you mean to use :global(...) instead?)', + position: [50, 57] + } +}); diff --git a/packages/svelte/tests/compiler-errors/samples/css-global-block-invalid-selector/main.svelte b/packages/svelte/tests/compiler-errors/samples/css-global-block-invalid-selector/main.svelte new file mode 100644 index 0000000000..15d721f54f --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/css-global-block-invalid-selector/main.svelte @@ -0,0 +1,8 @@ +