Merge branch 'master' into pr/5433

pull/5433/head
Conduitry 5 years ago
commit f4fbafea8e

@ -2,6 +2,23 @@
## Unreleased
* Add `EventSource` to known globals ([#5463](https://github.com/sveltejs/svelte/issues/5463))
* Fix compiler exception with `~`/`+` combinators and `{...spread}` attributes ([#5465](https://github.com/sveltejs/svelte/issues/5465))
## 3.28.0
* Add `{#key}` block for keying arbitrary content on an expression ([#1469](https://github.com/sveltejs/svelte/issues/1469))
## 3.27.0
* Add `|nonpassive` event modifier, explicitly passing `passive: false` ([#2068](https://github.com/sveltejs/svelte/issues/2068))
* Scope CSS selectors with `~` and `+` combinators ([#3104](https://github.com/sveltejs/svelte/issues/3104))
* Fix keyed `{#each}` not reacting to key changing ([#5444](https://github.com/sveltejs/svelte/issues/5444))
* Fix destructuring into store values ([#5449](https://github.com/sveltejs/svelte/issues/5449))
* Fix erroneous `missing-declaration` warning with `use:obj.method` ([#5451](https://github.com/sveltejs/svelte/issues/5451))
## 3.26.0
* Support `use:obj.method` as actions ([#3935](https://github.com/sveltejs/svelte/issues/3935))
* Support `_` as numeric separator ([#5407](https://github.com/sveltejs/svelte/issues/5407))
* Fix assignments to properties on store values ([#5412](https://github.com/sveltejs/svelte/issues/5412))

2
package-lock.json generated

@ -1,6 +1,6 @@
{
"name": "svelte",
"version": "3.25.1",
"version": "3.28.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

@ -1,6 +1,6 @@
{
"name": "svelte",
"version": "3.25.1",
"version": "3.28.0",
"description": "Cybernetically enhanced web apps",
"module": "index.mjs",
"main": "index",

@ -30,7 +30,9 @@ To treat `*.svelte` files as HTML, open *__Edit → Config...__* and add the fol
## Vim/Neovim
To treat all `*.svelte` files as HTML, add the following line to your `init.vim`:
You can use the [coc-svelte extension](https://github.com/coc-extensions/coc-svelte) which utilises the official language-server.
As an alternative you can treat all `*.svelte` files as HTML. Add the following line to your `init.vim`:
```
au! BufNewFile,BufRead *.svelte set ft=html
@ -50,13 +52,7 @@ To set the filetype for a single file, use a [modeline](https://vim.fandom.com/w
## Visual Studio Code
To treat `*.svelte` files as HTML, add the following lines to your `settings.json` file:
```cson
"files.associations": {
"*.svelte": "html"
}
```
We recommend using the official [Svelte for VS Code extension](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode).
## JetBrains WebStorm

@ -342,6 +342,33 @@ If you don't care about the pending state, you can also omit the initial block.
{/await}
```
### {#key ...}
```sv
{#key expression}...{/key}
```
Key blocks destroy and recreate their contents when the value of an expression changes.
---
This is useful if you want an element to play its transition whenever a value changes.
```sv
{#key value}
<div transition:fade>{value}</div>
{/key}
```
---
When used around components, this will cause them to be reinstantiated and reinitialised.
```sv
{#key value}
<Component />
{/key}
```
### {@html ...}
@ -471,6 +498,7 @@ The following modifiers are available:
* `preventDefault` — calls `event.preventDefault()` before running the handler
* `stopPropagation` — calls `event.stopPropagation()`, preventing the event reaching the next element
* `passive` — improves scrolling performance on touch/wheel events (Svelte will add it automatically where it's safe to do so)
* `nonpassive` — explicitly set `passive: false`
* `capture` — fires the handler during the *capture* phase instead of the *bubbling* phase
* `once` — remove the handler after the first time it runs
* `self` — only trigger handler if event.target is the element itself

@ -13,7 +13,7 @@ First, you'll need to integrate Svelte with a build tool. There are officially m
Don't worry if you're relatively new to web development and haven't used these tools before. We've prepared a simple step-by-step guide, [Svelte for new developers](blog/svelte-for-new-developers), which walks you through the process.
You'll also want to configure your text editor to treat `.svelte` files the same as `.html` for the sake of syntax highlighting. [Read this guide to learn how](blog/setting-up-your-editor).
You'll also want to configure your text editor. If you're using VS Code, install the [Svelte extension](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode), otherwise follow [this guide](blog/setting-up-your-editor) to configure your text editor to treat `.svelte` files the same as `.html` for the sake of syntax highlighting.
Then, once you've got your project set up, using Svelte components is easy. The compiler turns each component into a regular JavaScript class — just import it and instantiate with `new`:

@ -21,6 +21,7 @@ The full list of modifiers:
* `preventDefault` — calls `event.preventDefault()` before running the handler. Useful for client-side form handling, for example.
* `stopPropagation` — calls `event.stopPropagation()`, preventing the event reaching the next element
* `passive` — improves scrolling performance on touch/wheel events (Svelte will add it automatically where it's safe to do so)
* `nonpassive` — explicitly set `passive: false`
* `capture` — fires the handler during the *capture* phase instead of the *bubbling* phase ([MDN docs](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture))
* `once` — remove the handler after the first time it runs
* `self` — only trigger handler if event.target is the element itself

@ -29,6 +29,7 @@ import add_to_set from './utils/add_to_set';
import check_graph_for_cycles from './utils/check_graph_for_cycles';
import { print, x, b } from 'code-red';
import { is_reserved_keyword } from './utils/reserved_keywords';
import Element from './nodes/Element';
interface ComponentOptions {
namespace?: string;
@ -85,6 +86,7 @@ export default class Component {
file: string;
locate: (c: number) => { line: number; column: number };
elements: Element[] = [];
stylesheet: Stylesheet;
aliases: Map<string, Identifier> = new Map();
@ -171,8 +173,8 @@ export default class Component {
this.walk_instance_js_post_template();
this.elements.forEach(element => this.stylesheet.apply(element));
if (!compile_options.customElement) this.stylesheet.reify();
this.stylesheet.warn_on_unused_selectors(this);
}
@ -221,6 +223,10 @@ export default class Component {
return this.aliases.get(name);
}
apply_stylesheet(element: Element) {
this.elements.push(element);
}
global(name: string) {
const alias = this.alias(name);
this.globals.set(name, alias);

@ -4,12 +4,20 @@ import { gather_possible_values, UNKNOWN } from './gather_possible_values';
import { CssNode } from './interfaces';
import Component from '../Component';
import Element from '../nodes/Element';
import { INode } from '../nodes/interfaces';
import EachBlock from '../nodes/EachBlock';
import IfBlock from '../nodes/IfBlock';
import AwaitBlock from '../nodes/AwaitBlock';
enum BlockAppliesToNode {
NotPossible,
Possible,
UnknownSelectorType
}
enum NodeExist {
Probably = 1,
Definitely = 2,
}
const whitelist_attribute_selector = new Map([
['details', new Set(['open'])]
@ -39,10 +47,10 @@ export default class Selector {
this.used = this.local_blocks.length === 0;
}
apply(node: Element, stack: Element[]) {
apply(node: Element) {
const to_encapsulate: any[] = [];
apply_selector(this.local_blocks.slice(), node, stack.slice(), to_encapsulate);
apply_selector(this.local_blocks.slice(), node, to_encapsulate);
if (to_encapsulate.length > 0) {
to_encapsulate.forEach(({ node, block }) => {
@ -149,7 +157,7 @@ export default class Selector {
}
}
function apply_selector(blocks: Block[], node: Element, stack: Element[], to_encapsulate: any[]): boolean {
function apply_selector(blocks: Block[], node: Element, to_encapsulate: any[]): boolean {
const block = blocks.pop();
if (!block) return false;
@ -162,7 +170,7 @@ function apply_selector(blocks: Block[], node: Element, stack: Element[], to_enc
return false;
case BlockAppliesToNode.UnknownSelectorType:
// bail. TODO figure out what these could be
// bail. TODO figure out what these could be
to_encapsulate.push({ node, block });
return true;
}
@ -174,9 +182,10 @@ function apply_selector(blocks: Block[], node: Element, stack: Element[], to_enc
continue;
}
for (const stack_node of stack) {
if (block_might_apply_to_node(ancestor_block, stack_node) !== BlockAppliesToNode.NotPossible) {
to_encapsulate.push({ node: stack_node, block: ancestor_block });
let parent = node;
while (parent = get_element_parent(parent)) {
if (block_might_apply_to_node(ancestor_block, parent) !== BlockAppliesToNode.NotPossible) {
to_encapsulate.push({ node: parent, block: ancestor_block });
}
}
@ -193,12 +202,22 @@ function apply_selector(blocks: Block[], node: Element, stack: Element[], to_enc
return false;
} else if (block.combinator.name === '>') {
if (apply_selector(blocks, stack.pop(), stack, to_encapsulate)) {
if (apply_selector(blocks, get_element_parent(node), to_encapsulate)) {
to_encapsulate.push({ node, block });
return true;
}
return false;
} else if (block.combinator.name === '+' || block.combinator.name === '~') {
const siblings = get_possible_element_siblings(node, block.combinator.name === '+');
let has_match = false;
for (const possible_sibling of siblings.keys()) {
if (apply_selector(blocks.slice(), possible_sibling, to_encapsulate)) {
to_encapsulate.push({ node, block });
has_match = true;
}
}
return has_match;
}
// TODO other combinators
@ -376,6 +395,158 @@ function unquote(value: CssNode) {
return str;
}
function get_element_parent(node: Element): Element | null {
let parent: INode = node;
while ((parent = parent.parent) && parent.type !== 'Element');
return parent as Element | null;
}
function get_possible_element_siblings(node: INode, adjacent_only: boolean): Map<Element, NodeExist> {
const result: Map<Element, NodeExist> = new Map();
let prev: INode = node;
while (prev = prev.prev) {
if (prev.type === 'Element') {
if (!prev.attributes.find(attr => attr.type === 'Attribute' && attr.name.toLowerCase() === 'slot')) {
result.set(prev, NodeExist.Definitely);
}
if (adjacent_only) {
break;
}
} else if (prev.type === 'EachBlock' || prev.type === 'IfBlock' || prev.type === 'AwaitBlock') {
const possible_last_child = get_possible_last_child(prev, adjacent_only);
add_to_map(possible_last_child, result);
if (adjacent_only && has_definite_elements(possible_last_child)) {
return result;
}
}
}
if (!prev || !adjacent_only) {
let parent: INode = node;
let skip_each_for_last_child = node.type === 'ElseBlock';
while ((parent = parent.parent) && (parent.type === 'EachBlock' || parent.type === 'IfBlock' || parent.type === 'ElseBlock' || parent.type === 'AwaitBlock')) {
const possible_siblings = get_possible_element_siblings(parent, adjacent_only);
add_to_map(possible_siblings, result);
if (parent.type === 'EachBlock') {
// first child of each block can select the last child of each block as previous sibling
if (skip_each_for_last_child) {
skip_each_for_last_child = false;
} else {
add_to_map(get_possible_last_child(parent, adjacent_only), result);
}
} else if (parent.type === 'ElseBlock') {
skip_each_for_last_child = true;
parent = parent.parent;
}
if (adjacent_only && has_definite_elements(possible_siblings)) {
break;
}
}
}
return result;
}
function get_possible_last_child(block: EachBlock | IfBlock | AwaitBlock, adjacent_only: boolean): Map<Element, NodeExist> {
const result: Map<Element, NodeExist> = new Map();
if (block.type === 'EachBlock') {
const each_result: Map<Element, NodeExist> = loop_child(block.children, adjacent_only);
const else_result: Map<Element, NodeExist> = block.else ? loop_child(block.else.children, adjacent_only) : new Map();
const not_exhaustive = !has_definite_elements(else_result);
if (not_exhaustive) {
mark_as_probably(each_result);
mark_as_probably(else_result);
}
add_to_map(each_result, result);
add_to_map(else_result, result);
} else if (block.type === 'IfBlock') {
const if_result: Map<Element, NodeExist> = loop_child(block.children, adjacent_only);
const else_result: Map<Element, NodeExist> = block.else ? loop_child(block.else.children, adjacent_only) : new Map();
const not_exhaustive = !has_definite_elements(if_result) || !has_definite_elements(else_result);
if (not_exhaustive) {
mark_as_probably(if_result);
mark_as_probably(else_result);
}
add_to_map(if_result, result);
add_to_map(else_result, result);
} else if (block.type === 'AwaitBlock') {
const pending_result: Map<Element, NodeExist> = block.pending ? loop_child(block.pending.children, adjacent_only) : new Map();
const then_result: Map<Element, NodeExist> = block.then ? loop_child(block.then.children, adjacent_only) : new Map();
const catch_result: Map<Element, NodeExist> = block.catch ? loop_child(block.catch.children, adjacent_only) : new Map();
const not_exhaustive = !has_definite_elements(pending_result) || !has_definite_elements(then_result) || !has_definite_elements(catch_result);
if (not_exhaustive) {
mark_as_probably(pending_result);
mark_as_probably(then_result);
mark_as_probably(catch_result);
}
add_to_map(pending_result, result);
add_to_map(then_result, result);
add_to_map(catch_result, result);
}
return result;
}
function has_definite_elements(result: Map<Element, NodeExist>): boolean {
if (result.size === 0) return false;
for (const exist of result.values()) {
if (exist === NodeExist.Definitely) {
return true;
}
}
return false;
}
function add_to_map(from: Map<Element, NodeExist>, to: Map<Element, NodeExist>) {
from.forEach((exist, element) => {
to.set(element, higher_existance(exist, to.get(element)));
});
}
function higher_existance(exist1: NodeExist | null, exist2: NodeExist | null): NodeExist {
if (exist1 === undefined || exist2 === undefined) return exist1 || exist2;
return exist1 > exist2 ? exist1 : exist2;
}
function mark_as_probably(result: Map<Element, NodeExist>) {
for (const key of result.keys()) {
result.set(key, NodeExist.Probably);
}
}
function loop_child(children: INode[], adjacent_only: boolean) {
const result: Map<Element, NodeExist> = new Map();
for (let i = children.length - 1; i >= 0; i--) {
const child = children[i];
if (child.type === 'Element') {
result.set(child, NodeExist.Definitely);
if (adjacent_only) {
break;
}
} else if (child.type === 'EachBlock' || child.type === 'IfBlock' || child.type === 'AwaitBlock') {
const child_result = get_possible_last_child(child, adjacent_only);
add_to_map(child_result, result);
if (adjacent_only && has_definite_elements(child_result)) {
break;
}
}
}
return result;
}
class Block {
global: boolean;
combinator: CssNode;

@ -2,7 +2,7 @@ import MagicString from 'magic-string';
import { walk } from 'estree-walker';
import Selector from './Selector';
import Element from '../nodes/Element';
import { Ast, TemplateNode } from '../../interfaces';
import { Ast } from '../../interfaces';
import Component from '../Component';
import { CssNode } from './interfaces';
import hash from "../utils/hash";
@ -51,8 +51,8 @@ class Rule {
this.declarations = node.block.children.map((node: CssNode) => new Declaration(node));
}
apply(node: Element, stack: Element[]) {
this.selectors.forEach(selector => selector.apply(node, stack)); // TODO move the logic in here?
apply(node: Element) {
this.selectors.forEach(selector => selector.apply(node)); // TODO move the logic in here?
}
is_used(dev: boolean) {
@ -162,10 +162,10 @@ class Atrule {
this.declarations = [];
}
apply(node: Element, stack: Element[]) {
apply(node: Element) {
if (this.node.name === 'media' || this.node.name === 'supports') {
this.children.forEach(child => {
child.apply(node, stack);
child.apply(node);
});
}
@ -364,15 +364,9 @@ export default class Stylesheet {
apply(node: Element) {
if (!this.has_styles) return;
const stack: Element[] = [];
let parent: TemplateNode = node;
while (parent = parent.parent) {
if (parent.type === 'Element') stack.unshift(parent as Element);
}
for (let i = 0; i < this.children.length; i += 1) {
const child = this.children[i];
child.apply(node, stack);
child.apply(node);
}
}

@ -11,10 +11,11 @@ export default class Action extends Node {
constructor(component: Component, parent, scope, info) {
super(component, parent, scope, info);
component.warn_if_undefined(info.name, info, scope);
const object = info.name.split('.')[0];
component.warn_if_undefined(object, info, scope);
this.name = info.name;
component.add_reference(info.name.split('.')[0]);
component.add_reference(object);
this.expression = info.expression
? new Expression(component, this, scope, info.expression)

@ -16,6 +16,7 @@ import list from '../../utils/list';
import Let from './Let';
import TemplateScope from './shared/TemplateScope';
import { INode } from './interfaces';
import Component from '../Component';
const svg = /^(?:altGlyph|altGlyphDef|altGlyphItem|animate|animateColor|animateMotion|animateTransform|circle|clipPath|color-profile|cursor|defs|desc|discard|ellipse|feBlend|feColorMatrix|feComponentTransfer|feComposite|feConvolveMatrix|feDiffuseLighting|feDisplacementMap|feDistantLight|feDropShadow|feFlood|feFuncA|feFuncB|feFuncG|feFuncR|feGaussianBlur|feImage|feMerge|feMergeNode|feMorphology|feOffset|fePointLight|feSpecularLighting|feSpotLight|feTile|feTurbulence|filter|font|font-face|font-face-format|font-face-name|font-face-src|font-face-uri|foreignObject|g|glyph|glyphRef|hatch|hatchpath|hkern|image|line|linearGradient|marker|mask|mesh|meshgradient|meshpatch|meshrow|metadata|missing-glyph|mpath|path|pattern|polygon|polyline|radialGradient|rect|set|solidcolor|stop|svg|switch|symbol|text|textPath|tref|tspan|unknown|use|view|vkern)$/;
@ -80,6 +81,7 @@ const valid_modifiers = new Set([
'capture',
'once',
'passive',
'nonpassive',
'self'
]);
@ -123,7 +125,7 @@ export default class Element extends Node {
namespace: string;
needs_manual_style_scoping: boolean;
constructor(component, parent, scope, info: any) {
constructor(component: Component, parent, scope, info: any) {
super(component, parent, scope, info);
this.name = info.name;
@ -184,7 +186,7 @@ export default class Element extends Node {
case 'Attribute':
case 'Spread':
// special case
// special case
if (node.name === 'xmlns') this.namespace = node.value[0].data;
this.attributes.push(new Attribute(component, this, scope, node));
@ -235,7 +237,7 @@ export default class Element extends Node {
this.validate();
component.stylesheet.apply(this);
component.apply_stylesheet(this);
}
validate() {
@ -770,6 +772,13 @@ export default class Element extends Node {
});
}
if (handler.modifiers.has('passive') && handler.modifiers.has('nonpassive')) {
component.error(handler, {
code: 'invalid-event-modifier',
message: `The 'passive' and 'nonpassive' modifiers cannot be used together`
});
}
handler.modifiers.forEach(modifier => {
if (!valid_modifiers.has(modifier)) {
component.error(handler, {
@ -804,7 +813,7 @@ export default class Element extends Node {
}
});
if (passive_events.has(handler.name) && handler.can_make_passive && !handler.modifiers.has('preventDefault')) {
if (passive_events.has(handler.name) && handler.can_make_passive && !handler.modifiers.has('preventDefault') && !handler.modifiers.has('nonpassive')) {
// touch/wheel events should be passive by default
handler.modifiers.add('passive');
}

@ -0,0 +1,19 @@
import Expression from "./shared/Expression";
import map_children from "./shared/map_children";
import AbstractBlock from "./shared/AbstractBlock";
export default class KeyBlock extends AbstractBlock {
type: "KeyBlock";
expression: Expression;
constructor(component, parent, scope, info) {
super(component, parent, scope, info);
this.expression = new Expression(component, this, scope, info.expression);
this.children = map_children(component, this, scope, info.children);
this.warn_if_empty_block();
}
}

@ -18,6 +18,7 @@ import Fragment from './Fragment';
import Head from './Head';
import IfBlock from './IfBlock';
import InlineComponent from './InlineComponent';
import KeyBlock from './KeyBlock';
import Let from './Let';
import MustacheTag from './MustacheTag';
import Options from './Options';
@ -50,6 +51,7 @@ export type INode = Action
| Head
| IfBlock
| InlineComponent
| KeyBlock
| Let
| MustacheTag
| Options

@ -6,6 +6,7 @@ import Element from '../Element';
import Head from '../Head';
import IfBlock from '../IfBlock';
import InlineComponent from '../InlineComponent';
import KeyBlock from '../KeyBlock';
import MustacheTag from '../MustacheTag';
import Options from '../Options';
import RawMustacheTag from '../RawMustacheTag';
@ -28,6 +29,7 @@ function get_constructor(type) {
case 'Head': return Head;
case 'IfBlock': return IfBlock;
case 'InlineComponent': return InlineComponent;
case 'KeyBlock': return KeyBlock;
case 'MustacheTag': return MustacheTag;
case 'Options': return Options;
case 'RawMustacheTag': return RawMustacheTag;

@ -36,47 +36,46 @@ export function invalidate(renderer: Renderer, scope: Scope, node: Node, names:
return renderer.invalidate(variable.name, undefined, main_execution_context);
}
if (head) {
component.has_reactive_assignments = true;
if (node.type === 'AssignmentExpression' && node.operator === '=' && nodes_match(node.left, node.right) && tail.length === 0) {
return get_invalidated(head, node);
} else {
const is_store_value = head.name[0] === '$' && head.name[1] !== '$';
const extra_args = tail.map(variable => get_invalidated(variable)).filter(Boolean);
const pass_value = (
!main_execution_context &&
(
extra_args.length > 0 ||
(node.type === 'AssignmentExpression' && node.left.type !== 'Identifier') ||
(node.type === 'UpdateExpression' && (!node.prefix || node.argument.type !== 'Identifier'))
)
);
if (!head) {
return node;
}
if (pass_value) {
extra_args.unshift({
type: 'Identifier',
name: head.name
});
}
component.has_reactive_assignments = true;
let invalidate = is_store_value
? x`@set_store_value(${head.name.slice(1)}, ${node}, ${head.name})`
: !main_execution_context
? x`$$invalidate(${renderer.context_lookup.get(head.name).index}, ${node}, ${extra_args})`
: extra_args.length
? [node, ...extra_args]
: node;
if (node.type === 'AssignmentExpression' && node.operator === '=' && nodes_match(node.left, node.right) && tail.length === 0) {
return get_invalidated(head, node);
}
if (head.subscribable && head.reassigned) {
const subscribe = `$$subscribe_${head.name}`;
invalidate = x`${subscribe}(${invalidate})`;
}
const is_store_value = head.name[0] === '$' && head.name[1] !== '$';
const extra_args = tail.map(variable => get_invalidated(variable)).filter(Boolean);
return invalidate;
if (is_store_value) {
return x`@set_store_value(${head.name.slice(1)}, ${node}, ${head.name}, ${extra_args})`;
}
let invalidate;
if (!main_execution_context) {
const pass_value = (
extra_args.length > 0 ||
(node.type === 'AssignmentExpression' && node.left.type !== 'Identifier') ||
(node.type === 'UpdateExpression' && (!node.prefix || node.argument.type !== 'Identifier'))
);
if (pass_value) {
extra_args.unshift({
type: 'Identifier',
name: head.name
});
}
invalidate = x`$$invalidate(${renderer.context_lookup.get(head.name).index}, ${node}, ${extra_args})`;
} else {
// skip `$$invalidate` if it is in the main execution context
invalidate = extra_args.length ? [node, ...extra_args] : node;
}
if (head.subscribable && head.reassigned) {
const subscribe = `$$subscribe_${head.name}`;
invalidate = x`${subscribe}(${invalidate})`;
}
return node;
return invalidate;
}

@ -239,6 +239,11 @@ export default class EachBlockWrapper extends Wrapper {
this.node.expression.dynamic_dependencies().forEach((dependency: string) => {
all_dependencies.add(dependency);
});
if (this.node.key) {
this.node.key.dynamic_dependencies().forEach((dependency: string) => {
all_dependencies.add(dependency);
});
}
this.dependencies = all_dependencies;
if (this.node.key) {

@ -45,11 +45,17 @@ export default class EventHandlerWrapper {
const args = [];
const opts = ['passive', 'once', 'capture'].filter(mod => this.node.modifiers.has(mod));
const opts = ['nonpassive', 'passive', 'once', 'capture'].filter(mod => this.node.modifiers.has(mod));
if (opts.length) {
args.push((opts.length === 1 && opts[0] === 'capture')
? TRUE
: x`{ ${opts.map(opt => p`${opt}: true`)} }`);
if (opts.length === 1 && opts[0] === 'capture') {
args.push(TRUE);
} else {
args.push(x`{ ${ opts.map(opt =>
opt === 'nonpassive'
? p`passive: false`
: p`${opt}: true`
) } }`);
}
} else if (block.renderer.options.dev) {
args.push(FALSE);
}

@ -6,6 +6,7 @@ import EachBlock from './EachBlock';
import Element from './Element/index';
import Head from './Head';
import IfBlock from './IfBlock';
import KeyBlock from './KeyBlock';
import InlineComponent from './InlineComponent/index';
import MustacheTag from './MustacheTag';
import RawMustacheTag from './RawMustacheTag';
@ -30,6 +31,7 @@ const wrappers = {
Head,
IfBlock,
InlineComponent,
KeyBlock,
MustacheTag,
Options: null,
RawMustacheTag,

@ -0,0 +1,136 @@
import Wrapper from "./shared/Wrapper";
import Renderer from "../Renderer";
import Block from "../Block";
import EachBlock from "../../nodes/EachBlock";
import KeyBlock from "../../nodes/KeyBlock";
import create_debugging_comment from "./shared/create_debugging_comment";
import FragmentWrapper from "./Fragment";
import { b, x } from "code-red";
import { Identifier } from "estree";
export default class KeyBlockWrapper extends Wrapper {
node: KeyBlock;
fragment: FragmentWrapper;
block: Block;
dependencies: string[];
var: Identifier = { type: "Identifier", name: "key_block" };
constructor(
renderer: Renderer,
block: Block,
parent: Wrapper,
node: EachBlock,
strip_whitespace: boolean,
next_sibling: Wrapper
) {
super(renderer, block, parent, node);
this.cannot_use_innerhtml();
this.not_static_content();
this.dependencies = node.expression.dynamic_dependencies();
if (this.dependencies.length) {
block = block.child({
comment: create_debugging_comment(node, renderer.component),
name: renderer.component.get_unique_name("create_key_block"),
type: "key"
});
renderer.blocks.push(block);
}
this.block = block;
this.fragment = new FragmentWrapper(
renderer,
this.block,
node.children,
parent,
strip_whitespace,
next_sibling
);
}
render(block: Block, parent_node: Identifier, parent_nodes: Identifier) {
if (this.dependencies.length === 0) {
this.render_static_key(block, parent_node, parent_nodes);
} else {
this.render_dynamic_key(block, parent_node, parent_nodes);
}
}
render_static_key(_block: Block, parent_node: Identifier, parent_nodes: Identifier) {
this.fragment.render(this.block, parent_node, parent_nodes);
}
render_dynamic_key(block: Block, parent_node: Identifier, parent_nodes: Identifier) {
this.fragment.render(
this.block,
null,
(x`#nodes` as unknown) as Identifier
);
const has_transitions = !!(
this.block.has_intro_method || this.block.has_outro_method
);
const dynamic = this.block.has_update_method;
const previous_key = block.get_unique_name('previous_key');
const snippet = this.node.expression.manipulate(block);
block.add_variable(previous_key, snippet);
const not_equal = this.renderer.component.component_options.immutable ? x`@not_equal` : x`@safe_not_equal`;
const condition = x`${this.renderer.dirty(this.dependencies)} && ${not_equal}(${previous_key}, ${previous_key} = ${snippet})`;
block.chunks.init.push(b`
let ${this.var} = ${this.block.name}(#ctx);
`);
block.chunks.create.push(b`${this.var}.c();`);
if (this.renderer.options.hydratable) {
block.chunks.claim.push(b`${this.var}.l(${parent_nodes});`);
}
block.chunks.mount.push(
b`${this.var}.m(${parent_node || "#target"}, ${
parent_node ? "null" : "#anchor"
});`
);
const anchor = this.get_or_create_anchor(block, parent_node, parent_nodes);
const body = b`
${
has_transitions
? b`
@group_outros();
@transition_out(${this.var}, 1, 1, @noop);
@check_outros();
`
: b`${this.var}.d(1);`
}
${this.var} = ${this.block.name}(#ctx);
${this.var}.c();
${has_transitions && b`@transition_in(${this.var})`}
${this.var}.m(${this.get_update_mount_node(anchor)}, ${anchor});
`;
if (dynamic) {
block.chunks.update.push(b`
if (${condition}) {
${body}
} else {
${this.var}.p(#ctx, #dirty);
}
`);
} else {
block.chunks.update.push(b`
if (${condition}) {
${body}
}
`);
}
if (has_transitions) {
block.chunks.intro.push(b`@transition_in(${this.var})`);
block.chunks.outro.push(b`@transition_out(${this.var})`);
}
block.chunks.destroy.push(b`${this.var}.d(detaching)`);
}
}

@ -7,6 +7,7 @@ import Head from './handlers/Head';
import HtmlTag from './handlers/HtmlTag';
import IfBlock from './handlers/IfBlock';
import InlineComponent from './handlers/InlineComponent';
import KeyBlock from './handlers/KeyBlock';
import Slot from './handlers/Slot';
import Tag from './handlers/Tag';
import Text from './handlers/Text';
@ -30,6 +31,7 @@ const handlers: Record<string, Handler> = {
Head,
IfBlock,
InlineComponent,
KeyBlock,
MustacheTag: Tag, // TODO MustacheTag is an anachronism
Options: noop,
RawMustacheTag: HtmlTag,

@ -0,0 +1,6 @@
import KeyBlock from '../../nodes/KeyBlock';
import Renderer, { RenderOptions } from '../Renderer';
export default function(node: KeyBlock, renderer: Renderer, options: RenderOptions) {
renderer.render(node.children, options);
}

@ -38,7 +38,7 @@ export default function mustache(parser: Parser) {
parser.allow_whitespace();
// {/if}, {/each} or {/await}
// {/if}, {/each}, {/await} or {/key}
if (parser.eat('/')) {
let block = parser.current();
let expected;
@ -63,6 +63,8 @@ export default function mustache(parser: Parser) {
expected = 'each';
} else if (block.type === 'AwaitBlock') {
expected = 'await';
} else if (block.type === 'KeyBlock') {
expected = 'key';
} else {
parser.error({
code: `unexpected-block-close`,
@ -221,10 +223,12 @@ export default function mustache(parser: Parser) {
type = 'EachBlock';
} else if (parser.eat('await')) {
type = 'AwaitBlock';
} else if (parser.eat('key')) {
type = 'KeyBlock';
} else {
parser.error({
code: `expected-block-type`,
message: `Expected if, each or await`
message: `Expected if, each, await or key`
});
}

@ -18,6 +18,7 @@ export const globals = new Set([
'Error',
'EvalError',
'Event',
'EventSource',
'fetch',
'global',
'globalThis',

@ -0,0 +1 @@
.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}.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}

@ -0,0 +1,4 @@
<div class="a svelte-xyz"></div>
<div class="d svelte-xyz"></div>
<div class="f svelte-xyz"></div>
<div class="h svelte-xyz"></div>

@ -0,0 +1,41 @@
<script>
let promise = Promise.resolve();
</script>
<style>
.a ~ .b { color: green; }
.a ~ .c { color: green; }
.a ~ .d { color: green; }
.a ~ .e { color: green; }
.a ~ .f { color: green; }
.a ~ .g { color: green; }
.a ~ .h { color: green; }
.b ~ .d { color: green; }
.c ~ .d { color: green; }
.b ~ .e ~ .f ~ .h { color: green; }
.b ~ .d ~ .h { color: green; }
.c ~ .g { color: green; }
</style>
<div class="a" />
{#await promise then value}
<div class="b" />
{:catch error}
<div class="c" />
{/await}
{#await promise}
<div class="d" />
{:catch error}
<div class="e" />
{/await}
{#await promise}
<div class="f" />
{:then error}
<div class="g" />
{/await}
<div class="h" />

@ -0,0 +1,46 @@
export default {
warnings: [
{
code: "css-unused-selector",
frame: `
13:
14: /* no match */
15: .b ~ .c { color: green; }
^
16: .c ~ .d { color: green; }
17: .b ~ .d { color: green; }`,
message: 'Unused CSS selector ".b ~ .c"',
pos: 269,
start: { character: 269, column: 1, line: 15 },
end: { character: 276, column: 8, line: 15 }
},
{
code: "css-unused-selector",
frame: `
14: /* no match */
15: .b ~ .c { color: green; }
16: .c ~ .d { color: green; }
^
17: .b ~ .d { color: green; }
18: </style>`,
message: 'Unused CSS selector ".c ~ .d"',
pos: 296,
start: { character: 296, column: 1, line: 16 },
end: { character: 303, column: 8, line: 16 }
},
{
code: "css-unused-selector",
frame: `
15: .b ~ .c { color: green; }
16: .c ~ .d { color: green; }
17: .b ~ .d { color: green; }
^
18: </style>
19:`,
message: 'Unused CSS selector ".b ~ .d"',
pos: 323,
start: { character: 323, column: 1, line: 17 },
end: { character: 330, column: 8, line: 17 }
}
]
};

@ -0,0 +1 @@
.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}

@ -0,0 +1,3 @@
<div class="a svelte-xyz"></div>
<div class="b svelte-xyz"></div>
<div class="e svelte-xyz"></div>

@ -0,0 +1,30 @@
<script>
let promise = Promise.resolve();
</script>
<style>
.a ~ .b { color: green; }
.a ~ .c { color: green; }
.a ~ .d { color: green; }
.b ~ .e { color: green; }
.c ~ .e { color: green; }
.d ~ .e { color: green; }
.a ~ .e { color: green; }
/* no match */
.b ~ .c { color: green; }
.c ~ .d { color: green; }
.b ~ .d { color: green; }
</style>
<div class="a" />
{#await promise}
<div class="b" />
{:then value}
<div class="c" />
{:catch error}
<div class="d" />
{/await}
<div class="e" />

@ -0,0 +1 @@
.a.svelte-xyz~.b.svelte-xyz{color:green}.c.svelte-xyz~.d.svelte-xyz{color:green}.a.svelte-xyz~.d.svelte-xyz{color:green}.c.svelte-xyz~.b.svelte-xyz{color:green}.b.svelte-xyz~.c.svelte-xyz{color:green}.a.svelte-xyz~.c.svelte-xyz{color:green}

@ -0,0 +1,4 @@
<div class="a svelte-xyz"></div>
<div class="b svelte-xyz"></div>
<div class="c svelte-xyz"></div>
<div class="d svelte-xyz"></div>

@ -0,0 +1,37 @@
<script>
let array = [1];
</script>
<style>
/* boundary of each */
.a ~ .b {
color: green;
}
.c ~ .d {
color: green;
}
/* if array is empty */
.a ~ .d {
color: green;
}
/* if array has multiple items */
.c ~ .b {
color: green;
}
/* normal sibling */
.b ~ .c {
color: green;
}
.a ~ .c {
color: green;
}
</style>
<div class="a" />
{#each array as item}
<div class="b" />
<div class="c" />
{/each}
<div class="d" />

@ -0,0 +1,18 @@
export default {
warnings: [
{
code: "css-unused-selector",
frame: `
33:
34: /* no match */
35: .e ~ .f { color: green; }
^
36: </style>
37:`,
message: 'Unused CSS selector ".e ~ .f"',
pos: 812,
start: { character: 812, column: 1, line: 35 },
end: { character: 819, column: 8, line: 35 }
}
]
};

@ -0,0 +1 @@
.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}

@ -0,0 +1,3 @@
<div class="a svelte-xyz"></div>
<div class="f svelte-xyz"></div>
<div class="k svelte-xyz"></div>

@ -0,0 +1,77 @@
<script>
let array = [];
</script>
<style>
.a ~ .e { color: green; }
.a ~ .f { color: green; }
.b ~ .c { color: green; }
.b ~ .d { color: green; }
.c ~ .e { color: green; }
.c ~ .f { color: green; }
.d ~ .e { color: green; }
.d ~ .f { color: green; }
.e ~ .e { color: green; }
.i ~ .j { color: green; }
.g ~ .h ~ .j { color: green; }
.g ~ .i ~ .j { color: green; }
.m ~ .m { color: green; }
.m ~ .l { color: green; }
.l ~ .m { color: green; }
.a ~ .c { color: green; }
.a ~ .g { color: green; }
.b ~ .e { color: green; }
.c ~ .g { color: green; }
.c ~ .k { color: green; }
.d ~ .d { color: green; }
.g ~ .g { color: green; }
.h ~ .h { color: green; }
.i ~ .i { color: green; }
.j ~ .j { color: green; }
.g ~ .j { color: green; }
.g ~ .h ~ .i ~ .j { color: green; }
/* no match */
.e ~ .f { color: green; }
</style>
<div class="a" />
{#each array as a}
<div class="b" />
{#each array as b}
<div class="c" />
{:else}
<div class="d" />
{/each}
{/each}
{#each array as c}
{#each array as d}
<div class="e" />
{/each}
{:else}
<div class="f" />
{/each}
{#each array as x}
<div class="g" />
{#each array as y}
{#each array as z}
<div class="h" />
{/each}
{:else}
<div class="i" />
{/each}
<div class="j" />
{/each}
<div class="k" />
{#each array as item}
{#each array as item}
<div class="l" />
{:else}
<div class="m" />
{/each}
{/each}

@ -0,0 +1,18 @@
export default {
warnings: [
{
code: "css-unused-selector",
frame: `
11:
12: /* no match */
13: .b ~ .c { color: green; }
^
14: </style>
15:`,
message: 'Unused CSS selector ".b ~ .c"',
pos: 199,
start: { character: 199, column: 1, line: 13 },
end: { character: 206, column: 8, line: 13 }
}
]
};

@ -0,0 +1 @@
.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}

@ -0,0 +1,3 @@
<div class="a svelte-xyz"></div>
<div class="c svelte-xyz"></div>
<div class="d svelte-xyz"></div>

@ -0,0 +1,24 @@
<script>
let array = [];
</script>
<style>
.a ~ .b { color: green; }
.a ~ .c { color: green; }
.b ~ .d { color: green; }
.c ~ .d { color: green; }
.a ~ .d { color: green; }
/* no match */
.b ~ .c { color: green; }
</style>
<div class="a" />
{#each array as item}
<div class="b" />
{:else}
<div class="c" />
{/each}
<div class="d" />

@ -0,0 +1 @@
.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}.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}.d.svelte-xyz~.e.svelte-xyz.svelte-xyz{color:green}.e.svelte-xyz~.f.svelte-xyz.svelte-xyz{color:green}.g.svelte-xyz~.h.svelte-xyz.svelte-xyz{color:green}.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}.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}.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}.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}.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}

@ -0,0 +1,15 @@
<div class="a svelte-xyz"></div>
<div class="b"></div>
<div class="c svelte-xyz"></div>
<div class="d svelte-xyz"></div>
<div class="e svelte-xyz"></div>
<div class="f svelte-xyz"></div>
<div class="g svelte-xyz"></div>
<div class="h svelte-xyz"></div>
<div class="i svelte-xyz"></div>
<div class="j svelte-xyz"></div>
<div class="k svelte-xyz"></div>
<div class="l svelte-xyz"></div>
<div class="m svelte-xyz"></div>
<div class="n svelte-xyz"></div>
<div class="o svelte-xyz"></div>

@ -0,0 +1,113 @@
<script>
let array = [1];
</script>
<style>
/* boundary of each */
.a ~ .d { color: green; }
.a ~ .e { color: green; }
.a ~ .f { color: green; }
.a ~ .g { color: green; }
.c ~ .d { color: green; }
.c ~ .e { color: green; }
.c ~ .f { color: green; }
.c ~ .g { color: green; }
/* nested boundary of each */
.j ~ .m { color: green; }
.j ~ .n { color: green; }
.j ~ .o { color: green; }
.k ~ .m { color: green; }
.k ~ .n { color: green; }
.k ~ .o { color: green; }
.l ~ .m { color: green; }
.l ~ .n { color: green; }
.l ~ .o { color: green; }
/* parent each */
.d ~ .e { color: green; }
.e ~ .f { color: green; }
/* child each */
.g ~ .h { color: green; }
/* wrap around */
.f ~ .d { color: green; }
.f ~ .e { color: green; }
.f ~ .f { color: green; }
.h ~ .g { color: green; }
.i ~ .h { color: green; }
.i ~ .g { color: green; }
/* wrap around self */
.d ~ .d { color: green; }
.e ~ .e { color: green; }
.f ~ .f { color: green; }
.g ~ .g { color: green; }
.h ~ .h { color: green; }
.i ~ .i { color: green; }
/* wrap around self ~ next */
.e ~ .e ~ .f { color: green; }
.e ~ .e ~ .d { color: green; }
.h ~ .h ~ .i { color: green; }
.h ~ .h ~ .g { color: green; }
/* general siblings */
.a ~ .h { color: green; }
.a ~ .i { color: green; }
.c ~ .h { color: green; }
.c ~ .i { color: green; }
.d ~ .f { color: green; }
.d ~ .g { color: green; }
.e ~ .g { color: green; }
.g ~ .i { color: green; }
</style>
<div class="a" />
{#each array as item}
<div class="b" />
<div class="c" />
{/each}
{#each array as item}
{#each array as item}
{#each array as item}
<div class="d" />
{/each}
<div class="e" />
{/each}
<div class="f" />
{/each}
{#each array as item}
<div class="g" />
{#each array as item}
<div class="h" />
{#each array as item}
<div class="i" />
{/each}
{/each}
{/each}
{#each array as item}
<div class="j" />
{#each array as item}
<div class="k" />
{#each array as item}
<div class="l" />
{/each}
{/each}
{/each}
{#each array as item}
{#each array as item}
{#each array as item}
<div class="m" />
{/each}
<div class="n" />
{/each}
<div class="o" />
{/each}

@ -0,0 +1 @@
div.svelte-xyz~span.svelte-xyz{color:green}

@ -0,0 +1,6 @@
<div class="svelte-xyz"></div>
<span class="each svelte-xyz"></span>
<div class="each svelte-xyz"></div>
<span class="each svelte-xyz"></span>
<div class="each svelte-xyz"></div>
<span class="svelte-xyz"></span>

@ -0,0 +1,20 @@
<script>
let array = [1];
</script>
<style>
div ~ span {
color: green;
}
</style>
<div />
{#each array as item}
<span class="each" />
<div class="each" />
<span class="each" />
<div class="each" />
{/each}
<span />

@ -0,0 +1,18 @@
export default {
warnings: [
{
code: "css-unused-selector",
frame: `
16:
17: /* no match */
18: .b ~ .c { color: green; }
^
19: </style>
20:`,
message: 'Unused CSS selector ".b ~ .c"',
pos: 319,
start: { character: 319, column: 1, line: 18 },
end: { character: 326, column: 8, line: 18 }
}
]
};

@ -0,0 +1 @@
.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~.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}

@ -0,0 +1,3 @@
<div class="a svelte-xyz"></div>
<div class="c svelte-xyz"></div>
<div class="d svelte-xyz"></div>

@ -0,0 +1,31 @@
<script>
let foo = false;
let array = [1];
</script>
<style>
.a ~ .b { color: green; }
.a ~ .c { color: green; }
.a ~ .d { color: green; }
.b ~ .d { color: green; }
.c ~ .d { color: green; }
.a ~ .c ~ .c { color: green; }
.c ~ .c ~ .d { color: green; }
.a ~ .c ~ .c ~ .d { color: green; }
/* no match */
.b ~ .c { color: green; }
</style>
<div class="a" />
{#if foo}
<div class="b" />
{:else}
{#each array as item}
<div class="c" />
{/each}
{/if}
<div class="d" />

@ -0,0 +1,18 @@
export default {
warnings: [
{
code: "css-unused-selector",
frame: `
12:
13: /* no match */
14: .b ~ .c { color: green; }
^
15: </style>
16:`,
message: 'Unused CSS selector ".b ~ .c"',
pos: 215,
start: { character: 215, column: 1, line: 14 },
end: { character: 222, column: 8, line: 14 }
}
]
};

@ -0,0 +1 @@
.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}

@ -0,0 +1,3 @@
<div class="a svelte-xyz"></div>
<div class="b svelte-xyz"></div>
<div class="d svelte-xyz"></div>

@ -0,0 +1,25 @@
<script>
let foo = true;
let bar = true;
</script>
<style>
.a ~ .b { color: green; }
.a ~ .c { color: green; }
.a ~ .d { color: green; }
.b ~ .d { color: green; }
.c ~ .d { color: green; }
/* no match */
.b ~ .c { color: green; }
</style>
<div class="a" />
{#if foo}
<div class="b" />
{:else if bar}
<div class="c" />
{/if}
<div class="d" />

@ -0,0 +1,46 @@
export default {
warnings: [
{
code: "css-unused-selector",
frame: `
14:
15: /* no match */
16: .b ~ .c { color: green; }
^
17: .b ~ .d { color: green; }
18: .c ~ .d { color: green; }`,
message: 'Unused CSS selector ".b ~ .c"',
pos: 269,
start: { character: 269, column: 1, line: 16 },
end: { character: 276, column: 8, line: 16 }
},
{
code: "css-unused-selector",
frame: `
15: /* no match */
16: .b ~ .c { color: green; }
17: .b ~ .d { color: green; }
^
18: .c ~ .d { color: green; }
19: </style>`,
message: 'Unused CSS selector ".b ~ .d"',
pos: 296,
start: { character: 296, column: 1, line: 17 },
end: { character: 303, column: 8, line: 17 }
},
{
code: "css-unused-selector",
frame: `
16: .b ~ .c { color: green; }
17: .b ~ .d { color: green; }
18: .c ~ .d { color: green; }
^
19: </style>
20:`,
message: 'Unused CSS selector ".c ~ .d"',
pos: 323,
start: { character: 323, column: 1, line: 18 },
end: { character: 330, column: 8, line: 18 }
}
]
};

@ -0,0 +1 @@
.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}

@ -0,0 +1,3 @@
<div class="a svelte-xyz"></div>
<div class="b svelte-xyz"></div>
<div class="e svelte-xyz"></div>

@ -0,0 +1,31 @@
<script>
let foo = true;
let bar = true;
</script>
<style>
.a ~ .b { color: green; }
.a ~ .c { color: green; }
.a ~ .d { color: green; }
.b ~ .e { color: green; }
.c ~ .e { color: green; }
.d ~ .e { color: green; }
.a ~ .e { color: green; }
/* no match */
.b ~ .c { color: green; }
.b ~ .d { color: green; }
.c ~ .d { color: green; }
</style>
<div class="a" />
{#if foo}
<div class="b" />
{:else if bar}
<div class="c" />
{:else}
<div class="d" />
{/if}
<div class="e" />

@ -0,0 +1,88 @@
export default {
warnings: [
{
code: "css-unused-selector",
frame: `
8:
9: /* no match */
10: .a ~ .b { color: green; }
^
11: .b ~ .c { color: green; }
12: .c ~ .f { color: green; }`,
message: 'Unused CSS selector ".a ~ .b"',
pos: 111,
start: { character: 111, column: 1, line: 10 },
end: { character: 118, column: 8, line: 10 }
},
{
code: "css-unused-selector",
frame: `
9: /* no match */
10: .a ~ .b { color: green; }
11: .b ~ .c { color: green; }
^
12: .c ~ .f { color: green; }
13: .f ~ .g { color: green; }`,
message: 'Unused CSS selector ".b ~ .c"',
pos: 138,
start: { character: 138, column: 1, line: 11 },
end: { character: 145, column: 8, line: 11 }
},
{
code: "css-unused-selector",
frame: `
10: .a ~ .b { color: green; }
11: .b ~ .c { color: green; }
12: .c ~ .f { color: green; }
^
13: .f ~ .g { color: green; }
14: .b ~ .f { color: green; }`,
message: 'Unused CSS selector ".c ~ .f"',
pos: 165,
start: { character: 165, column: 1, line: 12 },
end: { character: 172, column: 8, line: 12 }
},
{
code: "css-unused-selector",
frame: `
11: .b ~ .c { color: green; }
12: .c ~ .f { color: green; }
13: .f ~ .g { color: green; }
^
14: .b ~ .f { color: green; }
15: .b ~ .g { color: green; }`,
message: 'Unused CSS selector ".f ~ .g"',
pos: 192,
start: { character: 192, column: 1, line: 13 },
end: { character: 199, column: 8, line: 13 }
},
{
code: "css-unused-selector",
frame: `
12: .c ~ .f { color: green; }
13: .f ~ .g { color: green; }
14: .b ~ .f { color: green; }
^
15: .b ~ .g { color: green; }
16: </style>`,
message: 'Unused CSS selector ".b ~ .f"',
pos: 219,
start: { character: 219, column: 1, line: 14 },
end: { character: 226, column: 8, line: 14 }
},
{
code: "css-unused-selector",
frame: `
13: .f ~ .g { color: green; }
14: .b ~ .f { color: green; }
15: .b ~ .g { color: green; }
^
16: </style>
17:`,
message: 'Unused CSS selector ".b ~ .g"',
pos: 246,
start: { character: 246, column: 1, line: 15 },
end: { character: 253, column: 8, line: 15 }
}
]
};

@ -0,0 +1 @@
.d.svelte-xyz~.e.svelte-xyz{color:green}.a.svelte-xyz~.g.svelte-xyz{color:green}

@ -0,0 +1,30 @@
<script>
let App;
</script>
<style>
.d ~ .e { color: green; }
.a ~ .g { color: green; }
/* no match */
.a ~ .b { color: green; }
.b ~ .c { color: green; }
.c ~ .f { color: green; }
.f ~ .g { color: green; }
.b ~ .f { color: green; }
.b ~ .g { color: green; }
</style>
<div class="a" />
<App>
<div class="b" slot="a" />
<div class="c" slot="b">
<div class="d" />
<div class="e" />
</div>
<div class="f" slot="c" />
</App>
<div class="g" />

@ -0,0 +1,18 @@
export default {
warnings: [
{
code: "css-unused-selector",
frame: `
3: margin-left: 4px;
4: }
5: .not-match > * ~ * {
^
6: margin-left: 4px;
7: }`,
message: 'Unused CSS selector ".not-match > * ~ *"',
pos: 50,
start: { character: 50, column: 1, line: 5 },
end: { character: 68, column: 19, line: 5 }
}
]
};

@ -0,0 +1 @@
.match.svelte-xyz>.svelte-xyz~.svelte-xyz{margin-left:4px}

@ -0,0 +1,7 @@
<div class="not-match">
<div></div>
</div>
<div class="match svelte-xyz">
<div class="svelte-xyz"></div>
<div class="svelte-xyz"></div>
</div>

@ -0,0 +1,17 @@
<style>
.match > * ~ * {
margin-left: 4px;
}
.not-match > * ~ * {
margin-left: 4px;
}
</style>
<div class="not-match">
<div />
</div>
<div class="match">
<div />
<div />
</div>

@ -0,0 +1,60 @@
export default {
warnings: [
{
code: "css-unused-selector",
frame: `
10:
11: /* no match */
12: article ~ div { color: green; }
^
13: span ~ article { color: green; }
14: b ~ article { color: green; }`,
message: 'Unused CSS selector "article ~ div"',
pos: 275,
start: { character: 275, column: 1, line: 12 },
end: { character: 288, column: 14, line: 12 }
},
{
code: "css-unused-selector",
frame: `
11: /* no match */
12: article ~ div { color: green; }
13: span ~ article { color: green; }
^
14: b ~ article { color: green; }
15: span ~ div { color: green; }`,
message: 'Unused CSS selector "span ~ article"',
pos: 308,
start: { character: 308, column: 1, line: 13 },
end: { character: 322, column: 15, line: 13 }
},
{
code: "css-unused-selector",
frame: `
12: article ~ div { color: green; }
13: span ~ article { color: green; }
14: b ~ article { color: green; }
^
15: span ~ div { color: green; }
16: </style>`,
message: 'Unused CSS selector "b ~ article"',
pos: 342,
start: { character: 342, column: 1, line: 14 },
end: { character: 353, column: 12, line: 14 }
},
{
code: "css-unused-selector",
frame: `
13: span ~ article { color: green; }
14: b ~ article { color: green; }
15: span ~ div { color: green; }
^
16: </style>
17:`,
message: 'Unused CSS selector "span ~ div"',
pos: 373,
start: { character: 373, column: 1, line: 15 },
end: { character: 383, column: 11, line: 15 }
}
]
};

@ -0,0 +1 @@
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}

@ -0,0 +1,7 @@
<div class="a svelte-xyz">
<span class="svelte-xyz"></span>
<b class="svelte-xyz"></b>
</div>
<article class="b svelte-xyz"></article>
<p class="c svelte-xyz"></p>
<details class="d svelte-xyz"></details>

@ -0,0 +1,24 @@
<style>
div ~ article { color: green; }
span ~ b { color: green; }
div span ~ b { color: green; }
.a ~ article { color: green; }
div ~ .b { color: green; }
.a ~ .c { color: green; }
article ~ details { color: green; }
.a ~ details { color: green; }
/* no match */
article ~ div { color: green; }
span ~ article { color: green; }
b ~ article { color: green; }
span ~ div { color: green; }
</style>
<div class="a">
<span />
<b />
</div>
<article class="b"></article>
<p class="c"></p>
<details class="d"></details>

@ -0,0 +1 @@
.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}.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}

@ -0,0 +1,4 @@
<div class="a svelte-xyz"></div>
<div class="d svelte-xyz"></div>
<div class="f svelte-xyz"></div>
<div class="h svelte-xyz"></div>

@ -0,0 +1,41 @@
<script>
let promise = Promise.resolve();
</script>
<style>
.a + .b { color: green; }
.a + .c { color: green; }
.a + .d { color: green; }
.a + .e { color: green; }
.a + .f { color: green; }
.a + .g { color: green; }
.a + .h { color: green; }
.b + .d { color: green; }
.c + .d { color: green; }
.b + .e + .f + .h { color: green; }
.b + .d + .h { color: green; }
.c + .g { color: green; }
</style>
<div class="a" />
{#await promise then value}
<div class="b" />
{:catch error}
<div class="c" />
{/await}
{#await promise}
<div class="d" />
{:catch error}
<div class="e" />
{/await}
{#await promise}
<div class="f" />
{:then error}
<div class="g" />
{/await}
<div class="h" />

@ -0,0 +1,60 @@
export default {
warnings: [
{
code: "css-unused-selector",
frame: `
12:
13: /* no match */
14: .a + .e { color: green; }
^
15: .b + .c { color: green; }
16: .c + .d { color: green; }`,
message: 'Unused CSS selector ".a + .e"',
pos: 242,
start: { character: 242, column: 1, line: 14 },
end: { character: 249, column: 8, line: 14 }
},
{
code: "css-unused-selector",
frame: `
13: /* no match */
14: .a + .e { color: green; }
15: .b + .c { color: green; }
^
16: .c + .d { color: green; }
17: .b + .d { color: green; }`,
message: 'Unused CSS selector ".b + .c"',
pos: 269,
start: { character: 269, column: 1, line: 15 },
end: { character: 276, column: 8, line: 15 }
},
{
code: "css-unused-selector",
frame: `
14: .a + .e { color: green; }
15: .b + .c { color: green; }
16: .c + .d { color: green; }
^
17: .b + .d { color: green; }
18: </style>`,
message: 'Unused CSS selector ".c + .d"',
pos: 296,
start: { character: 296, column: 1, line: 16 },
end: { character: 303, column: 8, line: 16 }
},
{
code: "css-unused-selector",
frame: `
15: .b + .c { color: green; }
16: .c + .d { color: green; }
17: .b + .d { color: green; }
^
18: </style>
19:`,
message: 'Unused CSS selector ".b + .d"',
pos: 323,
start: { character: 323, column: 1, line: 17 },
end: { character: 330, column: 8, line: 17 }
}
]
};

@ -0,0 +1 @@
.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}

@ -0,0 +1,3 @@
<div class="a svelte-xyz"></div>
<div class="b svelte-xyz"></div>
<div class="e svelte-xyz"></div>

@ -0,0 +1,30 @@
<script>
let promise = Promise.resolve();
</script>
<style>
.a + .b { color: green; }
.a + .c { color: green; }
.a + .d { color: green; }
.b + .e { color: green; }
.c + .e { color: green; }
.d + .e { color: green; }
/* no match */
.a + .e { color: green; }
.b + .c { color: green; }
.c + .d { color: green; }
.b + .d { color: green; }
</style>
<div class="a" />
{#await promise}
<div class="b" />
{:then value}
<div class="c" />
{:catch error}
<div class="d" />
{/await}
<div class="e" />

@ -0,0 +1,18 @@
export default {
warnings: [
{
code: "css-unused-selector",
frame: `
24: }
25: /* not match */
26: .a + .c {
^
27: color: green;
28: }`,
message: 'Unused CSS selector ".a + .c"',
pos: 320,
start: { character: 320, column: 1, line: 26 },
end: { character: 327, column: 8, line: 26 }
}
]
};

@ -0,0 +1 @@
.a.svelte-xyz+.b.svelte-xyz{color:green}.c.svelte-xyz+.d.svelte-xyz{color:green}.a.svelte-xyz+.d.svelte-xyz{color:green}.c.svelte-xyz+.b.svelte-xyz{color:green}.b.svelte-xyz+.c.svelte-xyz{color:green}

@ -0,0 +1,4 @@
<div class="a svelte-xyz"></div>
<div class="b svelte-xyz"></div>
<div class="c svelte-xyz"></div>
<div class="d svelte-xyz"></div>

@ -0,0 +1,38 @@
<script>
let array = [1];
</script>
<style>
/* boundary of each */
.a + .b {
color: green;
}
.c + .d {
color: green;
}
/* if array is empty */
.a + .d {
color: green;
}
/* if array has multiple items */
.c + .b {
color: green;
}
/* normal sibling */
.b + .c {
color: green;
}
/* not match */
.a + .c {
color: green;
}
</style>
<div class="a" />
{#each array as item}
<div class="b" />
<div class="c" />
{/each}
<div class="d" />

@ -0,0 +1,144 @@
export default {
warnings: [
{
code: "css-unused-selector",
frame: `
21:
22: /* no match */
23: .a + .c { color: green; }
^
24: .a + .g { color: green; }
25: .b + .e { color: green; }`,
message: 'Unused CSS selector ".a + .c"',
pos: 479,
start: { character: 479, column: 1, line: 23 },
end: { character: 486, column: 8, line: 23 }
},
{
code: "css-unused-selector",
frame: `
22: /* no match */
23: .a + .c { color: green; }
24: .a + .g { color: green; }
^
25: .b + .e { color: green; }
26: .c + .g { color: green; }`,
message: 'Unused CSS selector ".a + .g"',
pos: 506,
start: { character: 506, column: 1, line: 24 },
end: { character: 513, column: 8, line: 24 }
},
{
code: "css-unused-selector",
frame: `
23: .a + .c { color: green; }
24: .a + .g { color: green; }
25: .b + .e { color: green; }
^
26: .c + .g { color: green; }
27: .c + .k { color: green; }`,
message: 'Unused CSS selector ".b + .e"',
pos: 533,
start: { character: 533, column: 1, line: 25 },
end: { character: 540, column: 8, line: 25 }
},
{
code: "css-unused-selector",
frame: `
24: .a + .g { color: green; }
25: .b + .e { color: green; }
26: .c + .g { color: green; }
^
27: .c + .k { color: green; }
28: .d + .d { color: green; }`,
message: 'Unused CSS selector ".c + .g"',
pos: 560,
start: { character: 560, column: 1, line: 26 },
end: { character: 567, column: 8, line: 26 }
},
{
code: "css-unused-selector",
frame: `
25: .b + .e { color: green; }
26: .c + .g { color: green; }
27: .c + .k { color: green; }
^
28: .d + .d { color: green; }
29: .e + .f { color: green; }`,
message: 'Unused CSS selector ".c + .k"',
pos: 587,
start: { character: 587, column: 1, line: 27 },
end: { character: 594, column: 8, line: 27 }
},
{
code: "css-unused-selector",
frame: `
26: .c + .g { color: green; }
27: .c + .k { color: green; }
28: .d + .d { color: green; }
^
29: .e + .f { color: green; }
30: .f + .f { color: green; }`,
message: 'Unused CSS selector ".d + .d"',
pos: 614,
start: { character: 614, column: 1, line: 28 },
end: { character: 621, column: 8, line: 28 }
},
{
code: "css-unused-selector",
frame: `
27: .c + .k { color: green; }
28: .d + .d { color: green; }
29: .e + .f { color: green; }
^
30: .f + .f { color: green; }
31: .g + .j { color: green; }`,
message: 'Unused CSS selector ".e + .f"',
pos: 641,
start: { character: 641, column: 1, line: 29 },
end: { character: 648, column: 8, line: 29 }
},
{
code: "css-unused-selector",
frame: `
28: .d + .d { color: green; }
29: .e + .f { color: green; }
30: .f + .f { color: green; }
^
31: .g + .j { color: green; }
32: .g + .h + .i + .j { color: green; }`,
message: 'Unused CSS selector ".f + .f"',
pos: 668,
start: { character: 668, column: 1, line: 30 },
end: { character: 675, column: 8, line: 30 }
},
{
code: "css-unused-selector",
frame: `
29: .e + .f { color: green; }
30: .f + .f { color: green; }
31: .g + .j { color: green; }
^
32: .g + .h + .i + .j { color: green; }
33: </style>`,
message: 'Unused CSS selector ".g + .j"',
pos: 695,
start: { character: 695, column: 1, line: 31 },
end: { character: 702, column: 8, line: 31 }
},
{
code: "css-unused-selector",
frame: `
30: .f + .f { color: green; }
31: .g + .j { color: green; }
32: .g + .h + .i + .j { color: green; }
^
33: </style>
34:`,
message: 'Unused CSS selector ".g + .h + .i + .j"',
pos: 722,
start: { character: 722, column: 1, line: 32 },
end: { character: 739, column: 18, line: 32 }
}
]
};

@ -0,0 +1 @@
.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}

@ -0,0 +1,3 @@
<div class="a svelte-xyz"></div>
<div class="f svelte-xyz"></div>
<div class="k"></div>

@ -0,0 +1,74 @@
<script>
let array = [];
</script>
<style>
.a + .e { color: green; }
.a + .f { color: green; }
.b + .c { color: green; }
.b + .d { color: green; }
.c + .e { color: green; }
.c + .f { color: green; }
.d + .e { color: green; }
.d + .f { color: green; }
.e + .e { color: green; }
.i + .j { color: green; }
.g + .h + .j { color: green; }
.g + .i + .j { color: green; }
.m + .m { color: green; }
.m + .l { color: green; }
.l + .m { color: green; }
/* no match */
.a + .c { color: green; }
.a + .g { color: green; }
.b + .e { color: green; }
.c + .g { color: green; }
.c + .k { color: green; }
.d + .d { color: green; }
.e + .f { color: green; }
.f + .f { color: green; }
.g + .j { color: green; }
.g + .h + .i + .j { color: green; }
</style>
<div class="a" />
{#each array as a}
<div class="b" />
{#each array as b}
<div class="c" />
{:else}
<div class="d" />
{/each}
{/each}
{#each array as c}
{#each array as d}
<div class="e" />
{/each}
{:else}
<div class="f" />
{/each}
{#each array as item}
<div class="g" />
{#each array as item}
{#each array as item}
<div class="h" />
{/each}
{:else}
<div class="i" />
{/each}
<div class="j" />
{/each}
<div class="k" />
{#each array as item}
{#each array as item}
<div class="l" />
{:else}
<div class="m" />
{/each}
{/each}

@ -0,0 +1,32 @@
export default {
warnings: [
{
code: "css-unused-selector",
frame: `
10:
11: /* no match */
12: .a + .d { color: green; }
^
13: .b + .c { color: green; }
14: </style>`,
message: 'Unused CSS selector ".a + .d"',
pos: 172,
start: { character: 172, column: 1, line: 12 },
end: { character: 179, column: 8, line: 12 }
},
{
code: "css-unused-selector",
frame: `
11: /* no match */
12: .a + .d { color: green; }
13: .b + .c { color: green; }
^
14: </style>
15:`,
message: 'Unused CSS selector ".b + .c"',
pos: 199,
start: { character: 199, column: 1, line: 13 },
end: { character: 206, column: 8, line: 13 }
}
]
};

@ -0,0 +1 @@
.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}

@ -0,0 +1,3 @@
<div class="a svelte-xyz"></div>
<div class="c svelte-xyz"></div>
<div class="d svelte-xyz"></div>

@ -0,0 +1,24 @@
<script>
let array = [];
</script>
<style>
.a + .b { color: green; }
.a + .c { color: green; }
.b + .d { color: green; }
.c + .d { color: green; }
/* no match */
.a + .d { color: green; }
.b + .c { color: green; }
</style>
<div class="a" />
{#each array as item}
<div class="b" />
{:else}
<div class="c" />
{/each}
<div class="d" />

@ -0,0 +1,116 @@
export default {
warnings: [
{
code: "css-unused-selector",
frame: `
56:
57: /* no match */
58: .a + .h { color: green; }
^
59: .a + .i { color: green; }
60: .c + .h { color: green; }`,
message: 'Unused CSS selector ".a + .h"',
pos: 1229,
start: { character: 1229, column: 1, line: 58 },
end: { character: 1236, column: 8, line: 58 }
},
{
code: "css-unused-selector",
frame: `
57: /* no match */
58: .a + .h { color: green; }
59: .a + .i { color: green; }
^
60: .c + .h { color: green; }
61: .c + .i { color: green; }`,
message: 'Unused CSS selector ".a + .i"',
pos: 1256,
start: { character: 1256, column: 1, line: 59 },
end: { character: 1263, column: 8, line: 59 }
},
{
code: "css-unused-selector",
frame: `
58: .a + .h { color: green; }
59: .a + .i { color: green; }
60: .c + .h { color: green; }
^
61: .c + .i { color: green; }
62: .d + .f { color: green; }`,
message: 'Unused CSS selector ".c + .h"',
pos: 1283,
start: { character: 1283, column: 1, line: 60 },
end: { character: 1290, column: 8, line: 60 }
},
{
code: "css-unused-selector",
frame: `
59: .a + .i { color: green; }
60: .c + .h { color: green; }
61: .c + .i { color: green; }
^
62: .d + .f { color: green; }
63: .d + .g { color: green; }`,
message: 'Unused CSS selector ".c + .i"',
pos: 1310,
start: { character: 1310, column: 1, line: 61 },
end: { character: 1317, column: 8, line: 61 }
},
{
code: "css-unused-selector",
frame: `
60: .c + .h { color: green; }
61: .c + .i { color: green; }
62: .d + .f { color: green; }
^
63: .d + .g { color: green; }
64: .e + .g { color: green; }`,
message: 'Unused CSS selector ".d + .f"',
pos: 1337,
start: { character: 1337, column: 1, line: 62 },
end: { character: 1344, column: 8, line: 62 }
},
{
code: "css-unused-selector",
frame: `
61: .c + .i { color: green; }
62: .d + .f { color: green; }
63: .d + .g { color: green; }
^
64: .e + .g { color: green; }
65: .g + .i { color: green; }`,
message: 'Unused CSS selector ".d + .g"',
pos: 1364,
start: { character: 1364, column: 1, line: 63 },
end: { character: 1371, column: 8, line: 63 }
},
{
code: "css-unused-selector",
frame: `
62: .d + .f { color: green; }
63: .d + .g { color: green; }
64: .e + .g { color: green; }
^
65: .g + .i { color: green; }
66: </style>`,
message: 'Unused CSS selector ".e + .g"',
pos: 1391,
start: { character: 1391, column: 1, line: 64 },
end: { character: 1398, column: 8, line: 64 }
},
{
code: "css-unused-selector",
frame: `
63: .d + .g { color: green; }
64: .e + .g { color: green; }
65: .g + .i { color: green; }
^
66: </style>
67:`,
message: 'Unused CSS selector ".g + .i"',
pos: 1418,
start: { character: 1418, column: 1, line: 65 },
end: { character: 1425, column: 8, line: 65 }
}
]
};

@ -0,0 +1 @@
.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}.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}.d.svelte-xyz+.e.svelte-xyz.svelte-xyz{color:green}.e.svelte-xyz+.f.svelte-xyz.svelte-xyz{color:green}.g.svelte-xyz+.h.svelte-xyz.svelte-xyz{color:green}.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}.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}.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}.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}

@ -0,0 +1,15 @@
<div class="a svelte-xyz"></div>
<div class="b"></div>
<div class="c svelte-xyz"></div>
<div class="d svelte-xyz"></div>
<div class="e svelte-xyz"></div>
<div class="f svelte-xyz"></div>
<div class="g svelte-xyz"></div>
<div class="h svelte-xyz"></div>
<div class="i svelte-xyz"></div>
<div class="j svelte-xyz"></div>
<div class="k svelte-xyz"></div>
<div class="l svelte-xyz"></div>
<div class="m svelte-xyz"></div>
<div class="n svelte-xyz"></div>
<div class="o svelte-xyz"></div>

@ -0,0 +1,113 @@
<script>
let array = [1];
</script>
<style>
/* boundary of each */
.a + .d { color: green; }
.a + .e { color: green; }
.a + .f { color: green; }
.a + .g { color: green; }
.c + .d { color: green; }
.c + .e { color: green; }
.c + .f { color: green; }
.c + .g { color: green; }
/* nested boundary of each */
.j + .m { color: green; }
.j + .n { color: green; }
.j + .o { color: green; }
.k + .m { color: green; }
.k + .n { color: green; }
.k + .o { color: green; }
.l + .m { color: green; }
.l + .n { color: green; }
.l + .o { color: green; }
/* parent each */
.d + .e { color: green; }
.e + .f { color: green; }
/* child each */
.g + .h { color: green; }
/* wrap around */
.f + .d { color: green; }
.f + .e { color: green; }
.f + .f { color: green; }
.h + .g { color: green; }
.i + .h { color: green; }
.i + .g { color: green; }
/* wrap around self */
.d + .d { color: green; }
.e + .e { color: green; }
.f + .f { color: green; }
.g + .g { color: green; }
.h + .h { color: green; }
.i + .i { color: green; }
/* wrap around self + next */
.e + .e + .f { color: green; }
.e + .e + .d { color: green; }
.h + .h + .i { color: green; }
.h + .h + .g { color: green; }
/* no match */
.a + .h { color: green; }
.a + .i { color: green; }
.c + .h { color: green; }
.c + .i { color: green; }
.d + .f { color: green; }
.d + .g { color: green; }
.e + .g { color: green; }
.g + .i { color: green; }
</style>
<div class="a" />
{#each array as item}
<div class="b" />
<div class="c" />
{/each}
{#each array as item}
{#each array as item}
{#each array as item}
<div class="d" />
{/each}
<div class="e" />
{/each}
<div class="f" />
{/each}
{#each array as item}
<div class="g" />
{#each array as item}
<div class="h" />
{#each array as item}
<div class="i" />
{/each}
{/each}
{/each}
{#each array as item}
<div class="j" />
{#each array as item}
<div class="k" />
{#each array as item}
<div class="l" />
{/each}
{/each}
{/each}
{#each array as item}
{#each array as item}
{#each array as item}
<div class="m" />
{/each}
<div class="n" />
{/each}
<div class="o" />
{/each}

@ -0,0 +1 @@
div.svelte-xyz+span.svelte-xyz{color:green}

@ -0,0 +1,6 @@
<div class="svelte-xyz"></div>
<span class="each svelte-xyz"></span>
<div class="each svelte-xyz"></div>
<span class="each svelte-xyz"></span>
<div class="each svelte-xyz"></div>
<span class="svelte-xyz"></span>

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

Loading…
Cancel
Save