diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 924a0a752d..7a0338bbd9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -100,7 +100,7 @@ Test samples are kept in `/test/xxx/samples` folder. > PREREQUISITE: Install chromium via playwright by running `pnpm playwright install chromium` 1. To run test, run `pnpm test`. -1. To run test for a specific feature, you can use the `-g` (aka `--grep`) option. For example, to only run test involving transitions, run `pnpm test -- -g transition`. +1. To run test for a specific feature, you can use the `-t` (aka `--testNamePattern `) option. For example, to only run test involving transitions, run `pnpm test -- -t transistion`. ##### Running solo test diff --git a/packages/svelte/src/compiler/phases/1-parse/read/style.js b/packages/svelte/src/compiler/phases/1-parse/read/style.js index cf49b5d8da..d8b7d3301f 100644 --- a/packages/svelte/src/compiler/phases/1-parse/read/style.js +++ b/packages/svelte/src/compiler/phases/1-parse/read/style.js @@ -395,14 +395,21 @@ function read_declaration(parser) { * @returns {import('#compiler').Css.Declaration | import('#compiler').Css.Rule} */ function read_declaration_or_rule(parser) { - // We will only allow css nesting using & selector for now + // We need to know if this is a rule or a declaration + // so we'll attempt to read an identifier first + // if we can't, we'll assume it's a rule + // This needs to change when we support type (element) selectors // due to complexities with https://bugs.chromium.org/p/chromium/issues/detail?id=1427259 - // as most browsers as of 17/11/2023 do not support nesting without & selector - if (parser.match('&')) { - return read_rule(parser, true) - } else { - return read_declaration(parser); + const start = parser.index; + const is_ident = !!parser.read(REGEX_VALID_IDENTIFIER_CHAR); + + parser.index = start; + + if (!is_ident) { + return read_rule(parser, true); } + + return read_declaration(parser); } /** diff --git a/packages/svelte/src/compiler/phases/2-analyze/css/Selector.js b/packages/svelte/src/compiler/phases/2-analyze/css/Selector.js index a93e547504..7ff629415d 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/css/Selector.js +++ b/packages/svelte/src/compiler/phases/2-analyze/css/Selector.js @@ -321,6 +321,16 @@ function block_might_apply_to_node(block, node) { return NO_MATCH; } + if ( + block.nested && + block.selectors.length === 1 && + block.combinator !== null + ) { + // nested selector with combinator, eg: `.foo { + .bar { ... } }` + // TODO: How to handle this? + return UNKNOWN_SELECTOR; + } + if (selector.type === 'PseudoClassSelector' || selector.type === 'PseudoElementSelector') { continue; } @@ -831,14 +841,17 @@ class Block { /** * Groups selectors by combinator into blocks * @param {import('#compiler').Css.Selector} selector - * */ + */ function group_selectors(selector) { let block = new Block(null); const blocks = [block]; for (const child of selector.children) { if (child.type === 'Combinator') { - if (block.nested && !block.combinator) { + // If we start with a combinator, that means + // we're dealing with a nested selector + if(block.selectors.length === 0 && !block.combinator) { + block.nested = true; block.combinator = child; } else { block = new Block(child); diff --git a/packages/svelte/tests/css/samples/nested-css-adjacent-combinator/expected.css b/packages/svelte/tests/css/samples/nested-css-adjacent-combinator/expected.css new file mode 100644 index 0000000000..58a0fbec0c --- /dev/null +++ b/packages/svelte/tests/css/samples/nested-css-adjacent-combinator/expected.css @@ -0,0 +1,9 @@ +button.svelte-xyz { + color: red; + + + .abc.svelte-xyz { + color: purple; + } + + color: black; +} \ No newline at end of file diff --git a/packages/svelte/tests/css/samples/nested-css-adjacent-combinator/input.svelte b/packages/svelte/tests/css/samples/nested-css-adjacent-combinator/input.svelte new file mode 100644 index 0000000000..85a8e01311 --- /dev/null +++ b/packages/svelte/tests/css/samples/nested-css-adjacent-combinator/input.svelte @@ -0,0 +1,17 @@ + +