Merge branch 'css-nesting' of https://github.com/AlbertMarashi/svelte into css-nesting

pull/9549/head
Albert 3 years ago
commit e075ad7378
No known key found for this signature in database
GPG Key ID: 639EBA2F18800B0E

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: align `beforeUpdate`/`afterUpdate` behavior better with that in Svelte 4

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: use hybrid scoping strategy for consistent specificity increase

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: throw validation error when binding to each argument in runes mode

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: disallow exporting props, derived and reassigned state from within components

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: make CSS animation declaration transformation more robust

@ -9,6 +9,7 @@
"svelte.dev": "1.0.0"
},
"changesets": [
"afraid-dogs-matter",
"afraid-moose-matter",
"angry-books-jam",
"angry-plums-punch",
@ -135,6 +136,7 @@
"odd-needles-joke",
"odd-schools-wait",
"odd-shoes-cheat",
"odd-taxis-retire",
"old-flies-jog",
"old-houses-drum",
"old-mails-sneeze",
@ -181,6 +183,7 @@
"shiny-baboons-play",
"shiny-shrimps-march",
"short-buses-camp",
"silver-points-approve",
"sixty-items-crash",
"slimy-clouds-talk",
"slimy-laws-explode",
@ -203,6 +206,7 @@
"spotty-spiders-compare",
"stale-books-perform",
"stale-comics-look",
"strange-apricots-happen",
"strong-gifts-smoke",
"strong-lemons-provide",
"strong-pans-doubt",
@ -245,6 +249,7 @@
"two-falcons-buy",
"unlucky-boxes-obey",
"unlucky-trees-lick",
"violet-pigs-jam",
"wet-games-fly",
"wicked-clouds-exercise",
"wicked-doors-train",

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: handle sole empty expression tags

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: improve indexed each array reconcilation

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: set `open` binding value in `<details>`

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: add compiler error for each block mutations in runes mode

@ -220,4 +220,4 @@ This is just the beginning though. We have a long list of ideas for subsequent r
You can't use Svelte 5 in production yet. We're in the thick of it at the moment and can't tell you when it'll be ready to use in your apps.
But we didn't want to leave you hanging. We've created a [preview site](https://svelte-5-preview.vercel.app) with detailed explanations of the new features and an interactive playground. You can also visit the `#svelte-5-runes` channel of the [Svelte Discord](/chat) to learn more. We'd love to have your feedback!
But we didn't want to leave you hanging. We've created a [preview site](https://svelte-5-preview.vercel.app) with detailed explanations of the new features and an interactive playground. You can also visit the `#svelte-5-alpha` channel of the [Svelte Discord](/chat) to learn more. We'd love to have your feedback!

@ -1,5 +1,23 @@
# svelte
## 5.0.0-next.51
### Patch Changes
- fix: align `beforeUpdate`/`afterUpdate` behavior better with that in Svelte 4 ([#10408](https://github.com/sveltejs/svelte/pull/10408))
- fix: disallow exporting props, derived and reassigned state from within components ([#10430](https://github.com/sveltejs/svelte/pull/10430))
- fix: improve indexed each array reconcilation ([#10422](https://github.com/sveltejs/svelte/pull/10422))
- fix: add compiler error for each block mutations in runes mode ([#10428](https://github.com/sveltejs/svelte/pull/10428))
## 5.0.0-next.50
### Patch Changes
- fix: set `open` binding value in `<details>` ([#10413](https://github.com/sveltejs/svelte/pull/10413))
## 5.0.0-next.49
### Patch Changes

@ -2,7 +2,7 @@
"name": "svelte",
"description": "Cybernetically enhanced web apps",
"license": "MIT",
"version": "5.0.0-next.49",
"version": "5.0.0-next.51",
"type": "module",
"types": "./types/index.d.ts",
"engines": {

@ -108,7 +108,7 @@ const css = {
`:global(...) must not contain type or universal selectors when used in a compound selector`,
'invalid-css-selector': () => `Invalid selector`,
'invalid-css-identifier': () => 'Expected a valid CSS identifier',
'nesting-selector-not-allowed': () => 'Nesting selector is not allowed in top level rules',
'nesting-selector-not-allowed': () => 'Nesting selector is not allowed in top level rules'
};
/** @satisfies {Errors} */
@ -170,8 +170,12 @@ const runes = {
'invalid-legacy-export': () => `Cannot use \`export let\` in runes mode — use $props instead`,
/** @param {string} rune */
'invalid-rune-usage': (rune) => `Cannot use ${rune} rune in non-runes mode`,
'invalid-state-export': () => `Cannot export state if it is reassigned`,
'invalid-derived-export': () => `Cannot export derived state`,
'invalid-state-export': () =>
`Cannot export state if it is reassigned. Either export a function returning the state value or only mutate the state value's properties`,
'invalid-derived-export': () =>
`Cannot export derived state. To expose the current derived value, export a function returning its value`,
'invalid-prop-export': () =>
`Cannot export properties. To expose the current value of a property, export a function returning its value`,
'invalid-props-id': () => `$props() can only be used with an object destructuring pattern`,
'invalid-props-pattern': () =>
`$props() assignment must not contain nested properties or computed keys`,
@ -201,7 +205,11 @@ const runes = {
`${rune} can only be called with ${list(args, 'or')} ${
args.length === 1 && args[0] === 1 ? 'argument' : 'arguments'
}`,
'duplicate-props-rune': () => `Cannot use $props() more than once`
/** @param {string} name */
'invalid-runes-mode-import': (name) => `${name} cannot be used in runes mode`,
'duplicate-props-rune': () => `Cannot use $props() more than once`,
'invalid-each-assignment': () =>
`Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. 'array[i] = value' instead of 'entry = value')`
};
/** @satisfies {Errors} */

@ -55,7 +55,7 @@ export default class Selector {
this.local_selector_list = [];
// Process each block group to take trailing :global(...) selectors out of consideration
this.selector_list.forEach(complex_selector => {
this.selector_list.forEach((complex_selector) => {
let i = complex_selector.length;
while (i > 0) {
if (!complex_selector[i - 1].global) break;
@ -77,7 +77,7 @@ export default class Selector {
}
// Check if there are no local blocks across all groups, or if there's a host_only or root_only situation
const no_local_blocks = this.local_selector_list.every(group => group.length === 0);
const no_local_blocks = this.local_selector_list.every((group) => group.length === 0);
this.used = no_local_blocks || host_only || root_only;
}
/**
@ -115,7 +115,9 @@ export default class Selector {
* */
const used_blocks = new Map();
this.local_selector_list.map(complex_selector => apply_selector(complex_selector.slice(), node, used_blocks));
this.local_selector_list.map((complex_selector) =>
apply_selector(complex_selector.slice(), node, used_blocks)
);
// Iterate over used_blocks
for (const [relative_selector, nodes] of used_blocks) {
@ -129,10 +131,9 @@ export default class Selector {
/**
* @param {import('magic-string').default} code
* @param {string} attr
* @param {number} max_amount_class_specificity_increased
* @param {string} modifier
*/
transform(code, attr, max_amount_class_specificity_increased) {
transform(code, modifier) {
/** @param {import('#compiler').Css.SimpleSelector} selector */
function remove_global_pseudo_class(selector) {
code
@ -142,9 +143,9 @@ export default class Selector {
/**
* @param {RelativeSelector} relative_selector
* @param {string} attr
* @param {string} modifier
*/
function encapsulate_block(relative_selector, attr) {
function encapsulate_block(relative_selector, modifier) {
for (const selector of relative_selector.compound.selectors) {
if (selector.type === 'PseudoClassSelector' && selector.name === 'global') {
remove_global_pseudo_class(selector);
@ -154,7 +155,7 @@ export default class Selector {
let i = relative_selector.compound.selectors.length;
let first_selector = relative_selector.compound.selectors[0];
if (first_selector.type === "TypeSelector" && !first_selector.visible) return
if (first_selector.type === 'TypeSelector' && !first_selector.visible) return;
while (i--) {
const selector = relative_selector.compound.selectors[i];
@ -166,46 +167,37 @@ export default class Selector {
if (selector.type === 'PseudoElementSelector' || selector.type === 'PseudoClassSelector') {
if (!relative_selector.root && !relative_selector.host) {
if (i === 0) code.prependRight(selector.start, attr);
if (i === 0) code.prependRight(selector.start, modifier);
}
continue;
}
if (selector.type === 'TypeSelector' && selector.name === '*') {
code.update(selector.start, selector.end, attr);
code.update(selector.start, selector.end, modifier);
} else {
code.appendLeft(selector.end, attr);
code.appendLeft(selector.end, modifier);
}
break;
}
};
}
let first = true;
for (const complex_selector of this.selector_list) {
let amount_class_specificity_to_increase =
max_amount_class_specificity_increased - complex_selector
.filter(selector => selector.should_encapsulate)
.length;
complex_selector.map((relative_selector, index) => {
for (const relative_selector of complex_selector) {
if (relative_selector.global) {
// Remove the global pseudo class from the selector
remove_global_pseudo_class(relative_selector.compound.selectors[0]);
}
let amount = complex_selector
// Ignore invisible selectors because they are not part of the specificity
.filter(selector => !selector.contains_invisible_selectors)
// .filter(selector => selector.should_encapsulate)
.length - 1;
if(relative_selector.should_encapsulate) {
encapsulate_block(
relative_selector,
index === amount
? attr.repeat(amount_class_specificity_to_increase + 1)
: attr
);
if (relative_selector.should_encapsulate) {
// for the first occurrence, we use a classname selector, so that every
// encapsulated selector gets a +0-1-0 specificity bump. thereafter,
// we use a `:where` selector, which does not affect specificity
encapsulate_block(relative_selector, first ? modifier : `:where(${modifier})`);
first = false;
}
});
}
}
}
@ -217,7 +209,6 @@ export default class Selector {
this.validate_invalid_combinator_without_selector(analysis);
}
validate_invalid_css_global_placement() {
for (let complex_selector of this.selector_list) {
let start = 0;
@ -236,7 +227,6 @@ export default class Selector {
}
}
validate_global_with_multiple_selectors() {
for (const complex_selector of this.selector_list) {
if (complex_selector.length === 1 && complex_selector[0].compound.selectors.length === 1) {
@ -285,7 +275,9 @@ export default class Selector {
(i !== 0 ||
relative_selector.compound.selectors
.slice(1)
.some(s => s.type !== 'PseudoElementSelector' && s.type !== 'PseudoClassSelector'))
.some(
(s) => s.type !== 'PseudoElementSelector' && s.type !== 'PseudoClassSelector'
))
) {
error(selector, 'invalid-css-global-selector-list');
}
@ -294,13 +286,6 @@ export default class Selector {
}
}
}
get_amount_class_specificity_increased() {
// Is this right? Should we be counting the amount of blocks that are visible?
// Or should we be counting the amount of selectors that are visible?
return this.selector_list[0].filter(selector => selector.should_encapsulate).length;
}
}
/**
@ -362,7 +347,7 @@ function apply_selector(blocks, node, to_encapsulate) {
return true;
}
}
if (blocks.every(block => block.global)) {
if (blocks.every((block) => block.global)) {
add_node(to_encapsulate, block, node);
return true;
}
@ -883,7 +868,6 @@ function loop_child(children, adjacent_only) {
return result;
}
/**
* Not shared between different Selector instances
*/
@ -912,17 +896,25 @@ class RelativeSelector {
this.compound.add(selector);
}
get global() { return this.compound.global }
get host() { return this.compound.host }
get root() { return this.compound.root }
get end() {return this.compound.end }
get global() {
return this.compound.global;
}
get host() {
return this.compound.host;
}
get root() {
return this.compound.root;
}
get end() {
return this.compound.end;
}
get start() {
if (this.combinator) return this.combinator.start;
return this.compound.start;
}
get contains_invisible_selectors() {
return this.compound.selectors.some(selector => !selector.visible);
return this.compound.selectors.some((selector) => !selector.visible);
}
}
@ -958,8 +950,8 @@ class CompoundSelector {
this.selectors = [];
this.start = -1;
this.end = -1;
this.host = false
this.root = false
this.host = false;
this.root = false;
}
/** @param {SimpleSelectorWithData} selector */
@ -978,7 +970,10 @@ class CompoundSelector {
this.selectors.length >= 1 &&
this.selectors[0].type === 'PseudoClassSelector' &&
this.selectors[0].name === 'global' &&
this.selectors.every(selector => selector.type === 'PseudoClassSelector' || selector.type === 'PseudoElementSelector')
this.selectors.every(
(selector) =>
selector.type === 'PseudoClassSelector' || selector.type === 'PseudoElementSelector'
)
);
}
}
@ -996,14 +991,14 @@ function group_selectors(selector, parent_selector_list) {
return [selector_to_blocks([...selector.children], null)];
}
return parent_selector_list.map(parent_complex_selector => {
return parent_selector_list.map((parent_complex_selector) => {
const block_group = selector_to_blocks(
[...selector.children],
[...parent_complex_selector] // Clone the parent's blocks to avoid modifying the original array
);
return block_group;
})
});
}
/**
@ -1011,7 +1006,7 @@ function group_selectors(selector, parent_selector_list) {
* @param {ComplexSelector | null} parent_complex_selector - The parent rule's selectors to insert/swap into the nesting selector positions.
*/
function selector_to_blocks(children, parent_complex_selector) {
let block = new RelativeSelector(null, new CompoundSelector);
let block = new RelativeSelector(null, new CompoundSelector());
const blocks = [block];
// If this is a nested rule
@ -1019,7 +1014,7 @@ function selector_to_blocks(children, parent_complex_selector) {
for (const child of children) {
if (child.type === 'Combinator') {
block = new RelativeSelector(child, new CompoundSelector);
block = new RelativeSelector(child, new CompoundSelector());
blocks.push(block);
} else if (child.type === 'NestingSelector') {
if (!parent_complex_selector) {
@ -1033,10 +1028,12 @@ function selector_to_blocks(children, parent_complex_selector) {
child.use_wrapper = child.use_wrapper ?? { used: false };
// Shallow copy the child to avoid modifying the original's visibility
block.add(/** @type {SimpleSelectorWithData} */ ({
...child,
visible: child.visible === undefined ? true : child.visible
}));
block.add(
/** @type {SimpleSelectorWithData} */ ({
...child,
visible: child.visible === undefined ? true : child.visible
})
);
}
}
@ -1054,9 +1051,9 @@ function get_parent_selectors(parent_complex_selector) {
parent_selectors.push(relative_selector.combinator);
}
parent_selectors.push(
...relative_selector.compound.selectors.map(selector => ({
...relative_selector.compound.selectors.map((selector) => ({
...selector,
visible: false,
visible: false
}))
);
}
@ -1071,7 +1068,7 @@ function get_parent_selectors(parent_complex_selector) {
* @param {ComplexSelector} parent_complex_selector - The parent blocks to insert into the nesting selector positions.
*/
function nest_fake_parents(children, parent_complex_selector) {
let nested_selector_index = children.findIndex(child => child.type === 'NestingSelector');
let nested_selector_index = children.findIndex((child) => child.type === 'NestingSelector');
let used_ampersand = false;
// TODO: Handle multiple nesting selectors?
@ -1103,20 +1100,19 @@ function nest_fake_parents(children, parent_complex_selector) {
let last_parent_child = parent_selectors[parent_selectors.length - 1];
let child_before = children[nested_selector_index - 1];
if(last_parent_child.type !== "Combinator" && !child_after) {
if (last_parent_child.type !== 'Combinator' && !child_after) {
// Case: b { c & { color: red }} (we need to mark b as visible so we increase specifity)
last_parent_child.visible = true;
}
if(
child_before?.type !== "Combinator"
&& child_after?.type !== "Combinator"
&& !used_ampersand
if (
child_before?.type !== 'Combinator' &&
child_after?.type !== 'Combinator' &&
!used_ampersand
) {
children.splice(nested_selector_index, 0, FakeCombinator);
}
}
// Finally, insert the parent selectors into the children array
children.splice(nested_selector_index, 0, ...parent_selectors);
}
}

@ -8,7 +8,7 @@ import { push_array } from '../utils/push_array.js';
import { create_attribute } from '../../nodes.js';
const regex_css_browser_prefix = /^-((webkit)|(moz)|(o)|(ms))-/;
const regex_name_boundary = /^[\s,;}]$/;
/**
* @param {string} name
* @returns {string}
@ -88,8 +88,12 @@ class Rule {
* - .b .c
*/
if (parent && parent.node.type === 'Rule') {
let block_groups = /** @type {Rule} **/ (parent).selectors.map(selector => selector.selector_list).flat();
this.selectors = node.prelude.children.map(node => new Selector(node, stylesheet, block_groups));
let block_groups = /** @type {Rule} **/ (parent).selectors
.map((selector) => selector.selector_list)
.flat();
this.selectors = node.prelude.children.map(
(node) => new Selector(node, stylesheet, block_groups)
);
} else {
this.selectors = node.prelude.children.map((node) => new Selector(node, stylesheet, null));
}
@ -129,21 +133,16 @@ class Rule {
* @param {import('magic-string').default} code
* @param {string} id
* @param {Map<string, string>} keyframes
* @param {number} max_amount_class_specificity_increased
*/
transform(code, id, keyframes, max_amount_class_specificity_increased) {
transform(code, id, keyframes) {
if (this.parent && this.parent.node.type === 'Atrule' && is_keyframes_node(this.parent.node)) {
return;
}
const attr = `.${id}`;
this.selectors.forEach((selector) =>
selector.transform(code, attr, max_amount_class_specificity_increased)
);
const modifier = `.${id}`;
this.selectors.forEach((selector) => selector.transform(code, modifier));
this.declarations.forEach((declaration) => declaration.transform(code, keyframes));
this.nested_rules.forEach((rule) =>
rule.transform(code, id, keyframes, max_amount_class_specificity_increased)
);
this.nested_rules.forEach((rule) => rule.transform(code, id, keyframes));
}
/** @param {import('../../types.js').ComponentAnalysis} analysis */
@ -166,14 +165,6 @@ class Rule {
});
}
/** @returns number */
get_max_amount_class_specificity_increased() {
return Math.max(
...this.selectors.map((selector) => selector.get_amount_class_specificity_increased())
);
// do we need to check nested rules?
}
/**
* @param {MagicString} code
* @param {boolean} dev
@ -259,20 +250,29 @@ class Declaration {
transform(code, keyframes) {
const property = this.node.property && remove_css_prefix(this.node.property.toLowerCase());
if (property === 'animation' || property === 'animation-name') {
const name = /** @type {string} */ (this.node.value)
.split(' ')
.find((name) => keyframes.has(name));
if (name) {
const start = code.original.indexOf(
name,
code.original.indexOf(this.node.property, this.node.start)
);
let index = this.node.start + this.node.property.length + 1;
let name = '';
const end = start + name.length;
while (index < code.original.length) {
const character = code.original[index];
const keyframe = /** @type {string} */ (keyframes.get(name));
code.update(start, end, keyframe);
if (regex_name_boundary.test(character)) {
const keyframe = keyframes.get(name);
if (keyframe) {
code.update(index - name.length, index, keyframe);
}
if (character === ';' || character === '}') {
break;
}
name = '';
} else {
name += character;
}
index++;
}
}
}
@ -324,9 +324,8 @@ class Atrule {
* @param {import('magic-string').default} code
* @param {string} id
* @param {Map<string, string>} keyframes
* @param {number} max_amount_class_specificity_increased
*/
transform(code, id, keyframes, max_amount_class_specificity_increased) {
transform(code, id, keyframes) {
if (is_keyframes_node(this.node)) {
let start = this.node.start + this.node.name.length + 1;
while (code.original[start] === ' ') start += 1;
@ -346,7 +345,7 @@ class Atrule {
}
}
this.children.forEach((child) => {
child.transform(code, id, keyframes, max_amount_class_specificity_increased);
child.transform(code, id, keyframes);
});
}
@ -365,13 +364,6 @@ class Atrule {
});
}
/** @returns {number} */
get_max_amount_class_specificity_increased() {
return Math.max(
...this.children.map((rule) => rule.get_max_amount_class_specificity_increased())
);
}
/**
* @param {MagicString} code
* @param {boolean} dev
@ -560,12 +552,8 @@ export default class Stylesheet {
}
});
const max = Math.max(
...this.children.map((rule) => rule.get_max_amount_class_specificity_increased())
);
for (const child of this.children) {
child.transform(code, this.id, this.keyframes, max);
child.transform(code, this.id, this.keyframes);
}
code.remove(0, this.ast.content.start);

@ -1,5 +1,5 @@
import { error } from '../../errors.js';
import { extract_identifiers, get_parent, is_text_attribute } from '../../utils/ast.js';
import { extract_identifiers, get_parent, is_text_attribute, object } from '../../utils/ast.js';
import { warn } from '../../warnings.js';
import fuzzymatch from '../1-parse/utils/fuzzymatch.js';
import { disallowed_parapgraph_contents, interactive_elements } from '../1-parse/utils/html.js';
@ -334,17 +334,16 @@ function is_tag_valid_with_parent(tag, parent_tag) {
* @type {import('zimmerframe').Visitors<import('#compiler').SvelteNode, import('./types.js').AnalysisState>}
*/
const validation = {
AssignmentExpression(node, context) {
validate_assignment(node, node.left, context.state);
},
BindDirective(node, context) {
validate_no_const_assignment(node, node.expression, context.state.scope, true);
const assignee = node.expression;
let left = assignee;
while (left.type === 'MemberExpression') {
left = /** @type {import('estree').MemberExpression} */ (left.object);
}
const left = object(assignee);
if (left.type !== 'Identifier') {
if (left === null) {
error(node, 'invalid-binding-expression');
}
@ -370,6 +369,10 @@ const validation = {
error(node.expression, 'invalid-derived-binding');
}
if (context.state.analysis.runes && binding.kind === 'each') {
error(node, 'invalid-each-assignment');
}
// TODO handle mutations of non-state/props in runes mode
}
@ -492,6 +495,20 @@ const validation = {
error(node, 'invalid-const-placement');
}
},
ImportDeclaration(node, context) {
if (node.source.value === 'svelte' && context.state.analysis.runes) {
for (const specifier of node.specifiers) {
if (specifier.type === 'ImportSpecifier') {
if (
specifier.imported.name === 'beforeUpdate' ||
specifier.imported.name === 'afterUpdate'
) {
error(specifier, 'invalid-runes-mode-import', specifier.imported.name);
}
}
}
}
},
LetDirective(node, context) {
const parent = context.path.at(-1);
if (
@ -641,6 +658,9 @@ const validation = {
error(child, 'invalid-title-content');
}
},
UpdateExpression(node, context) {
validate_assignment(node, node.argument, context.state);
},
ExpressionTag(node, context) {
if (!node.parent) return;
if (context.state.parent_element) {
@ -696,6 +716,10 @@ function validate_export(node, scope, name) {
const binding = scope.get(name);
if (!binding) return;
if (binding.kind === 'prop') {
error(node, 'invalid-prop-export');
}
if (binding.kind === 'derived') {
error(node, 'invalid-derived-export');
}
@ -890,24 +914,28 @@ function validate_no_const_assignment(node, argument, scope, is_binding) {
function validate_assignment(node, argument, state) {
validate_no_const_assignment(node, argument, state.scope, false);
let left = /** @type {import('estree').Expression | import('estree').Super} */ (argument);
if (left.type === 'Identifier') {
const binding = state.scope.get(left.name);
if (state.analysis.runes && argument.type === 'Identifier') {
const binding = state.scope.get(argument.name);
if (binding?.kind === 'derived') {
error(node, 'invalid-derived-assignment');
}
if (binding?.kind === 'each') {
error(node, 'invalid-each-assignment');
}
}
let object = /** @type {import('estree').Expression | import('estree').Super} */ (argument);
/** @type {import('estree').Expression | import('estree').PrivateIdentifier | null} */
let property = null;
while (left.type === 'MemberExpression') {
property = left.property;
left = left.object;
while (object.type === 'MemberExpression') {
property = object.property;
object = object.object;
}
if (left.type === 'ThisExpression' && property?.type === 'PrivateIdentifier') {
if (object.type === 'ThisExpression' && property?.type === 'PrivateIdentifier') {
if (state.private_derived_state.includes(property.name)) {
error(node, 'invalid-derived-assignment');
}
@ -915,22 +943,24 @@ function validate_assignment(node, argument, state) {
}
export const validation_runes = merge(validation, a11y_validators, {
AssignmentExpression(node, { state, path }) {
const parent = path.at(-1);
if (parent && parent.type === 'ConstTag') return;
validate_assignment(node, node.left, state);
},
UpdateExpression(node, { state }) {
validate_assignment(node, node.argument, state);
},
LabeledStatement(node, { path }) {
if (node.label.name !== '$' || path.at(-1)?.type !== 'Program') return;
error(node, 'invalid-legacy-reactive-statement');
},
ExportNamedDeclaration(node, { state }) {
ExportNamedDeclaration(node, { state, next }) {
if (node.declaration?.type !== 'VariableDeclaration') return;
if (node.declaration.kind !== 'let') return;
// visit children, so bindings are correctly initialised
next();
for (const declarator of node.declaration.declarations) {
for (const id of extract_identifiers(declarator.id)) {
validate_export(node, state.scope, id.name);
}
}
if (state.analysis.instance.scope !== state.scope) return;
if (node.declaration.kind !== 'let') return;
error(node, 'invalid-legacy-export');
},
ExportSpecifier(node, { state }) {

@ -265,6 +265,7 @@ export function client_component(source, analysis, options) {
...legacy_reactive_declarations,
...group_binding_declarations,
.../** @type {import('estree').Statement[]} */ (instance.body),
analysis.runes ? b.empty : b.stmt(b.call('$.init')),
.../** @type {import('estree').Statement[]} */ (template.body),
...static_bindings
]);

@ -175,6 +175,7 @@ export const binding_properties = {
textContent: {},
open: {
event: 'toggle',
type: 'set',
valid_elements: ['details']
},
value: {

@ -90,8 +90,8 @@ export type SimpleSelector = (
) & {
// Deeply nested because we want to track whether the selector is used
// between clones of the AST
use_wrapper?: { used: boolean },
visible?: boolean
use_wrapper?: { used: boolean };
visible?: boolean;
};
export interface Combinator extends BaseNode {

@ -13,15 +13,11 @@ import {
hydrate_block_anchor,
set_current_hydration_fragment
} from './hydration.js';
import { clear_text_content, map_get, map_set } from './operations.js';
import { STATE_SYMBOL } from './proxy.js';
import { clear_text_content, empty, map_get, map_set } from './operations.js';
import { insert, remove } from './reconciler.js';
import { empty } from './render.js';
import {
destroy_signal,
execute_effect,
is_lazy_property,
lazy_property,
mutable_source,
push_destroy_fn,
render_effect,
@ -132,7 +128,7 @@ function each(anchor_node, collection, flags, key_fn, render_fn, fallback_fn, re
};
/** @param {import('./types.js').EachBlock} block */
const clear_each = (block) => {
const render_each = (block) => {
const flags = block.f;
const is_controlled = (flags & EACH_IS_CONTROLLED) !== 0;
const anchor_node = block.a;
@ -175,7 +171,7 @@ function each(anchor_node, collection, flags, key_fn, render_fn, fallback_fn, re
if (fallback_fn !== null) {
if (length === 0) {
if (block.v.length !== 0 || render === null) {
clear_each(block);
render_each(block);
create_fallback_effect();
return;
}
@ -201,7 +197,7 @@ function each(anchor_node, collection, flags, key_fn, render_fn, fallback_fn, re
false
);
render = render_effect(clear_each, block, true);
render = render_effect(render_each, block, true);
if (mismatch) {
// Set a fragment so that Svelte continues to operate in hydration mode
@ -279,14 +275,9 @@ function reconcile_indexed_array(
flags,
apply_transitions
) {
var is_proxied_array = STATE_SYMBOL in array && /** @type {any} */ (array[STATE_SYMBOL]).i;
var a_blocks = each_block.v;
var active_transitions = each_block.s;
if (is_proxied_array) {
flags &= ~EACH_ITEM_REACTIVE;
}
/** @type {number | void} */
var a = a_blocks.length;
@ -334,7 +325,7 @@ function reconcile_indexed_array(
break;
}
item = is_proxied_array ? lazy_property(array, index) : array[index];
item = array[index];
block = each_item_block(item, null, index, render_fn, flags);
b_blocks[index] = block;
@ -349,7 +340,7 @@ function reconcile_indexed_array(
for (; index < length; index++) {
if (index >= a) {
// Add block
item = is_proxied_array ? lazy_property(array, index) : array[index];
item = array[index];
block = each_item_block(item, null, index, render_fn, flags);
b_blocks[index] = block;
insert_each_item_block(block, dom, is_controlled, null);
@ -789,17 +780,6 @@ function update_each_item_block(block, item, index, type) {
const block_v = block.v;
if ((type & EACH_ITEM_REACTIVE) !== 0) {
set_signal_value(block_v, item);
} else if (is_lazy_property(block_v)) {
// If we have lazy properties, it means that an array was used that has been
// proxied. Given this, we need to re-sync the old array by mutating the backing
// value to be the latest value to ensure the UI updates correctly. TODO: maybe
// we should bypass any internal mutation checks for this?
const o = block_v.o;
const p = block_v.p;
const prev = o[p];
if (prev !== item) {
o[p] = item;
}
}
const transitions = block.s;
const index_is_reactive = (type & EACH_INDEX_REACTIVE) !== 0;
@ -856,9 +836,7 @@ export function destroy_each_item_block(
/**
* @template V
* @template O
* @template P
* @param {V | import('./types.js').LazyProperty<O, P>} item
* @param {V} item
* @param {unknown} key
* @param {number} index
* @param {(anchor: null, item: V, index: number | import('./types.js').Signal<number>) => void} render_fn

@ -1,5 +1,6 @@
// Handle hydration
import { empty } from './operations.js';
import { schedule_task } from './runtime.js';
/** @type {null | Array<import('./types.js').TemplateNode>} */
@ -16,9 +17,10 @@ export function set_current_hydration_fragment(fragment) {
/**
* Returns all nodes between the first `<!--ssr:...-->` comment tag pair encountered.
* @param {Node | null} node
* @param {boolean} [insert_text] Whether to insert an empty text node if the fragment is empty
* @returns {Array<import('./types.js').TemplateNode> | null}
*/
export function get_hydration_fragment(node) {
export function get_hydration_fragment(node, insert_text = false) {
/** @type {Array<import('./types.js').TemplateNode>} */
const fragment = [];
@ -37,6 +39,11 @@ export function get_hydration_fragment(node) {
if (target_depth === null) {
target_depth = depth;
} else if (depth === target_depth) {
if (insert_text && fragment.length === 0) {
const text = empty();
fragment.push(text);
/** @type {Node} */ (current_node.parentNode).insertBefore(text, current_node);
}
return fragment;
} else {
fragment.push(/** @type {Text | Comment | Element} */ (current_node));

@ -158,6 +158,11 @@ export function clone_node(node, deep) {
return /** @type {N} */ (clone_node_method.call(node, deep));
}
/** @returns {Text} */
export function empty() {
return document.createTextNode('');
}
/**
* @template {Node} N
* @param {N} node
@ -169,7 +174,7 @@ export function child(node) {
if (current_hydration_fragment !== null) {
// Child can be null if we have an element with a single child, like `<p>{text}</p>`, where `text` is empty
if (child === null) {
const text = document.createTextNode('');
const text = empty();
node.appendChild(text);
return text;
} else {
@ -193,7 +198,7 @@ export function child_frag(node, is_text) {
// if an {expression} is empty during SSR, there might be no
// text node to hydrate — we must therefore create one
if (is_text && first_node?.nodeType !== 3) {
const text = document.createTextNode('');
const text = empty();
current_hydration_fragment.unshift(text);
if (first_node) {
/** @type {DocumentFragment} */ (first_node.parentNode).insertBefore(text, first_node);
@ -221,8 +226,10 @@ export function child_frag(node, is_text) {
export function sibling(node, is_text = false) {
const next_sibling = next_sibling_get.call(node);
if (current_hydration_fragment !== null) {
// if a sibling {expression} is empty during SSR, there might be no
// text node to hydrate — we must therefore create one
if (is_text && next_sibling?.nodeType !== 3) {
const text = document.createTextNode('');
const text = empty();
if (next_sibling) {
const index = current_hydration_fragment.indexOf(
/** @type {Text | Comment | Element} */ (next_sibling)

@ -4,6 +4,7 @@ import {
child,
clone_node,
create_element,
empty,
init_operations,
map_get,
map_set,
@ -75,11 +76,6 @@ const all_registerd_events = new Set();
/** @type {Set<(events: Array<string>) => void>} */
const root_event_handles = new Set();
/** @returns {Text} */
export function empty() {
return document.createTextNode('');
}
/**
* @param {string} html
* @param {boolean} return_fragment
@ -212,11 +208,22 @@ const space_template = template(' ', false);
const comment_template = template('<!>', true);
/**
* @param {null | Text | Comment | Element} anchor
* @param {Text | Comment | Element | null} anchor
*/
/*#__NO_SIDE_EFFECTS__*/
export function space(anchor) {
return open(anchor, true, space_template);
/** @type {Node | null} */
var node = /** @type {any} */ (open(anchor, true, space_template));
// if an {expression} is empty during SSR, there might be no
// text node to hydrate (or an anchor comment is falsely detected instead)
// — we must therefore create one
if (current_hydration_fragment !== null && node?.nodeType !== 3) {
node = empty();
// @ts-ignore in this case the anchor should always be a comment,
// if not something more fundamental is wrong and throwing here is better to bail out early
anchor.parentElement.insertBefore(node, anchor);
}
return node;
}
/**
@ -228,6 +235,8 @@ export function comment(anchor) {
}
/**
* Assign the created (or in hydration mode, traversed) dom elements to the current block
* and insert the elements into the dom (in client mode).
* @param {Element | Text} dom
* @param {boolean} is_fragment
* @param {null | Text | Comment | Element} anchor
@ -2866,7 +2875,9 @@ export function mount(component, options) {
const container = options.target;
const block = create_root_block(options.intro || false);
const first_child = /** @type {ChildNode} */ (container.firstChild);
const hydration_fragment = get_hydration_fragment(first_child);
// Call with insert_text == true to prevent empty {expressions} resulting in an empty
// fragment array, resulting in a hydration error down the line
const hydration_fragment = get_hydration_fragment(first_child, true);
const previous_hydration_fragment = current_hydration_fragment;
/** @type {Exports} */

@ -1,6 +1,6 @@
import { DEV } from 'esm-env';
import { subscribe_to_store } from '../../store/utils.js';
import { noop, run_all } from '../common.js';
import { noop, run, run_all } from '../common.js';
import {
array_prototype,
get_descriptor,
@ -39,7 +39,6 @@ const FLUSH_MICROTASK = 0;
const FLUSH_SYNC = 1;
export const UNINITIALIZED = Symbol();
export const LAZY_PROPERTY = Symbol();
// Used for controlling the flush of effects.
let current_scheduler_mode = FLUSH_MICROTASK;
@ -104,18 +103,9 @@ export let current_block = null;
/** @type {import('./types.js').ComponentContext | null} */
export let current_component_context = null;
export let is_ssr = false;
export let updating_derived = false;
/**
* @param {boolean} ssr
* @returns {void}
*/
export function set_is_ssr(ssr) {
is_ssr = ssr;
}
/**
* @param {null | import('./types.js').ComponentContext} context
* @returns {boolean}
@ -147,14 +137,6 @@ export function batch_inspect(target, prop, receiver) {
};
}
/**
* @param {null | import('./types.js').ComponentContext} context_stack_item
* @returns {void}
*/
export function set_current_component_context(context_stack_item) {
current_component_context = context_stack_item;
}
/**
* @param {unknown} a
* @param {unknown} b
@ -181,8 +163,6 @@ function create_source_signal(flags, value) {
f: flags,
// value
v: value,
// context: We can remove this if we get rid of beforeUpdate/afterUpdate
x: null,
// this is for DEV only
inspect: new Set()
};
@ -195,9 +175,7 @@ function create_source_signal(flags, value) {
// flags
f: flags,
// value
v: value,
// context: We can remove this if we get rid of beforeUpdate/afterUpdate
x: null
v: value
};
}
@ -346,12 +324,6 @@ function execute_signal_fn(signal) {
current_skip_consumer = !is_flushing_effect && (flags & UNOWNED) !== 0;
current_untracking = false;
// Render effects are invoked when the UI is about to be updated - run beforeUpdate at that point
if (is_render_effect && current_component_context?.u != null) {
// update_callbacks.execute()
current_component_context.u.e();
}
try {
let res;
if (is_render_effect) {
@ -924,7 +896,7 @@ export function store_set(store, value) {
* @param {import('./types.js').StoreReferencesContainer} stores
*/
export function unsubscribe_on_destroy(stores) {
onDestroy(() => {
on_destroy(() => {
let store_name;
for (store_name in stores) {
const ref = stores[store_name];
@ -1150,7 +1122,7 @@ export function mark_subtree_inert(signal, inert, visited_blocks = new Set()) {
* @returns {void}
*/
function mark_signal_consumers(signal, to_status, force_schedule) {
const runes = is_runes(signal.x);
const runes = is_runes(null);
const consumers = signal.c;
if (consumers !== null) {
const length = consumers.length;
@ -1192,7 +1164,7 @@ export function set_signal_value(signal, value) {
!current_untracking &&
!ignore_mutation_validation &&
current_consumer !== null &&
is_runes(signal.x) &&
is_runes(null) &&
(current_consumer.f & DERIVED) !== 0
) {
throw new Error(
@ -1208,7 +1180,6 @@ export function set_signal_value(signal, value) {
(signal.f & SOURCE) !== 0 &&
!(/** @type {import('./types.js').EqualsFunctions} */ (signal.e)(value, signal.v))
) {
const component_context = signal.x;
signal.v = value;
// If the current signal is running for the first time, it won't have any
// consumers as we only allocate and assign the consumers after the signal
@ -1219,7 +1190,7 @@ export function set_signal_value(signal, value) {
// $effect(() => x++)
//
if (
is_runes(component_context) &&
is_runes(null) &&
current_effect !== null &&
current_effect.c === null &&
(current_effect.f & CLEAN) !== 0
@ -1236,19 +1207,6 @@ export function set_signal_value(signal, value) {
}
}
mark_signal_consumers(signal, DIRTY, true);
// If we have afterUpdates locally on the component, but we're within a render effect
// then we will need to manually invoke the beforeUpdate/afterUpdate logic.
// TODO: should we put this being a is_runes check and only run it in non-runes mode?
if (current_effect === null && current_queued_pre_and_render_effects.length === 0) {
const update_callbacks = component_context?.u;
if (update_callbacks != null) {
run_all(update_callbacks.b);
const managed = managed_effect(() => {
destroy_signal(managed);
run_all(update_callbacks.a);
});
}
}
// @ts-expect-error
if (DEV && signal.inspect) {
@ -1299,7 +1257,7 @@ export function derived(init) {
create_computation_signal(flags | CLEAN, UNINITIALIZED, current_block)
);
signal.i = init;
signal.x = current_component_context;
bind_signal_to_component_context(signal);
signal.e = default_equals;
if (current_consumer !== null) {
push_reference(current_consumer, signal);
@ -1327,10 +1285,27 @@ export function derived_safe_equal(init) {
/*#__NO_SIDE_EFFECTS__*/
export function source(initial_value) {
const source = create_source_signal(SOURCE | CLEAN, initial_value);
source.x = current_component_context;
bind_signal_to_component_context(source);
return source;
}
/**
* This function binds a signal to the component context, so that we can fire
* beforeUpdate/afterUpdate callbacks at the correct time etc
* @param {import('./types.js').Signal} signal
*/
function bind_signal_to_component_context(signal) {
if (current_component_context === null || !current_component_context.r) return;
const signals = current_component_context.d;
if (signals) {
signals.push(signal);
} else {
current_component_context.d = [signal];
}
}
/**
* @template V
* @param {V} initial_value
@ -1566,20 +1541,6 @@ export function is_signal(val) {
);
}
/**
* @template O
* @template P
* @param {any} val
* @returns {val is import('./types.js').LazyProperty<O, P>}
*/
export function is_lazy_property(val) {
return (
typeof val === 'object' &&
val !== null &&
/** @type {import('./types.js').LazyProperty<O, P>} */ (val).t === LAZY_PROPERTY
);
}
/**
* @template V
* @param {unknown} val
@ -1883,18 +1844,11 @@ export function value_or_fallback(value, fallback) {
/**
* Schedules a callback to run immediately before the component is unmounted.
*
* Out of `onMount`, `beforeUpdate`, `afterUpdate` and `onDestroy`, this is the
* only one that runs inside a server-side component.
*
* https://svelte.dev/docs/svelte#ondestroy
* @param {() => any} fn
* @returns {void}
*/
export function onDestroy(fn) {
if (!is_ssr) {
user_effect(() => () => untrack(fn));
}
function on_destroy(fn) {
user_effect(() => () => untrack(fn));
}
/**
@ -1914,6 +1868,8 @@ export function push(props, runes = false) {
m: false,
// parent
p: current_component_context,
// signals
d: null,
// props
s: props,
// runes
@ -1945,6 +1901,56 @@ export function pop(accessors) {
}
}
/**
* Invoke the getter of all signals associated with a component
* so they can be registered to the effect this function is called in.
* @param {import('./types.js').ComponentContext} context
*/
function observe_all(context) {
if (context.d) {
for (const signal of context.d) get(signal);
}
const props = get_descriptors(context.s);
for (const descriptor of Object.values(props)) {
if (descriptor.get) descriptor.get();
}
}
/**
* Legacy-mode only: Call `onMount` callbacks and set up `beforeUpdate`/`afterUpdate` effects
*/
export function init() {
const context = /** @type {import('./types.js').ComponentContext} */ (current_component_context);
const callbacks = context.u;
if (!callbacks) return;
// beforeUpdate
pre_effect(() => {
observe_all(context);
callbacks.b.forEach(run);
});
// onMount (must run before afterUpdate)
user_effect(() => {
const fns = untrack(() => callbacks.m.map(run));
return () => {
for (const fn of fns) {
if (typeof fn === 'function') {
fn();
}
}
};
});
// afterUpdate
user_effect(() => {
observe_all(context);
callbacks.a.forEach(run);
});
}
/**
* @param {any} value
* @param {Set<any>} visited
@ -2063,21 +2069,6 @@ export function inspect(get_value, inspect = console.log) {
});
}
/**
* @template O
* @template P
* @param {O} o
* @param {P} p
* @returns {import('./types.js').LazyProperty<O, P>}
*/
export function lazy_property(o, p) {
return {
o,
p,
t: LAZY_PROPERTY
};
}
/**
* @template V
* @param {V} value
@ -2088,9 +2079,6 @@ export function unwrap(value) {
// @ts-ignore
return get(value);
}
if (is_lazy_property(value)) {
return value.o[value.p];
}
// @ts-ignore
return value;
}

@ -10,8 +10,7 @@ import {
ROOT_BLOCK
} from './block.js';
import { destroy_each_item_block, get_first_element } from './each.js';
import { append_child } from './operations.js';
import { empty } from './render.js';
import { append_child, empty } from './operations.js';
import {
current_block,
current_effect,

@ -11,7 +11,7 @@ import {
SNIPPET_BLOCK
} from './block.js';
import type { READONLY_SYMBOL, STATE_SYMBOL } from './proxy.js';
import { DERIVED, EFFECT, RENDER_EFFECT, SOURCE, PRE_EFFECT, LAZY_PROPERTY } from './runtime.js';
import { DERIVED, EFFECT, RENDER_EFFECT, SOURCE, PRE_EFFECT } from './runtime.js';
// Put all internal types in this file. Once we convert to JSDoc, we can make this a d.ts file
@ -36,6 +36,8 @@ export type Store<V> = {
// when the JS VM JITs the code.
export type ComponentContext = {
/** local signals (needed for beforeUpdate/afterUpdate) */
d: null | Signal<any>[];
/** props */
s: Record<string, unknown>;
/** accessors */
@ -52,12 +54,12 @@ export type ComponentContext = {
r: boolean;
/** update_callbacks */
u: null | {
/** before */
b: Array<() => void>;
/** after */
/** afterUpdate callbacks */
a: Array<() => void>;
/** execute */
e: () => void;
/** beforeUpdate callbacks */
b: Array<() => void>;
/** onMount callbacks */
m: Array<() => any>;
};
};
@ -69,8 +71,6 @@ export type ComponentContext = {
export type SourceSignal<V = unknown> = {
/** consumers: Signals that read from the current signal */
c: null | ComputationSignal[];
/** context: The associated component if this signal is an effect/computed */
x: null | ComponentContext;
/** equals: For value equality */
e: null | EqualsFunctions;
/** flags: The types that the signal represent, as a bitwise value */
@ -123,12 +123,6 @@ export type MaybeSignal<T = unknown> = T | Signal<T>;
export type UnwrappedSignal<T> = T extends Signal<infer U> ? U : T;
export type LazyProperty<O, P> = {
o: O;
p: P;
t: typeof LAZY_PROPERTY;
};
export type EqualsFunctions<T = any> = (a: T, v: T) => boolean;
export type BlockType =

@ -19,3 +19,8 @@ export function run_all(arr) {
arr[i]();
}
}
/** @param {Function} fn */
export function run(fn) {
return fn();
}

@ -30,7 +30,6 @@ export {
exclude_from_object,
store_set,
unsubscribe_on_destroy,
onDestroy,
pop,
push,
reactive_import,
@ -38,7 +37,8 @@ export {
user_root_effect,
inspect,
unwrap,
freeze
freeze,
init
} from './client/runtime.js';
export * from './client/each.js';
export * from './client/render.js';

@ -1,5 +1,4 @@
import * as $ from '../client/runtime.js';
import { set_is_ssr } from '../client/runtime.js';
import { is_promise, noop } from '../common.js';
import { subscribe_to_store } from '../../store/utils.js';
import { DOMBooleanAttributes } from '../../constants.js';
@ -95,7 +94,6 @@ export function render(component, options) {
const root_anchor = create_anchor(payload);
const root_head_anchor = create_anchor(payload.head);
set_is_ssr(true);
const prev_on_destroy = on_destroy;
on_destroy = [];
payload.out += root_anchor;
@ -112,7 +110,6 @@ export function render(component, options) {
payload.out += root_anchor;
for (const cleanup of on_destroy) cleanup();
on_destroy = prev_on_destroy;
set_is_ssr(false);
return {
head:

@ -1,12 +1,8 @@
import {
current_component_context,
destroy_signal,
get_or_init_context_map,
is_ssr,
managed_effect,
untrack,
user_effect,
flush_local_render_effects
user_effect
} from '../internal/client/runtime.js';
import { is_array } from '../internal/client/utils.js';
@ -25,16 +21,38 @@ import { is_array } from '../internal/client/utils.js';
* @returns {void}
*/
export function onMount(fn) {
if (!is_ssr) {
if (current_component_context === null) {
throw new Error('onMount can only be used during component initialisation.');
}
if (current_component_context.r) {
user_effect(() => {
const result = untrack(fn);
if (typeof result === 'function') {
return /** @type {() => any} */ (result);
}
const cleanup = untrack(fn);
if (typeof cleanup === 'function') return /** @type {() => void} */ (cleanup);
});
} else {
init_update_callbacks(current_component_context).m.push(fn);
}
}
/**
* Schedules a callback to run immediately before the component is unmounted.
*
* Out of `onMount`, `beforeUpdate`, `afterUpdate` and `onDestroy`, this is the
* only one that runs inside a server-side component.
*
* https://svelte.dev/docs/svelte#ondestroy
* @param {() => any} fn
* @returns {void}
*/
export function onDestroy(fn) {
if (current_component_context === null) {
throw new Error('onDestroy can only be used during component initialisation.');
}
onMount(() => () => untrack(fn));
}
/**
* Retrieves the context that belongs to the closest parent component with the specified `key`.
* Must be called during component initialisation.
@ -155,46 +173,6 @@ export function createEventDispatcher() {
};
}
function init_update_callbacks() {
let called_before = false;
let called_after = false;
/** @type {NonNullable<import('../internal/client/types.js').ComponentContext['u']>} */
const update_callbacks = {
b: [],
a: [],
e() {
if (!called_before) {
called_before = true;
// TODO somehow beforeUpdate ran twice on mount in Svelte 4 if it causes a render
// possibly strategy to get this back if needed: analyse beforeUpdate function for assignements to state,
// if yes, add a call to the component to force-run beforeUpdate once.
untrack(() => update_callbacks.b.forEach(/** @param {any} c */ (c) => c()));
flush_local_render_effects();
// beforeUpdate can run again once if afterUpdate causes another update,
// but afterUpdate shouldn't be called again in that case to prevent infinite loops
if (!called_after) {
user_effect(() => {
called_before = false;
called_after = true;
untrack(() => update_callbacks.a.forEach(/** @param {any} c */ (c) => c()));
// managed_effect so that it's not cleaned up when the parent effect is cleaned up
const managed = managed_effect(() => {
destroy_signal(managed);
called_after = false;
});
});
} else {
user_effect(() => {
called_before = false;
});
}
}
}
};
return update_callbacks;
}
// TODO mark beforeUpdate and afterUpdate as deprecated in Svelte 6
/**
@ -210,12 +188,15 @@ function init_update_callbacks() {
* @returns {void}
*/
export function beforeUpdate(fn) {
const component_context = current_component_context;
if (component_context === null) {
throw new Error('beforeUpdate can only be used during component initialisation.');
if (current_component_context === null) {
throw new Error('beforeUpdate can only be used during component initialisation');
}
(component_context.u ??= init_update_callbacks()).b.push(fn);
if (current_component_context.r) {
throw new Error('beforeUpdate cannot be used in runes mode');
}
init_update_callbacks(current_component_context).b.push(fn);
}
/**
@ -231,22 +212,25 @@ export function beforeUpdate(fn) {
* @returns {void}
*/
export function afterUpdate(fn) {
const component_context = current_component_context;
if (component_context === null) {
if (current_component_context === null) {
throw new Error('afterUpdate can only be used during component initialisation.');
}
(component_context.u ??= init_update_callbacks()).a.push(fn);
if (current_component_context.r) {
throw new Error('afterUpdate cannot be used in runes mode');
}
init_update_callbacks(current_component_context).a.push(fn);
}
/**
* Legacy-mode: Init callbacks object for onMount/beforeUpdate/afterUpdate
* @param {import('../internal/client/types.js').ComponentContext} context
*/
function init_update_callbacks(context) {
return (context.u ??= { a: [], b: [], m: [] });
}
// TODO bring implementations in here
// (except probably untrack — do we want to expose that, if there's also a rune?)
export {
flushSync,
createRoot,
mount,
tick,
untrack,
unstate,
onDestroy
} from '../internal/index.js';
export { flushSync, createRoot, mount, tick, untrack, unstate } from '../internal/index.js';

@ -1,4 +1,4 @@
import { noop } from '../internal/common.js';
import { noop, run } from '../internal/common.js';
import { subscribe_to_store } from './utils.js';
/**
@ -106,11 +106,6 @@ export function writable(value, start = noop) {
return { set, update, subscribe };
}
/** @param {Function} fn */
function run(fn) {
return fn();
}
/**
* @param {Function[]} fns
* @returns {void}

@ -6,5 +6,5 @@
* https://svelte.dev/docs/svelte-compiler#svelte-version
* @type {string}
*/
export const VERSION = '5.0.0-next.49';
export const VERSION = '5.0.0-next.51';
export const PUBLIC_VERSION = '5';

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid-derived-export',
message: 'Cannot export derived state',
position: [24, 66]
message:
'Cannot export derived state. To expose the current derived value, export a function returning its value'
}
});

@ -0,0 +1,4 @@
<script>
let count = $state(0);
export const double = $derived(count * 2);
</script>

@ -0,0 +1,10 @@
import { test } from '../../test';
export default test({
error: {
code: 'invalid-state-export',
message:
"Cannot export state if it is reassigned. Either export a function returning the state value or only mutate the state value's properties",
position: [59, 99]
}
});

@ -0,0 +1,15 @@
<script>
export const object = $state({
ok: true
});
export const primitive = $state('nope');
export function update_object() {
object.ok = !object.ok;
}
export function update_primitive() {
primitive = 'yep';
}
</script>

@ -3,7 +3,8 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid-state-export',
message: 'Cannot export state if it is reassigned',
message:
"Cannot export state if it is reassigned. Either export a function returning the state value or only mutate the state value's properties",
position: [46, 86]
}
});

@ -0,0 +1,8 @@
import { test } from '../../test';
export default test({
error: {
code: 'invalid-runes-mode-import',
message: 'beforeUpdate cannot be used in runes mode'
}
});

@ -0,0 +1,5 @@
<svelte:options runes />
<script>
import { beforeUpdate, afterUpdate } from 'svelte';
</script>

@ -3,7 +3,8 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid-state-export',
message: 'Cannot export state if it is reassigned',
message:
"Cannot export state if it is reassigned. Either export a function returning the state value or only mutate the state value's properties",
position: [28, 53]
}
});

@ -0,0 +1,9 @@
import { test } from '../../test';
export default test({
error: {
code: 'invalid-prop-export',
message:
'Cannot export properties. To expose the current value of a property, export a function returning its value'
}
});

@ -0,0 +1,4 @@
<script>
let { foo } = $props();
export { foo };
</script>

@ -0,0 +1,9 @@
import { test } from '../../test';
export default test({
error: {
code: 'invalid-each-assignment',
message:
"Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. 'array[i] = value' instead of 'entry = value')"
}
});

@ -0,0 +1,7 @@
<script>
let arr = $state([1,2,3]);
</script>
{#each arr as value}
<input bind:value>
{/each}

@ -0,0 +1,9 @@
import { test } from '../../test';
export default test({
error: {
code: 'invalid-each-assignment',
message:
"Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. 'array[i] = value' instead of 'entry = value')"
}
});

@ -0,0 +1,7 @@
<script>
let arr = $state([1,2,3]);
</script>
{#each arr as value}
<button onclick={() => value += 1}>click</button>
{/each}

@ -0,0 +1,24 @@
@keyframes svelte-xyz-a {
0% {
transform: scale(1);
}
100% {
transform: scale(2);
}
}
@keyframes svelte-xyz-animation {
0% {
transform: scale(1);
}
100% {
transform: scale(2);
}
}
h1.svelte-xyz {
animation: 1s linear infinite svelte-xyz-a;
animation: svelte-xyz-a 1s linear infinite;
animation: 1s linear infinite svelte-xyz-a,svelte-xyz-animation 1s linear infinite;
}

@ -0,0 +1,27 @@
<h1>test</h1>
<style>
@keyframes a {
0% {
transform: scale(1);
}
100% {
transform: scale(2);
}
}
@keyframes animation {
0% {
transform: scale(1);
}
100% {
transform: scale(2);
}
}
h1 {
animation: 1s linear infinite a;
animation: a 1s linear infinite;
animation: 1s linear infinite a,animation 1s linear infinite;
}
</style>

@ -1,7 +1,7 @@
main.svelte-xyz button.svelte-xyz.svelte-xyz {
main.svelte-xyz button:where(.svelte-xyz) {
background-color: red;
}
main.svelte-xyz div.svelte-xyz > button.svelte-xyz {
main.svelte-xyz div:where(.svelte-xyz) > button:where(.svelte-xyz) {
background-color: blue;
}

@ -1,3 +1,3 @@
.test.svelte-xyz > div.svelte-xyz {
.test.svelte-xyz > div:where(.svelte-xyz) {
color: #0af;
}

@ -1,3 +1,3 @@
p.svelte-xyz span.svelte-xyz {
p.svelte-xyz span:where(.svelte-xyz) {
color: red;
}

@ -1,18 +1,18 @@
div.svelte-xyz.svelte-xyz.svelte-xyz {
div.svelte-xyz {
color: red;
}
h2.svelte-xyz > p.svelte-xyz.svelte-xyz {
h2.svelte-xyz > p:where(.svelte-xyz) {
color: red;
}
h2.svelte-xyz span.svelte-xyz.svelte-xyz {
h2.svelte-xyz span:where(.svelte-xyz) {
color: red;
}
h2.svelte-xyz > span.svelte-xyz > b.svelte-xyz {
h2.svelte-xyz > span:where(.svelte-xyz) > b:where(.svelte-xyz) {
color: red;
}
h2.svelte-xyz span b.svelte-xyz.svelte-xyz {
h2.svelte-xyz span b:where(.svelte-xyz) {
color: red;
}
h2.svelte-xyz b.svelte-xyz.svelte-xyz {
h2.svelte-xyz b:where(.svelte-xyz) {
color: red;
}

@ -1,13 +1,13 @@
.a.svelte-xyz ~ .b.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz ~ .c.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz ~ .d.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz ~ .e.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz ~ .f.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz ~ .g.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz ~ .h.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz ~ .b:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .c:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .d:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .e:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .f:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .g:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .h:where(.svelte-xyz) { color: green; }
.b.svelte-xyz ~ .d.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz ~ .d.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.b.svelte-xyz ~ .e.svelte-xyz ~ .f.svelte-xyz ~ .h.svelte-xyz { color: green; }
.b.svelte-xyz ~ .d.svelte-xyz ~ .h.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz ~ .g.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.b.svelte-xyz ~ .d:where(.svelte-xyz) { color: green; }
.c.svelte-xyz ~ .d:where(.svelte-xyz) { color: green; }
.b.svelte-xyz ~ .e:where(.svelte-xyz) ~ .f:where(.svelte-xyz) ~ .h:where(.svelte-xyz) { color: green; }
.b.svelte-xyz ~ .d:where(.svelte-xyz) ~ .h:where(.svelte-xyz) { color: green; }
.c.svelte-xyz ~ .g:where(.svelte-xyz) { color: green; }

@ -1,10 +1,10 @@
.a.svelte-xyz ~ .b.svelte-xyz { color: green; }
.a.svelte-xyz ~ .c.svelte-xyz { color: green; }
.a.svelte-xyz ~ .d.svelte-xyz { color: green; }
.b.svelte-xyz ~ .e.svelte-xyz { color: green; }
.c.svelte-xyz ~ .e.svelte-xyz { color: green; }
.d.svelte-xyz ~ .e.svelte-xyz { color: green; }
.a.svelte-xyz ~ .e.svelte-xyz { color: green; }
.a.svelte-xyz ~ .b:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .c:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .d:where(.svelte-xyz) { color: green; }
.b.svelte-xyz ~ .e:where(.svelte-xyz) { color: green; }
.c.svelte-xyz ~ .e:where(.svelte-xyz) { color: green; }
.d.svelte-xyz ~ .e:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .e:where(.svelte-xyz) { color: green; }
/* no match */
/* (unused) .b ~ .c { color: green; }*/

@ -1,22 +1,22 @@
/* boundary of each */
.a.svelte-xyz ~ .b.svelte-xyz {
.a.svelte-xyz ~ .b:where(.svelte-xyz) {
color: green;
}
.c.svelte-xyz ~ .d.svelte-xyz {
.c.svelte-xyz ~ .d:where(.svelte-xyz) {
color: green;
}
/* if array is empty */
.a.svelte-xyz ~ .d.svelte-xyz {
.a.svelte-xyz ~ .d:where(.svelte-xyz) {
color: green;
}
/* if array has multiple items */
.c.svelte-xyz ~ .b.svelte-xyz {
.c.svelte-xyz ~ .b:where(.svelte-xyz) {
color: green;
}
/* normal sibling */
.b.svelte-xyz ~ .c.svelte-xyz {
.b.svelte-xyz ~ .c:where(.svelte-xyz) {
color: green;
}
.a.svelte-xyz ~ .c.svelte-xyz {
.a.svelte-xyz ~ .c:where(.svelte-xyz) {
color: green;
}

@ -1,30 +1,30 @@
.a.svelte-xyz ~ .e.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz ~ .f.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.b.svelte-xyz ~ .c.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.b.svelte-xyz ~ .d.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz ~ .e.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz ~ .f.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.d.svelte-xyz ~ .e.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.d.svelte-xyz ~ .f.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.e.svelte-xyz ~ .e.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.i.svelte-xyz ~ .j.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.g.svelte-xyz ~ .h.svelte-xyz ~ .j.svelte-xyz.svelte-xyz { color: green; }
.g.svelte-xyz ~ .i.svelte-xyz ~ .j.svelte-xyz.svelte-xyz { color: green; }
.m.svelte-xyz ~ .m.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.m.svelte-xyz ~ .l.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.l.svelte-xyz ~ .m.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz ~ .c.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz ~ .g.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.b.svelte-xyz ~ .e.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz ~ .g.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz ~ .k.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.d.svelte-xyz ~ .d.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.g.svelte-xyz ~ .g.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.h.svelte-xyz ~ .h.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.i.svelte-xyz ~ .i.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.j.svelte-xyz ~ .j.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.g.svelte-xyz ~ .j.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.g.svelte-xyz ~ .h.svelte-xyz ~ .i.svelte-xyz ~ .j.svelte-xyz { color: green; }
.a.svelte-xyz ~ .e:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .f:where(.svelte-xyz) { color: green; }
.b.svelte-xyz ~ .c:where(.svelte-xyz) { color: green; }
.b.svelte-xyz ~ .d:where(.svelte-xyz) { color: green; }
.c.svelte-xyz ~ .e:where(.svelte-xyz) { color: green; }
.c.svelte-xyz ~ .f:where(.svelte-xyz) { color: green; }
.d.svelte-xyz ~ .e:where(.svelte-xyz) { color: green; }
.d.svelte-xyz ~ .f:where(.svelte-xyz) { color: green; }
.e.svelte-xyz ~ .e:where(.svelte-xyz) { color: green; }
.i.svelte-xyz ~ .j:where(.svelte-xyz) { color: green; }
.g.svelte-xyz ~ .h:where(.svelte-xyz) ~ .j:where(.svelte-xyz) { color: green; }
.g.svelte-xyz ~ .i:where(.svelte-xyz) ~ .j:where(.svelte-xyz) { color: green; }
.m.svelte-xyz ~ .m:where(.svelte-xyz) { color: green; }
.m.svelte-xyz ~ .l:where(.svelte-xyz) { color: green; }
.l.svelte-xyz ~ .m:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .c:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .g:where(.svelte-xyz) { color: green; }
.b.svelte-xyz ~ .e:where(.svelte-xyz) { color: green; }
.c.svelte-xyz ~ .g:where(.svelte-xyz) { color: green; }
.c.svelte-xyz ~ .k:where(.svelte-xyz) { color: green; }
.d.svelte-xyz ~ .d:where(.svelte-xyz) { color: green; }
.g.svelte-xyz ~ .g:where(.svelte-xyz) { color: green; }
.h.svelte-xyz ~ .h:where(.svelte-xyz) { color: green; }
.i.svelte-xyz ~ .i:where(.svelte-xyz) { color: green; }
.j.svelte-xyz ~ .j:where(.svelte-xyz) { color: green; }
.g.svelte-xyz ~ .j:where(.svelte-xyz) { color: green; }
.g.svelte-xyz ~ .h:where(.svelte-xyz) ~ .i:where(.svelte-xyz) ~ .j:where(.svelte-xyz) { color: green; }
/* no match */
/* (unused) .e ~ .f { color: green; }*/

@ -1,8 +1,8 @@
.a.svelte-xyz ~ .b.svelte-xyz { color: green; }
.a.svelte-xyz ~ .c.svelte-xyz { color: green; }
.b.svelte-xyz ~ .d.svelte-xyz { color: green; }
.c.svelte-xyz ~ .d.svelte-xyz { color: green; }
.a.svelte-xyz ~ .d.svelte-xyz { color: green; }
.a.svelte-xyz ~ .b:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .c:where(.svelte-xyz) { color: green; }
.b.svelte-xyz ~ .d:where(.svelte-xyz) { color: green; }
.c.svelte-xyz ~ .d:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .d:where(.svelte-xyz) { color: green; }
/* no match */
/* (unused) .b ~ .c { color: green; }*/

@ -1,60 +1,60 @@
/* boundary of each */
.a.svelte-xyz ~ .d.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz ~ .e.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz ~ .f.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz ~ .g.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz ~ .d.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz ~ .e.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz ~ .f.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz ~ .g.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz ~ .d:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .e:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .f:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .g:where(.svelte-xyz) { color: green; }
.c.svelte-xyz ~ .d:where(.svelte-xyz) { color: green; }
.c.svelte-xyz ~ .e:where(.svelte-xyz) { color: green; }
.c.svelte-xyz ~ .f:where(.svelte-xyz) { color: green; }
.c.svelte-xyz ~ .g:where(.svelte-xyz) { color: green; }
/* nested boundary of each */
.j.svelte-xyz ~ .m.svelte-xyz.svelte-xyz { color: green; }
.j.svelte-xyz ~ .n.svelte-xyz.svelte-xyz { color: green; }
.j.svelte-xyz ~ .o.svelte-xyz.svelte-xyz { color: green; }
.k.svelte-xyz ~ .m.svelte-xyz.svelte-xyz { color: green; }
.k.svelte-xyz ~ .n.svelte-xyz.svelte-xyz { color: green; }
.k.svelte-xyz ~ .o.svelte-xyz.svelte-xyz { color: green; }
.l.svelte-xyz ~ .m.svelte-xyz.svelte-xyz { color: green; }
.l.svelte-xyz ~ .n.svelte-xyz.svelte-xyz { color: green; }
.l.svelte-xyz ~ .o.svelte-xyz.svelte-xyz { color: green; }
.j.svelte-xyz ~ .m:where(.svelte-xyz) { color: green; }
.j.svelte-xyz ~ .n:where(.svelte-xyz) { color: green; }
.j.svelte-xyz ~ .o:where(.svelte-xyz) { color: green; }
.k.svelte-xyz ~ .m:where(.svelte-xyz) { color: green; }
.k.svelte-xyz ~ .n:where(.svelte-xyz) { color: green; }
.k.svelte-xyz ~ .o:where(.svelte-xyz) { color: green; }
.l.svelte-xyz ~ .m:where(.svelte-xyz) { color: green; }
.l.svelte-xyz ~ .n:where(.svelte-xyz) { color: green; }
.l.svelte-xyz ~ .o:where(.svelte-xyz) { color: green; }
/* parent each */
.d.svelte-xyz ~ .e.svelte-xyz.svelte-xyz { color: green; }
.e.svelte-xyz ~ .f.svelte-xyz.svelte-xyz { color: green; }
.d.svelte-xyz ~ .e:where(.svelte-xyz) { color: green; }
.e.svelte-xyz ~ .f:where(.svelte-xyz) { color: green; }
/* child each */
.g.svelte-xyz ~ .h.svelte-xyz.svelte-xyz { color: green; }
.g.svelte-xyz ~ .h:where(.svelte-xyz) { color: green; }
/* wrap around */
.f.svelte-xyz ~ .d.svelte-xyz.svelte-xyz { color: green; }
.f.svelte-xyz ~ .e.svelte-xyz.svelte-xyz { color: green; }
.f.svelte-xyz ~ .f.svelte-xyz.svelte-xyz { color: green; }
.f.svelte-xyz ~ .d:where(.svelte-xyz) { color: green; }
.f.svelte-xyz ~ .e:where(.svelte-xyz) { color: green; }
.f.svelte-xyz ~ .f:where(.svelte-xyz) { color: green; }
.h.svelte-xyz ~ .g.svelte-xyz.svelte-xyz { color: green; }
.i.svelte-xyz ~ .h.svelte-xyz.svelte-xyz { color: green; }
.i.svelte-xyz ~ .g.svelte-xyz.svelte-xyz { color: green; }
.h.svelte-xyz ~ .g:where(.svelte-xyz) { color: green; }
.i.svelte-xyz ~ .h:where(.svelte-xyz) { color: green; }
.i.svelte-xyz ~ .g:where(.svelte-xyz) { color: green; }
/* wrap around self */
.d.svelte-xyz ~ .d.svelte-xyz.svelte-xyz { color: green; }
.e.svelte-xyz ~ .e.svelte-xyz.svelte-xyz { color: green; }
.f.svelte-xyz ~ .f.svelte-xyz.svelte-xyz { color: green; }
.g.svelte-xyz ~ .g.svelte-xyz.svelte-xyz { color: green; }
.h.svelte-xyz ~ .h.svelte-xyz.svelte-xyz { color: green; }
.i.svelte-xyz ~ .i.svelte-xyz.svelte-xyz { color: green; }
.d.svelte-xyz ~ .d:where(.svelte-xyz) { color: green; }
.e.svelte-xyz ~ .e:where(.svelte-xyz) { color: green; }
.f.svelte-xyz ~ .f:where(.svelte-xyz) { color: green; }
.g.svelte-xyz ~ .g:where(.svelte-xyz) { color: green; }
.h.svelte-xyz ~ .h:where(.svelte-xyz) { color: green; }
.i.svelte-xyz ~ .i:where(.svelte-xyz) { color: green; }
/* wrap around self ~ next */
.e.svelte-xyz ~ .e.svelte-xyz ~ .f.svelte-xyz { color: green; }
.e.svelte-xyz ~ .e.svelte-xyz ~ .d.svelte-xyz { color: green; }
.h.svelte-xyz ~ .h.svelte-xyz ~ .i.svelte-xyz { color: green; }
.h.svelte-xyz ~ .h.svelte-xyz ~ .g.svelte-xyz { color: green; }
.e.svelte-xyz ~ .e:where(.svelte-xyz) ~ .f:where(.svelte-xyz) { color: green; }
.e.svelte-xyz ~ .e:where(.svelte-xyz) ~ .d:where(.svelte-xyz) { color: green; }
.h.svelte-xyz ~ .h:where(.svelte-xyz) ~ .i:where(.svelte-xyz) { color: green; }
.h.svelte-xyz ~ .h:where(.svelte-xyz) ~ .g:where(.svelte-xyz) { color: green; }
/* general siblings */
.a.svelte-xyz ~ .h.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz ~ .i.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz ~ .h.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz ~ .i.svelte-xyz.svelte-xyz { color: green; }
.d.svelte-xyz ~ .f.svelte-xyz.svelte-xyz { color: green; }
.d.svelte-xyz ~ .g.svelte-xyz.svelte-xyz { color: green; }
.e.svelte-xyz ~ .g.svelte-xyz.svelte-xyz { color: green; }
.g.svelte-xyz ~ .i.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz ~ .h:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .i:where(.svelte-xyz) { color: green; }
.c.svelte-xyz ~ .h:where(.svelte-xyz) { color: green; }
.c.svelte-xyz ~ .i:where(.svelte-xyz) { color: green; }
.d.svelte-xyz ~ .f:where(.svelte-xyz) { color: green; }
.d.svelte-xyz ~ .g:where(.svelte-xyz) { color: green; }
.e.svelte-xyz ~ .g:where(.svelte-xyz) { color: green; }
.g.svelte-xyz ~ .i:where(.svelte-xyz) { color: green; }

@ -1,3 +1,3 @@
div.svelte-xyz ~ span.svelte-xyz {
div.svelte-xyz ~ span:where(.svelte-xyz) {
color: green;
}

@ -1,3 +1,3 @@
h1.svelte-xyz ~ p.svelte-xyz {
h1.svelte-xyz ~ p:where(.svelte-xyz) {
color: red;
}

@ -1,12 +1,12 @@
.a.svelte-xyz ~ .b.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz ~ .c.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz ~ .d.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.b.svelte-xyz ~ .d.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz ~ .d.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz ~ .b:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .c:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .d:where(.svelte-xyz) { color: green; }
.b.svelte-xyz ~ .d:where(.svelte-xyz) { color: green; }
.c.svelte-xyz ~ .d:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .c.svelte-xyz ~ .c.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz ~ .c.svelte-xyz ~ .d.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz ~ .c.svelte-xyz ~ .c.svelte-xyz ~ .d.svelte-xyz { color: green; }
.a.svelte-xyz ~ .c:where(.svelte-xyz) ~ .c:where(.svelte-xyz) { color: green; }
.c.svelte-xyz ~ .c:where(.svelte-xyz) ~ .d:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .c:where(.svelte-xyz) ~ .c:where(.svelte-xyz) ~ .d:where(.svelte-xyz) { color: green; }
/* no match */
/* (unused) .b ~ .c { color: green; }*/

@ -1,8 +1,8 @@
.a.svelte-xyz ~ .b.svelte-xyz { color: green; }
.a.svelte-xyz ~ .c.svelte-xyz { color: green; }
.a.svelte-xyz ~ .d.svelte-xyz { color: green; }
.b.svelte-xyz ~ .d.svelte-xyz { color: green; }
.c.svelte-xyz ~ .d.svelte-xyz { color: green; }
.a.svelte-xyz ~ .b:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .c:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .d:where(.svelte-xyz) { color: green; }
.b.svelte-xyz ~ .d:where(.svelte-xyz) { color: green; }
.c.svelte-xyz ~ .d:where(.svelte-xyz) { color: green; }
/* no match */
/* (unused) .b ~ .c { color: green; }*/

@ -1,10 +1,10 @@
.a.svelte-xyz ~ .b.svelte-xyz { color: green; }
.a.svelte-xyz ~ .c.svelte-xyz { color: green; }
.a.svelte-xyz ~ .d.svelte-xyz { color: green; }
.b.svelte-xyz ~ .e.svelte-xyz { color: green; }
.c.svelte-xyz ~ .e.svelte-xyz { color: green; }
.d.svelte-xyz ~ .e.svelte-xyz { color: green; }
.a.svelte-xyz ~ .e.svelte-xyz { color: green; }
.a.svelte-xyz ~ .b:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .c:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .d:where(.svelte-xyz) { color: green; }
.b.svelte-xyz ~ .e:where(.svelte-xyz) { color: green; }
.c.svelte-xyz ~ .e:where(.svelte-xyz) { color: green; }
.d.svelte-xyz ~ .e:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .e:where(.svelte-xyz) { color: green; }
/* no match */
/* (unused) .b ~ .c { color: green; }*/

@ -1,3 +1,3 @@
h1.svelte-xyz ~ p.svelte-xyz {
h1.svelte-xyz ~ p:where(.svelte-xyz) {
color: red;
}

@ -1,3 +1,3 @@
h1.svelte-xyz ~ p.svelte-xyz {
h1.svelte-xyz ~ p:where(.svelte-xyz) {
color: red;
}

@ -1,3 +1,3 @@
h1.svelte-xyz ~ p.svelte-xyz {
h1.svelte-xyz ~ p:where(.svelte-xyz) {
color: red;
}

@ -1,5 +1,5 @@
.d.svelte-xyz ~ .e.svelte-xyz { color: green; }
.a.svelte-xyz ~ .g.svelte-xyz { color: green; }
.d.svelte-xyz ~ .e:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .g:where(.svelte-xyz) { color: green; }
/* no match */
/* (unused) .a ~ .b { color: green; }*/

@ -1,11 +1,11 @@
h1.svelte-xyz ~ span.svelte-xyz {
h1.svelte-xyz ~ span:where(.svelte-xyz) {
color: green;
}
h1.svelte-xyz ~ p.svelte-xyz {
h1.svelte-xyz ~ p:where(.svelte-xyz) {
color: red;
}
span.svelte-xyz ~ p.svelte-xyz {
span.svelte-xyz ~ p:where(.svelte-xyz) {
color: blue;
}

@ -1,4 +1,4 @@
.match.svelte-xyz > .svelte-xyz ~ .svelte-xyz {
.match.svelte-xyz > :where(.svelte-xyz) ~ :where(.svelte-xyz) {
margin-left: 4px;
}
/* (unused) .not-match > * ~ * {

@ -1,11 +1,11 @@
div.svelte-xyz ~ article.svelte-xyz.svelte-xyz { color: green; }
span.svelte-xyz ~ b.svelte-xyz.svelte-xyz { color: green; }
div.svelte-xyz span.svelte-xyz ~ b.svelte-xyz { color: green; }
.a.svelte-xyz ~ article.svelte-xyz.svelte-xyz { color: green; }
div.svelte-xyz ~ .b.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz ~ .c.svelte-xyz.svelte-xyz { color: green; }
article.svelte-xyz ~ details.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz ~ details.svelte-xyz.svelte-xyz { color: green; }
div.svelte-xyz ~ article:where(.svelte-xyz) { color: green; }
span.svelte-xyz ~ b:where(.svelte-xyz) { color: green; }
div.svelte-xyz span:where(.svelte-xyz) ~ b:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ article:where(.svelte-xyz) { color: green; }
div.svelte-xyz ~ .b:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ .c:where(.svelte-xyz) { color: green; }
article.svelte-xyz ~ details:where(.svelte-xyz) { color: green; }
.a.svelte-xyz ~ details:where(.svelte-xyz) { color: green; }
/* no match */
/* (unused) article ~ div { color: green; }*/

@ -1,9 +1,9 @@
button.svelte-xyz {
color: red;
+ .abc.svelte-xyz {
+ .abc:where(.svelte-xyz) {
color: purple;
}
color: black;
}
}

@ -1,20 +1,20 @@
button.svelte-xyz {
color: red;
& > div.svelte-xyz {
& > div:where(.svelte-xyz) {
color: blue;
}
& .foo.svelte-xyz {
& .foo:where(.svelte-xyz) {
color: yellow;
}
&:last-child {
color: green;
}
& .bar.svelte-xyz {
& .hello.svelte-xyz {
& .bar:where(.svelte-xyz) {
& .hello:where(.svelte-xyz) {
color: orange;
}
}
color: black;
}
}

@ -1,7 +1,7 @@
c.svelte-xyz {
color: red;
b.svelte-xyz & x.svelte-xyz {
b:where(.svelte-xyz) & x:where(.svelte-xyz) {
color: yellow;
}

@ -1,9 +1,9 @@
button.svelte-xyz {
color: red;
> .abc.svelte-xyz {
> .abc:where(.svelte-xyz) {
color: purple;
}
color: black;
}
}

@ -1,9 +1,9 @@
button.svelte-xyz {
color: red;
.hello.svelte-xyz {
.hello:where(.svelte-xyz) {
color: pink;
}
color: black;
}
}

@ -1,7 +1,7 @@
div.svelte-xyz {
color: red;
button.svelte-xyz {
button:where(.svelte-xyz) {
color: yellow;
}
}
}

@ -1,6 +1,6 @@
b.svelte-xyz {
color: red;
/* (empty) x.svelte-xyz {
/* (empty) x:where(.svelte-xyz) {
}*/
}
}

@ -1,5 +1,5 @@
b.svelte-xyz {
x.svelte-xyz {
x:where(.svelte-xyz) {
color: yellow;
}
}
}

@ -1,17 +1,17 @@
a.svelte-xyz {
color: red;
b.svelte-xyz {
b:where(.svelte-xyz) {
color: yellow;
c.svelte-xyz {
c:where(.svelte-xyz) {
color: green;
}
}
b c.svelte-xyz {
b c:where(.svelte-xyz) {
color: blue;
}
b c d.svelte-xyz {
b c d:where(.svelte-xyz) {
color: orange;
}
}
}

@ -1,7 +1,7 @@
/* (unused) a*/ b.svelte-xyz {
color: red;
x.svelte-xyz {
x:where(.svelte-xyz) {
color: yellow;
}

@ -1,9 +1,9 @@
a.svelte-xyz, b.svelte-xyz {
color: red;
x.svelte-xyz {
x:where(.svelte-xyz) {
color: purple;
}
color: black;
}
}

@ -1,3 +1,3 @@
html body .root.svelte-xyz p.svelte-xyz {
html body .root.svelte-xyz p:where(.svelte-xyz) {
color: red;
}

@ -1,3 +1,3 @@
.root.svelte-xyz p.svelte-xyz {
.root.svelte-xyz p:where(.svelte-xyz) {
color: red;
}

@ -1,3 +1,3 @@
div.svelte-xyz section p.svelte-xyz {
div.svelte-xyz section p:where(.svelte-xyz) {
color: red;
}

@ -1,3 +1,3 @@
div.svelte-xyz p.svelte-xyz {
div.svelte-xyz p:where(.svelte-xyz) {
color: red;
}

@ -1,8 +1,8 @@
a.svelte-xyz b c span.svelte-xyz {
a.svelte-xyz b c span:where(.svelte-xyz) {
color: red;
font-size: 2em;
font-family: 'Comic Sans MS';
}
.foo.svelte-xyz.svelte-xyz {
.foo.svelte-xyz {
color: green;
}

@ -1,13 +1,13 @@
.a.svelte-xyz + .b.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz + .c.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz + .d.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz + .e.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz + .f.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz + .g.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz + .h.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz + .b:where(.svelte-xyz) { color: green; }
.a.svelte-xyz + .c:where(.svelte-xyz) { color: green; }
.a.svelte-xyz + .d:where(.svelte-xyz) { color: green; }
.a.svelte-xyz + .e:where(.svelte-xyz) { color: green; }
.a.svelte-xyz + .f:where(.svelte-xyz) { color: green; }
.a.svelte-xyz + .g:where(.svelte-xyz) { color: green; }
.a.svelte-xyz + .h:where(.svelte-xyz) { color: green; }
.b.svelte-xyz + .d.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz + .d.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.b.svelte-xyz + .e.svelte-xyz + .f.svelte-xyz + .h.svelte-xyz { color: green; }
.b.svelte-xyz + .d.svelte-xyz + .h.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz + .g.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.b.svelte-xyz + .d:where(.svelte-xyz) { color: green; }
.c.svelte-xyz + .d:where(.svelte-xyz) { color: green; }
.b.svelte-xyz + .e:where(.svelte-xyz) + .f:where(.svelte-xyz) + .h:where(.svelte-xyz) { color: green; }
.b.svelte-xyz + .d:where(.svelte-xyz) + .h:where(.svelte-xyz) { color: green; }
.c.svelte-xyz + .g:where(.svelte-xyz) { color: green; }

@ -1,9 +1,9 @@
.a.svelte-xyz + .b.svelte-xyz { color: green; }
.a.svelte-xyz + .c.svelte-xyz { color: green; }
.a.svelte-xyz + .d.svelte-xyz { color: green; }
.b.svelte-xyz + .e.svelte-xyz { color: green; }
.c.svelte-xyz + .e.svelte-xyz { color: green; }
.d.svelte-xyz + .e.svelte-xyz { color: green; }
.a.svelte-xyz + .b:where(.svelte-xyz) { color: green; }
.a.svelte-xyz + .c:where(.svelte-xyz) { color: green; }
.a.svelte-xyz + .d:where(.svelte-xyz) { color: green; }
.b.svelte-xyz + .e:where(.svelte-xyz) { color: green; }
.c.svelte-xyz + .e:where(.svelte-xyz) { color: green; }
.d.svelte-xyz + .e:where(.svelte-xyz) { color: green; }
/* no match */
/* (unused) .a + .e { color: green; }*/

@ -1,20 +1,20 @@
/* boundary of each */
.a.svelte-xyz + .b.svelte-xyz {
.a.svelte-xyz + .b:where(.svelte-xyz) {
color: green;
}
.c.svelte-xyz + .d.svelte-xyz {
.c.svelte-xyz + .d:where(.svelte-xyz) {
color: green;
}
/* if array is empty */
.a.svelte-xyz + .d.svelte-xyz {
.a.svelte-xyz + .d:where(.svelte-xyz) {
color: green;
}
/* if array has multiple items */
.c.svelte-xyz + .b.svelte-xyz {
.c.svelte-xyz + .b:where(.svelte-xyz) {
color: green;
}
/* normal sibling */
.b.svelte-xyz + .c.svelte-xyz {
.b.svelte-xyz + .c:where(.svelte-xyz) {
color: green;
}
/* not match */

@ -1,18 +1,18 @@
.a.svelte-xyz + .e.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz + .f.svelte-xyz.svelte-xyz { color: green; }
.b.svelte-xyz + .c.svelte-xyz.svelte-xyz { color: green; }
.b.svelte-xyz + .d.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz + .e.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz + .f.svelte-xyz.svelte-xyz { color: green; }
.d.svelte-xyz + .e.svelte-xyz.svelte-xyz { color: green; }
.d.svelte-xyz + .f.svelte-xyz.svelte-xyz { color: green; }
.e.svelte-xyz + .e.svelte-xyz.svelte-xyz { color: green; }
.i.svelte-xyz + .j.svelte-xyz.svelte-xyz { color: green; }
.g.svelte-xyz + .h.svelte-xyz + .j.svelte-xyz { color: green; }
.g.svelte-xyz + .i.svelte-xyz + .j.svelte-xyz { color: green; }
.m.svelte-xyz + .m.svelte-xyz.svelte-xyz { color: green; }
.m.svelte-xyz + .l.svelte-xyz.svelte-xyz { color: green; }
.l.svelte-xyz + .m.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz + .e:where(.svelte-xyz) { color: green; }
.a.svelte-xyz + .f:where(.svelte-xyz) { color: green; }
.b.svelte-xyz + .c:where(.svelte-xyz) { color: green; }
.b.svelte-xyz + .d:where(.svelte-xyz) { color: green; }
.c.svelte-xyz + .e:where(.svelte-xyz) { color: green; }
.c.svelte-xyz + .f:where(.svelte-xyz) { color: green; }
.d.svelte-xyz + .e:where(.svelte-xyz) { color: green; }
.d.svelte-xyz + .f:where(.svelte-xyz) { color: green; }
.e.svelte-xyz + .e:where(.svelte-xyz) { color: green; }
.i.svelte-xyz + .j:where(.svelte-xyz) { color: green; }
.g.svelte-xyz + .h:where(.svelte-xyz) + .j:where(.svelte-xyz) { color: green; }
.g.svelte-xyz + .i:where(.svelte-xyz) + .j:where(.svelte-xyz) { color: green; }
.m.svelte-xyz + .m:where(.svelte-xyz) { color: green; }
.m.svelte-xyz + .l:where(.svelte-xyz) { color: green; }
.l.svelte-xyz + .m:where(.svelte-xyz) { color: green; }
/* no match */
/* (unused) .a + .c { color: green; }*/

@ -1,7 +1,7 @@
.a.svelte-xyz + .b.svelte-xyz { color: green; }
.a.svelte-xyz + .c.svelte-xyz { color: green; }
.b.svelte-xyz + .d.svelte-xyz { color: green; }
.c.svelte-xyz + .d.svelte-xyz { color: green; }
.a.svelte-xyz + .b:where(.svelte-xyz) { color: green; }
.a.svelte-xyz + .c:where(.svelte-xyz) { color: green; }
.b.svelte-xyz + .d:where(.svelte-xyz) { color: green; }
.c.svelte-xyz + .d:where(.svelte-xyz) { color: green; }
/* no match */
/* (unused) .a + .d { color: green; }*/

@ -1,53 +1,53 @@
/* boundary of each */
.a.svelte-xyz + .d.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz + .e.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz + .f.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz + .g.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz + .d.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz + .e.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz + .f.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz + .g.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz + .d:where(.svelte-xyz) { color: green; }
.a.svelte-xyz + .e:where(.svelte-xyz) { color: green; }
.a.svelte-xyz + .f:where(.svelte-xyz) { color: green; }
.a.svelte-xyz + .g:where(.svelte-xyz) { color: green; }
.c.svelte-xyz + .d:where(.svelte-xyz) { color: green; }
.c.svelte-xyz + .e:where(.svelte-xyz) { color: green; }
.c.svelte-xyz + .f:where(.svelte-xyz) { color: green; }
.c.svelte-xyz + .g:where(.svelte-xyz) { color: green; }
/* nested boundary of each */
.j.svelte-xyz + .m.svelte-xyz.svelte-xyz { color: green; }
.j.svelte-xyz + .n.svelte-xyz.svelte-xyz { color: green; }
.j.svelte-xyz + .o.svelte-xyz.svelte-xyz { color: green; }
.k.svelte-xyz + .m.svelte-xyz.svelte-xyz { color: green; }
.k.svelte-xyz + .n.svelte-xyz.svelte-xyz { color: green; }
.k.svelte-xyz + .o.svelte-xyz.svelte-xyz { color: green; }
.l.svelte-xyz + .m.svelte-xyz.svelte-xyz { color: green; }
.l.svelte-xyz + .n.svelte-xyz.svelte-xyz { color: green; }
.l.svelte-xyz + .o.svelte-xyz.svelte-xyz { color: green; }
.j.svelte-xyz + .m:where(.svelte-xyz) { color: green; }
.j.svelte-xyz + .n:where(.svelte-xyz) { color: green; }
.j.svelte-xyz + .o:where(.svelte-xyz) { color: green; }
.k.svelte-xyz + .m:where(.svelte-xyz) { color: green; }
.k.svelte-xyz + .n:where(.svelte-xyz) { color: green; }
.k.svelte-xyz + .o:where(.svelte-xyz) { color: green; }
.l.svelte-xyz + .m:where(.svelte-xyz) { color: green; }
.l.svelte-xyz + .n:where(.svelte-xyz) { color: green; }
.l.svelte-xyz + .o:where(.svelte-xyz) { color: green; }
/* parent each */
.d.svelte-xyz + .e.svelte-xyz.svelte-xyz { color: green; }
.e.svelte-xyz + .f.svelte-xyz.svelte-xyz { color: green; }
.d.svelte-xyz + .e:where(.svelte-xyz) { color: green; }
.e.svelte-xyz + .f:where(.svelte-xyz) { color: green; }
/* child each */
.g.svelte-xyz + .h.svelte-xyz.svelte-xyz { color: green; }
.g.svelte-xyz + .h:where(.svelte-xyz) { color: green; }
/* wrap around */
.f.svelte-xyz + .d.svelte-xyz.svelte-xyz { color: green; }
.f.svelte-xyz + .e.svelte-xyz.svelte-xyz { color: green; }
.f.svelte-xyz + .f.svelte-xyz.svelte-xyz { color: green; }
.f.svelte-xyz + .d:where(.svelte-xyz) { color: green; }
.f.svelte-xyz + .e:where(.svelte-xyz) { color: green; }
.f.svelte-xyz + .f:where(.svelte-xyz) { color: green; }
.h.svelte-xyz + .g.svelte-xyz.svelte-xyz { color: green; }
.i.svelte-xyz + .h.svelte-xyz.svelte-xyz { color: green; }
.i.svelte-xyz + .g.svelte-xyz.svelte-xyz { color: green; }
.h.svelte-xyz + .g:where(.svelte-xyz) { color: green; }
.i.svelte-xyz + .h:where(.svelte-xyz) { color: green; }
.i.svelte-xyz + .g:where(.svelte-xyz) { color: green; }
/* wrap around self */
.d.svelte-xyz + .d.svelte-xyz.svelte-xyz { color: green; }
.e.svelte-xyz + .e.svelte-xyz.svelte-xyz { color: green; }
.f.svelte-xyz + .f.svelte-xyz.svelte-xyz { color: green; }
.g.svelte-xyz + .g.svelte-xyz.svelte-xyz { color: green; }
.h.svelte-xyz + .h.svelte-xyz.svelte-xyz { color: green; }
.i.svelte-xyz + .i.svelte-xyz.svelte-xyz { color: green; }
.d.svelte-xyz + .d:where(.svelte-xyz) { color: green; }
.e.svelte-xyz + .e:where(.svelte-xyz) { color: green; }
.f.svelte-xyz + .f:where(.svelte-xyz) { color: green; }
.g.svelte-xyz + .g:where(.svelte-xyz) { color: green; }
.h.svelte-xyz + .h:where(.svelte-xyz) { color: green; }
.i.svelte-xyz + .i:where(.svelte-xyz) { color: green; }
/* wrap around self + next */
.e.svelte-xyz + .e.svelte-xyz + .f.svelte-xyz { color: green; }
.e.svelte-xyz + .e.svelte-xyz + .d.svelte-xyz { color: green; }
.h.svelte-xyz + .h.svelte-xyz + .i.svelte-xyz { color: green; }
.h.svelte-xyz + .h.svelte-xyz + .g.svelte-xyz { color: green; }
.e.svelte-xyz + .e:where(.svelte-xyz) + .f:where(.svelte-xyz) { color: green; }
.e.svelte-xyz + .e:where(.svelte-xyz) + .d:where(.svelte-xyz) { color: green; }
.h.svelte-xyz + .h:where(.svelte-xyz) + .i:where(.svelte-xyz) { color: green; }
.h.svelte-xyz + .h:where(.svelte-xyz) + .g:where(.svelte-xyz) { color: green; }
/* no match */
/* (unused) .a + .h { color: green; }*/

@ -1,3 +1,3 @@
div.svelte-xyz + span.svelte-xyz {
div.svelte-xyz + span:where(.svelte-xyz) {
color: green;
}

@ -1,3 +1,3 @@
h1.svelte-xyz + span.svelte-xyz {
h1.svelte-xyz + span:where(.svelte-xyz) {
color: red;
}

@ -1,12 +1,12 @@
.a.svelte-xyz + .b.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz + .c.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz + .d.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.b.svelte-xyz + .d.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz + .d.svelte-xyz.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz + .b:where(.svelte-xyz) { color: green; }
.a.svelte-xyz + .c:where(.svelte-xyz) { color: green; }
.a.svelte-xyz + .d:where(.svelte-xyz) { color: green; }
.b.svelte-xyz + .d:where(.svelte-xyz) { color: green; }
.c.svelte-xyz + .d:where(.svelte-xyz) { color: green; }
.a.svelte-xyz + .c.svelte-xyz + .c.svelte-xyz.svelte-xyz { color: green; }
.c.svelte-xyz + .c.svelte-xyz + .d.svelte-xyz.svelte-xyz { color: green; }
.a.svelte-xyz + .c.svelte-xyz + .c.svelte-xyz + .d.svelte-xyz { color: green; }
.a.svelte-xyz + .c:where(.svelte-xyz) + .c:where(.svelte-xyz) { color: green; }
.c.svelte-xyz + .c:where(.svelte-xyz) + .d:where(.svelte-xyz) { color: green; }
.a.svelte-xyz + .c:where(.svelte-xyz) + .c:where(.svelte-xyz) + .d:where(.svelte-xyz) { color: green; }
/* no match */
/* (unused) .b + .c { color: green; }*/

@ -1,8 +1,8 @@
.a.svelte-xyz + .b.svelte-xyz { color: green; }
.a.svelte-xyz + .c.svelte-xyz { color: green; }
.a.svelte-xyz + .d.svelte-xyz { color: green; }
.b.svelte-xyz + .d.svelte-xyz { color: green; }
.c.svelte-xyz + .d.svelte-xyz { color: green; }
.a.svelte-xyz + .b:where(.svelte-xyz) { color: green; }
.a.svelte-xyz + .c:where(.svelte-xyz) { color: green; }
.a.svelte-xyz + .d:where(.svelte-xyz) { color: green; }
.b.svelte-xyz + .d:where(.svelte-xyz) { color: green; }
.c.svelte-xyz + .d:where(.svelte-xyz) { color: green; }
/* no match */
/* (unused) .b + .c { color: green; }*/

@ -1,9 +1,9 @@
.a.svelte-xyz + .b.svelte-xyz { color: green; }
.a.svelte-xyz + .c.svelte-xyz { color: green; }
.a.svelte-xyz + .d.svelte-xyz { color: green; }
.b.svelte-xyz + .e.svelte-xyz { color: green; }
.c.svelte-xyz + .e.svelte-xyz { color: green; }
.d.svelte-xyz + .e.svelte-xyz { color: green; }
.a.svelte-xyz + .b:where(.svelte-xyz) { color: green; }
.a.svelte-xyz + .c:where(.svelte-xyz) { color: green; }
.a.svelte-xyz + .d:where(.svelte-xyz) { color: green; }
.b.svelte-xyz + .e:where(.svelte-xyz) { color: green; }
.c.svelte-xyz + .e:where(.svelte-xyz) { color: green; }
.d.svelte-xyz + .e:where(.svelte-xyz) { color: green; }
/* no match */
/* (unused) .a + .e { color: green; }*/

@ -1,3 +1,3 @@
h1.svelte-xyz + span.svelte-xyz {
h1.svelte-xyz + span:where(.svelte-xyz) {
color: red;
}

@ -1,3 +1,3 @@
h1.svelte-xyz + span.svelte-xyz {
h1.svelte-xyz + span:where(.svelte-xyz) {
color: red;
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save