diff --git a/CHANGELOG.md b/CHANGELOG.md index ad33840527..106d091cee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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)) diff --git a/package-lock.json b/package-lock.json index 2e2a95b362..4d6b1f8b6a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "3.25.1", + "version": "3.28.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 7ebb41fdfb..7be5b19819 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "3.25.1", + "version": "3.28.0", "description": "Cybernetically enhanced web apps", "module": "index.mjs", "main": "index", diff --git a/site/content/blog/2019-04-15-setting-up-your-editor.md b/site/content/blog/2019-04-15-setting-up-your-editor.md index b80223d820..fb8287d0cb 100644 --- a/site/content/blog/2019-04-15-setting-up-your-editor.md +++ b/site/content/blog/2019-04-15-setting-up-your-editor.md @@ -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 diff --git a/site/content/docs/02-template-syntax.md b/site/content/docs/02-template-syntax.md index e93449728b..d955f650e2 100644 --- a/site/content/docs/02-template-syntax.md +++ b/site/content/docs/02-template-syntax.md @@ -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} +
{value}
+{/key} +``` + +--- + +When used around components, this will cause them to be reinstantiated and reinitialised. + +```sv +{#key value} + +{/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 diff --git a/site/content/tutorial/01-introduction/07-making-an-app/text.md b/site/content/tutorial/01-introduction/07-making-an-app/text.md index 4d044272b5..d75a9a626c 100644 --- a/site/content/tutorial/01-introduction/07-making-an-app/text.md +++ b/site/content/tutorial/01-introduction/07-making-an-app/text.md @@ -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`: diff --git a/site/content/tutorial/05-events/03-event-modifiers/text.md b/site/content/tutorial/05-events/03-event-modifiers/text.md index 41154cafcd..2b2d6e6b31 100644 --- a/site/content/tutorial/05-events/03-event-modifiers/text.md +++ b/site/content/tutorial/05-events/03-event-modifiers/text.md @@ -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 diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 078ecb8869..6c1fe89823 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -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 = 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); diff --git a/src/compiler/compile/css/Selector.ts b/src/compiler/compile/css/Selector.ts index c45cda57e9..46e9b4c4f0 100644 --- a/src/compiler/compile/css/Selector.ts +++ b/src/compiler/compile/css/Selector.ts @@ -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 { + const result: Map = 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 { + const result: Map = new Map(); + + if (block.type === 'EachBlock') { + const each_result: Map = loop_child(block.children, adjacent_only); + const else_result: Map = 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 = loop_child(block.children, adjacent_only); + const else_result: Map = 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 = block.pending ? loop_child(block.pending.children, adjacent_only) : new Map(); + const then_result: Map = block.then ? loop_child(block.then.children, adjacent_only) : new Map(); + const catch_result: Map = 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): 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, to: Map) { + 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) { + for (const key of result.keys()) { + result.set(key, NodeExist.Probably); + } +} + +function loop_child(children: INode[], adjacent_only: boolean) { + const result: Map = 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; diff --git a/src/compiler/compile/css/Stylesheet.ts b/src/compiler/compile/css/Stylesheet.ts index 27438947ff..dc464d7df8 100644 --- a/src/compiler/compile/css/Stylesheet.ts +++ b/src/compiler/compile/css/Stylesheet.ts @@ -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); } } diff --git a/src/compiler/compile/nodes/Action.ts b/src/compiler/compile/nodes/Action.ts index 86aefa0ced..dc6f080b71 100644 --- a/src/compiler/compile/nodes/Action.ts +++ b/src/compiler/compile/nodes/Action.ts @@ -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) diff --git a/src/compiler/compile/nodes/Element.ts b/src/compiler/compile/nodes/Element.ts index 6636c6b87b..7c9272e5d3 100644 --- a/src/compiler/compile/nodes/Element.ts +++ b/src/compiler/compile/nodes/Element.ts @@ -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'); } diff --git a/src/compiler/compile/nodes/KeyBlock.ts b/src/compiler/compile/nodes/KeyBlock.ts new file mode 100644 index 0000000000..356210b6b0 --- /dev/null +++ b/src/compiler/compile/nodes/KeyBlock.ts @@ -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(); + } +} diff --git a/src/compiler/compile/nodes/interfaces.ts b/src/compiler/compile/nodes/interfaces.ts index 752168a49d..51d7b17e07 100644 --- a/src/compiler/compile/nodes/interfaces.ts +++ b/src/compiler/compile/nodes/interfaces.ts @@ -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 diff --git a/src/compiler/compile/nodes/shared/map_children.ts b/src/compiler/compile/nodes/shared/map_children.ts index dcdc52f86d..5d5da223fb 100644 --- a/src/compiler/compile/nodes/shared/map_children.ts +++ b/src/compiler/compile/nodes/shared/map_children.ts @@ -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; diff --git a/src/compiler/compile/render_dom/invalidate.ts b/src/compiler/compile/render_dom/invalidate.ts index b045db079f..b891b48cb5 100644 --- a/src/compiler/compile/render_dom/invalidate.ts +++ b/src/compiler/compile/render_dom/invalidate.ts @@ -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; } \ No newline at end of file diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index 2513ea1adc..fe1c21a8df 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -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) { diff --git a/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts b/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts index 157e186ea6..2fa2e9291a 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts @@ -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); } diff --git a/src/compiler/compile/render_dom/wrappers/Fragment.ts b/src/compiler/compile/render_dom/wrappers/Fragment.ts index a0984b69b9..853a41f3cc 100644 --- a/src/compiler/compile/render_dom/wrappers/Fragment.ts +++ b/src/compiler/compile/render_dom/wrappers/Fragment.ts @@ -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, diff --git a/src/compiler/compile/render_dom/wrappers/KeyBlock.ts b/src/compiler/compile/render_dom/wrappers/KeyBlock.ts new file mode 100644 index 0000000000..359fb6946f --- /dev/null +++ b/src/compiler/compile/render_dom/wrappers/KeyBlock.ts @@ -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)`); + } +} diff --git a/src/compiler/compile/render_ssr/Renderer.ts b/src/compiler/compile/render_ssr/Renderer.ts index fb9216327c..c633ff8b0a 100644 --- a/src/compiler/compile/render_ssr/Renderer.ts +++ b/src/compiler/compile/render_ssr/Renderer.ts @@ -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 = { Head, IfBlock, InlineComponent, + KeyBlock, MustacheTag: Tag, // TODO MustacheTag is an anachronism Options: noop, RawMustacheTag: HtmlTag, diff --git a/src/compiler/compile/render_ssr/handlers/KeyBlock.ts b/src/compiler/compile/render_ssr/handlers/KeyBlock.ts new file mode 100644 index 0000000000..33a6681280 --- /dev/null +++ b/src/compiler/compile/render_ssr/handlers/KeyBlock.ts @@ -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); +} diff --git a/src/compiler/parse/state/mustache.ts b/src/compiler/parse/state/mustache.ts index dc26d994df..b72b77c30b 100644 --- a/src/compiler/parse/state/mustache.ts +++ b/src/compiler/parse/state/mustache.ts @@ -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` }); } diff --git a/src/compiler/utils/names.ts b/src/compiler/utils/names.ts index 1fa37660f4..7b6a6f55e0 100644 --- a/src/compiler/utils/names.ts +++ b/src/compiler/utils/names.ts @@ -18,6 +18,7 @@ export const globals = new Set([ 'Error', 'EvalError', 'Event', + 'EventSource', 'fetch', 'global', 'globalThis', diff --git a/test/css/samples/general-siblings-combinator-await-not-exhaustive/_config.js b/test/css/samples/general-siblings-combinator-await-not-exhaustive/_config.js new file mode 100644 index 0000000000..c81f1a9f82 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-await-not-exhaustive/_config.js @@ -0,0 +1,3 @@ +export default { + warnings: [] +}; diff --git a/test/css/samples/general-siblings-combinator-await-not-exhaustive/expected.css b/test/css/samples/general-siblings-combinator-await-not-exhaustive/expected.css new file mode 100644 index 0000000000..54eefc6088 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-await-not-exhaustive/expected.css @@ -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} \ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-await-not-exhaustive/expected.html b/test/css/samples/general-siblings-combinator-await-not-exhaustive/expected.html new file mode 100644 index 0000000000..de97b02a5e --- /dev/null +++ b/test/css/samples/general-siblings-combinator-await-not-exhaustive/expected.html @@ -0,0 +1,4 @@ +
+
+
+
\ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-await-not-exhaustive/input.svelte b/test/css/samples/general-siblings-combinator-await-not-exhaustive/input.svelte new file mode 100644 index 0000000000..a677077c33 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-await-not-exhaustive/input.svelte @@ -0,0 +1,41 @@ + + + + +
+ +{#await promise then value} +
+{:catch error} +
+{/await} + +{#await promise} +
+{:catch error} +
+{/await} + +{#await promise} +
+{:then error} +
+{/await} + +
\ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-await/_config.js b/test/css/samples/general-siblings-combinator-await/_config.js new file mode 100644 index 0000000000..b4ebe41828 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-await/_config.js @@ -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: `, + 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: + 19:`, + message: 'Unused CSS selector ".b ~ .d"', + pos: 323, + start: { character: 323, column: 1, line: 17 }, + end: { character: 330, column: 8, line: 17 } + } + ] +}; diff --git a/test/css/samples/general-siblings-combinator-await/expected.css b/test/css/samples/general-siblings-combinator-await/expected.css new file mode 100644 index 0000000000..94a5494597 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-await/expected.css @@ -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} \ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-await/expected.html b/test/css/samples/general-siblings-combinator-await/expected.html new file mode 100644 index 0000000000..3d8ac9f966 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-await/expected.html @@ -0,0 +1,3 @@ +
+
+
\ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-await/input.svelte b/test/css/samples/general-siblings-combinator-await/input.svelte new file mode 100644 index 0000000000..8aeadab170 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-await/input.svelte @@ -0,0 +1,30 @@ + + + + +
+ +{#await promise} +
+{:then value} +
+{:catch error} +
+{/await} + +
\ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-each-2/_config.js b/test/css/samples/general-siblings-combinator-each-2/_config.js new file mode 100644 index 0000000000..c81f1a9f82 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-each-2/_config.js @@ -0,0 +1,3 @@ +export default { + warnings: [] +}; diff --git a/test/css/samples/general-siblings-combinator-each-2/expected.css b/test/css/samples/general-siblings-combinator-each-2/expected.css new file mode 100644 index 0000000000..d197058b24 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-each-2/expected.css @@ -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} \ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-each-2/expected.html b/test/css/samples/general-siblings-combinator-each-2/expected.html new file mode 100644 index 0000000000..331a5e4317 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-each-2/expected.html @@ -0,0 +1,4 @@ +
+
+
+
\ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-each-2/input.svelte b/test/css/samples/general-siblings-combinator-each-2/input.svelte new file mode 100644 index 0000000000..5bbdbdef66 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-each-2/input.svelte @@ -0,0 +1,37 @@ + + + + +
+ +{#each array as item} +
+
+{/each} + +
\ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-each-else-nested/_config.js b/test/css/samples/general-siblings-combinator-each-else-nested/_config.js new file mode 100644 index 0000000000..cf241d856d --- /dev/null +++ b/test/css/samples/general-siblings-combinator-each-else-nested/_config.js @@ -0,0 +1,18 @@ +export default { + warnings: [ + { + code: "css-unused-selector", + frame: ` + 33: + 34: /* no match */ + 35: .e ~ .f { color: green; } + ^ + 36: + 37:`, + message: 'Unused CSS selector ".e ~ .f"', + pos: 812, + start: { character: 812, column: 1, line: 35 }, + end: { character: 819, column: 8, line: 35 } + } + ] +}; diff --git a/test/css/samples/general-siblings-combinator-each-else-nested/expected.css b/test/css/samples/general-siblings-combinator-each-else-nested/expected.css new file mode 100644 index 0000000000..b055f35ecd --- /dev/null +++ b/test/css/samples/general-siblings-combinator-each-else-nested/expected.css @@ -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} \ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-each-else-nested/expected.html b/test/css/samples/general-siblings-combinator-each-else-nested/expected.html new file mode 100644 index 0000000000..67dd05f677 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-each-else-nested/expected.html @@ -0,0 +1,3 @@ +
+
+
\ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-each-else-nested/input.svelte b/test/css/samples/general-siblings-combinator-each-else-nested/input.svelte new file mode 100644 index 0000000000..63a1123708 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-each-else-nested/input.svelte @@ -0,0 +1,77 @@ + + + + +
+ +{#each array as a} +
+ {#each array as b} +
+ {:else} +
+ {/each} +{/each} + +{#each array as c} + {#each array as d} +
+ {/each} +{:else} +
+{/each} + +{#each array as x} +
+ {#each array as y} + {#each array as z} +
+ {/each} + {:else} +
+ {/each} +
+{/each} + +
+ +{#each array as item} + {#each array as item} +
+ {:else} +
+ {/each} +{/each} \ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-each-else/_config.js b/test/css/samples/general-siblings-combinator-each-else/_config.js new file mode 100644 index 0000000000..4d9beceeb2 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-each-else/_config.js @@ -0,0 +1,18 @@ +export default { + warnings: [ + { + code: "css-unused-selector", + frame: ` + 11: + 12: /* no match */ + 13: .b ~ .c { color: green; } + ^ + 14: + 15:`, + message: 'Unused CSS selector ".b ~ .c"', + pos: 199, + start: { character: 199, column: 1, line: 13 }, + end: { character: 206, column: 8, line: 13 } + } + ] +}; diff --git a/test/css/samples/general-siblings-combinator-each-else/expected.css b/test/css/samples/general-siblings-combinator-each-else/expected.css new file mode 100644 index 0000000000..31fafa3243 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-each-else/expected.css @@ -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} \ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-each-else/expected.html b/test/css/samples/general-siblings-combinator-each-else/expected.html new file mode 100644 index 0000000000..fb838a55fd --- /dev/null +++ b/test/css/samples/general-siblings-combinator-each-else/expected.html @@ -0,0 +1,3 @@ +
+
+
\ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-each-else/input.svelte b/test/css/samples/general-siblings-combinator-each-else/input.svelte new file mode 100644 index 0000000000..5cd78853ca --- /dev/null +++ b/test/css/samples/general-siblings-combinator-each-else/input.svelte @@ -0,0 +1,24 @@ + + + + +
+ +{#each array as item} +
+{:else} +
+{/each} + +
\ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-each-nested/_config.js b/test/css/samples/general-siblings-combinator-each-nested/_config.js new file mode 100644 index 0000000000..c81f1a9f82 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-each-nested/_config.js @@ -0,0 +1,3 @@ +export default { + warnings: [] +}; diff --git a/test/css/samples/general-siblings-combinator-each-nested/expected.css b/test/css/samples/general-siblings-combinator-each-nested/expected.css new file mode 100644 index 0000000000..5bf1f832ae --- /dev/null +++ b/test/css/samples/general-siblings-combinator-each-nested/expected.css @@ -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} \ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-each-nested/expected.html b/test/css/samples/general-siblings-combinator-each-nested/expected.html new file mode 100644 index 0000000000..340d6fc4c8 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-each-nested/expected.html @@ -0,0 +1,15 @@ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-each-nested/input.svelte b/test/css/samples/general-siblings-combinator-each-nested/input.svelte new file mode 100644 index 0000000000..b7c7377015 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-each-nested/input.svelte @@ -0,0 +1,113 @@ + + + + +
+ +{#each array as item} +
+
+{/each} + +{#each array as item} + {#each array as item} + {#each array as item} +
+ {/each} +
+ {/each} +
+{/each} + +{#each array as item} +
+ {#each array as item} +
+ {#each array as item} +
+ {/each} + {/each} +{/each} + +{#each array as item} +
+ {#each array as item} +
+ {#each array as item} +
+ {/each} + {/each} +{/each} + +{#each array as item} + {#each array as item} + {#each array as item} +
+ {/each} +
+ {/each} +
+{/each} \ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-each/expected.css b/test/css/samples/general-siblings-combinator-each/expected.css new file mode 100644 index 0000000000..8c48251bdd --- /dev/null +++ b/test/css/samples/general-siblings-combinator-each/expected.css @@ -0,0 +1 @@ +div.svelte-xyz~span.svelte-xyz{color:green} \ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-each/expected.html b/test/css/samples/general-siblings-combinator-each/expected.html new file mode 100644 index 0000000000..9d0416f01b --- /dev/null +++ b/test/css/samples/general-siblings-combinator-each/expected.html @@ -0,0 +1,6 @@ +
+ +
+ +
+ diff --git a/test/css/samples/general-siblings-combinator-each/input.svelte b/test/css/samples/general-siblings-combinator-each/input.svelte new file mode 100644 index 0000000000..ce65da109d --- /dev/null +++ b/test/css/samples/general-siblings-combinator-each/input.svelte @@ -0,0 +1,20 @@ + + + + +
+ +{#each array as item} + +
+ +
+{/each} + + \ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-if-not-exhaustive-with-each/_config.js b/test/css/samples/general-siblings-combinator-if-not-exhaustive-with-each/_config.js new file mode 100644 index 0000000000..0b5d391f50 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-if-not-exhaustive-with-each/_config.js @@ -0,0 +1,18 @@ +export default { + warnings: [ + { + code: "css-unused-selector", + frame: ` + 16: + 17: /* no match */ + 18: .b ~ .c { color: green; } + ^ + 19: + 20:`, + message: 'Unused CSS selector ".b ~ .c"', + pos: 319, + start: { character: 319, column: 1, line: 18 }, + end: { character: 326, column: 8, line: 18 } + } + ] +}; diff --git a/test/css/samples/general-siblings-combinator-if-not-exhaustive-with-each/expected.css b/test/css/samples/general-siblings-combinator-if-not-exhaustive-with-each/expected.css new file mode 100644 index 0000000000..e6a974efca --- /dev/null +++ b/test/css/samples/general-siblings-combinator-if-not-exhaustive-with-each/expected.css @@ -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} \ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-if-not-exhaustive-with-each/expected.html b/test/css/samples/general-siblings-combinator-if-not-exhaustive-with-each/expected.html new file mode 100644 index 0000000000..fb838a55fd --- /dev/null +++ b/test/css/samples/general-siblings-combinator-if-not-exhaustive-with-each/expected.html @@ -0,0 +1,3 @@ +
+
+
\ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-if-not-exhaustive-with-each/input.svelte b/test/css/samples/general-siblings-combinator-if-not-exhaustive-with-each/input.svelte new file mode 100644 index 0000000000..2b53f7b5b8 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-if-not-exhaustive-with-each/input.svelte @@ -0,0 +1,31 @@ + + + + +
+ +{#if foo} +
+{:else} + {#each array as item} +
+ {/each} +{/if} + +
\ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-if-not-exhaustive/_config.js b/test/css/samples/general-siblings-combinator-if-not-exhaustive/_config.js new file mode 100644 index 0000000000..81fb595d68 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-if-not-exhaustive/_config.js @@ -0,0 +1,18 @@ +export default { + warnings: [ + { + code: "css-unused-selector", + frame: ` + 12: + 13: /* no match */ + 14: .b ~ .c { color: green; } + ^ + 15: + 16:`, + message: 'Unused CSS selector ".b ~ .c"', + pos: 215, + start: { character: 215, column: 1, line: 14 }, + end: { character: 222, column: 8, line: 14 } + } + ] +}; diff --git a/test/css/samples/general-siblings-combinator-if-not-exhaustive/expected.css b/test/css/samples/general-siblings-combinator-if-not-exhaustive/expected.css new file mode 100644 index 0000000000..dc7ee1b62b --- /dev/null +++ b/test/css/samples/general-siblings-combinator-if-not-exhaustive/expected.css @@ -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} \ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-if-not-exhaustive/expected.html b/test/css/samples/general-siblings-combinator-if-not-exhaustive/expected.html new file mode 100644 index 0000000000..813e778dc6 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-if-not-exhaustive/expected.html @@ -0,0 +1,3 @@ +
+
+
\ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-if-not-exhaustive/input.svelte b/test/css/samples/general-siblings-combinator-if-not-exhaustive/input.svelte new file mode 100644 index 0000000000..3e5c5af7a2 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-if-not-exhaustive/input.svelte @@ -0,0 +1,25 @@ + + + + +
+ +{#if foo} +
+{:else if bar} +
+{/if} + +
\ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-if/_config.js b/test/css/samples/general-siblings-combinator-if/_config.js new file mode 100644 index 0000000000..cbc3d8a784 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-if/_config.js @@ -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: `, + 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: + 20:`, + message: 'Unused CSS selector ".c ~ .d"', + pos: 323, + start: { character: 323, column: 1, line: 18 }, + end: { character: 330, column: 8, line: 18 } + } + ] +}; diff --git a/test/css/samples/general-siblings-combinator-if/expected.css b/test/css/samples/general-siblings-combinator-if/expected.css new file mode 100644 index 0000000000..94a5494597 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-if/expected.css @@ -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} \ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-if/expected.html b/test/css/samples/general-siblings-combinator-if/expected.html new file mode 100644 index 0000000000..3d8ac9f966 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-if/expected.html @@ -0,0 +1,3 @@ +
+
+
\ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-if/input.svelte b/test/css/samples/general-siblings-combinator-if/input.svelte new file mode 100644 index 0000000000..fca5499f2e --- /dev/null +++ b/test/css/samples/general-siblings-combinator-if/input.svelte @@ -0,0 +1,31 @@ + + + + +
+ +{#if foo} +
+{:else if bar} +
+{:else} +
+{/if} + +
\ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-slot/_config.js b/test/css/samples/general-siblings-combinator-slot/_config.js new file mode 100644 index 0000000000..4cf743c0a0 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-slot/_config.js @@ -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: `, + 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: + 17:`, + message: 'Unused CSS selector ".b ~ .g"', + pos: 246, + start: { character: 246, column: 1, line: 15 }, + end: { character: 253, column: 8, line: 15 } + } + ] +}; diff --git a/test/css/samples/general-siblings-combinator-slot/expected.css b/test/css/samples/general-siblings-combinator-slot/expected.css new file mode 100644 index 0000000000..29325e0cef --- /dev/null +++ b/test/css/samples/general-siblings-combinator-slot/expected.css @@ -0,0 +1 @@ +.d.svelte-xyz~.e.svelte-xyz{color:green}.a.svelte-xyz~.g.svelte-xyz{color:green} \ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-slot/input.svelte b/test/css/samples/general-siblings-combinator-slot/input.svelte new file mode 100644 index 0000000000..e5af4c0962 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-slot/input.svelte @@ -0,0 +1,30 @@ + + + + +
+ +
+ +
+
+
+
+ +
+ + +
\ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-star/_config.js b/test/css/samples/general-siblings-combinator-star/_config.js new file mode 100644 index 0000000000..64e5baad19 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-star/_config.js @@ -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 } + } + ] +}; diff --git a/test/css/samples/general-siblings-combinator-star/expected.css b/test/css/samples/general-siblings-combinator-star/expected.css new file mode 100644 index 0000000000..de947fa47e --- /dev/null +++ b/test/css/samples/general-siblings-combinator-star/expected.css @@ -0,0 +1 @@ +.match.svelte-xyz>.svelte-xyz~.svelte-xyz{margin-left:4px} \ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-star/expected.html b/test/css/samples/general-siblings-combinator-star/expected.html new file mode 100644 index 0000000000..1cfae6e6f7 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-star/expected.html @@ -0,0 +1,7 @@ +
+
+
+
+
+
+
\ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-star/input.svelte b/test/css/samples/general-siblings-combinator-star/input.svelte new file mode 100644 index 0000000000..a069685d4f --- /dev/null +++ b/test/css/samples/general-siblings-combinator-star/input.svelte @@ -0,0 +1,17 @@ + + +
+
+
+ +
+
+
+
\ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator/_config.js b/test/css/samples/general-siblings-combinator/_config.js new file mode 100644 index 0000000000..6513366549 --- /dev/null +++ b/test/css/samples/general-siblings-combinator/_config.js @@ -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: `, + 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: + 17:`, + message: 'Unused CSS selector "span ~ div"', + pos: 373, + start: { character: 373, column: 1, line: 15 }, + end: { character: 383, column: 11, line: 15 } + } + ] +}; diff --git a/test/css/samples/general-siblings-combinator/expected.css b/test/css/samples/general-siblings-combinator/expected.css new file mode 100644 index 0000000000..647a53f778 --- /dev/null +++ b/test/css/samples/general-siblings-combinator/expected.css @@ -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} \ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator/expected.html b/test/css/samples/general-siblings-combinator/expected.html new file mode 100644 index 0000000000..01fbffcae4 --- /dev/null +++ b/test/css/samples/general-siblings-combinator/expected.html @@ -0,0 +1,7 @@ +
+ + +
+
+

+
\ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator/input.svelte b/test/css/samples/general-siblings-combinator/input.svelte new file mode 100644 index 0000000000..533702a3a3 --- /dev/null +++ b/test/css/samples/general-siblings-combinator/input.svelte @@ -0,0 +1,24 @@ + + +
+ + +
+
+

+
\ No newline at end of file diff --git a/test/css/samples/siblings-combinator-await-not-exhaustive/_config.js b/test/css/samples/siblings-combinator-await-not-exhaustive/_config.js new file mode 100644 index 0000000000..c81f1a9f82 --- /dev/null +++ b/test/css/samples/siblings-combinator-await-not-exhaustive/_config.js @@ -0,0 +1,3 @@ +export default { + warnings: [] +}; diff --git a/test/css/samples/siblings-combinator-await-not-exhaustive/expected.css b/test/css/samples/siblings-combinator-await-not-exhaustive/expected.css new file mode 100644 index 0000000000..60bb8e92dc --- /dev/null +++ b/test/css/samples/siblings-combinator-await-not-exhaustive/expected.css @@ -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} \ No newline at end of file diff --git a/test/css/samples/siblings-combinator-await-not-exhaustive/expected.html b/test/css/samples/siblings-combinator-await-not-exhaustive/expected.html new file mode 100644 index 0000000000..de97b02a5e --- /dev/null +++ b/test/css/samples/siblings-combinator-await-not-exhaustive/expected.html @@ -0,0 +1,4 @@ +
+
+
+
\ No newline at end of file diff --git a/test/css/samples/siblings-combinator-await-not-exhaustive/input.svelte b/test/css/samples/siblings-combinator-await-not-exhaustive/input.svelte new file mode 100644 index 0000000000..d3345c6edc --- /dev/null +++ b/test/css/samples/siblings-combinator-await-not-exhaustive/input.svelte @@ -0,0 +1,41 @@ + + + + +
+ +{#await promise then value} +
+{:catch error} +
+{/await} + +{#await promise} +
+{:catch error} +
+{/await} + +{#await promise} +
+{:then error} +
+{/await} + +
\ No newline at end of file diff --git a/test/css/samples/siblings-combinator-await/_config.js b/test/css/samples/siblings-combinator-await/_config.js new file mode 100644 index 0000000000..5af12d38e5 --- /dev/null +++ b/test/css/samples/siblings-combinator-await/_config.js @@ -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: `, + 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: + 19:`, + message: 'Unused CSS selector ".b + .d"', + pos: 323, + start: { character: 323, column: 1, line: 17 }, + end: { character: 330, column: 8, line: 17 } + } + ] +}; diff --git a/test/css/samples/siblings-combinator-await/expected.css b/test/css/samples/siblings-combinator-await/expected.css new file mode 100644 index 0000000000..5ea39be7c2 --- /dev/null +++ b/test/css/samples/siblings-combinator-await/expected.css @@ -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} \ No newline at end of file diff --git a/test/css/samples/siblings-combinator-await/expected.html b/test/css/samples/siblings-combinator-await/expected.html new file mode 100644 index 0000000000..3d8ac9f966 --- /dev/null +++ b/test/css/samples/siblings-combinator-await/expected.html @@ -0,0 +1,3 @@ +
+
+
\ No newline at end of file diff --git a/test/css/samples/siblings-combinator-await/input.svelte b/test/css/samples/siblings-combinator-await/input.svelte new file mode 100644 index 0000000000..07698c2a30 --- /dev/null +++ b/test/css/samples/siblings-combinator-await/input.svelte @@ -0,0 +1,30 @@ + + + + +
+ +{#await promise} +
+{:then value} +
+{:catch error} +
+{/await} + +
\ No newline at end of file diff --git a/test/css/samples/siblings-combinator-each-2/_config.js b/test/css/samples/siblings-combinator-each-2/_config.js new file mode 100644 index 0000000000..e4799f1055 --- /dev/null +++ b/test/css/samples/siblings-combinator-each-2/_config.js @@ -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 } + } + ] +}; diff --git a/test/css/samples/siblings-combinator-each-2/expected.css b/test/css/samples/siblings-combinator-each-2/expected.css new file mode 100644 index 0000000000..60fa224269 --- /dev/null +++ b/test/css/samples/siblings-combinator-each-2/expected.css @@ -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} \ No newline at end of file diff --git a/test/css/samples/siblings-combinator-each-2/expected.html b/test/css/samples/siblings-combinator-each-2/expected.html new file mode 100644 index 0000000000..331a5e4317 --- /dev/null +++ b/test/css/samples/siblings-combinator-each-2/expected.html @@ -0,0 +1,4 @@ +
+
+
+
\ No newline at end of file diff --git a/test/css/samples/siblings-combinator-each-2/input.svelte b/test/css/samples/siblings-combinator-each-2/input.svelte new file mode 100644 index 0000000000..bbad045fbc --- /dev/null +++ b/test/css/samples/siblings-combinator-each-2/input.svelte @@ -0,0 +1,38 @@ + + + + +
+ +{#each array as item} +
+
+{/each} + +
\ No newline at end of file diff --git a/test/css/samples/siblings-combinator-each-else-nested/_config.js b/test/css/samples/siblings-combinator-each-else-nested/_config.js new file mode 100644 index 0000000000..ab3fac6abe --- /dev/null +++ b/test/css/samples/siblings-combinator-each-else-nested/_config.js @@ -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: `, + 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: + 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 } + } + ] +}; diff --git a/test/css/samples/siblings-combinator-each-else-nested/expected.css b/test/css/samples/siblings-combinator-each-else-nested/expected.css new file mode 100644 index 0000000000..aa4e04081d --- /dev/null +++ b/test/css/samples/siblings-combinator-each-else-nested/expected.css @@ -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} \ No newline at end of file diff --git a/test/css/samples/siblings-combinator-each-else-nested/expected.html b/test/css/samples/siblings-combinator-each-else-nested/expected.html new file mode 100644 index 0000000000..5f25a2d38a --- /dev/null +++ b/test/css/samples/siblings-combinator-each-else-nested/expected.html @@ -0,0 +1,3 @@ +
+
+
\ No newline at end of file diff --git a/test/css/samples/siblings-combinator-each-else-nested/input.svelte b/test/css/samples/siblings-combinator-each-else-nested/input.svelte new file mode 100644 index 0000000000..bee9c6b1dc --- /dev/null +++ b/test/css/samples/siblings-combinator-each-else-nested/input.svelte @@ -0,0 +1,74 @@ + + + + +
+ +{#each array as a} +
+ {#each array as b} +
+ {:else} +
+ {/each} +{/each} + +{#each array as c} + {#each array as d} +
+ {/each} +{:else} +
+{/each} + +{#each array as item} +
+ {#each array as item} + {#each array as item} +
+ {/each} + {:else} +
+ {/each} +
+{/each} + +
+ +{#each array as item} + {#each array as item} +
+ {:else} +
+ {/each} +{/each} \ No newline at end of file diff --git a/test/css/samples/siblings-combinator-each-else/_config.js b/test/css/samples/siblings-combinator-each-else/_config.js new file mode 100644 index 0000000000..fcd961d5fe --- /dev/null +++ b/test/css/samples/siblings-combinator-each-else/_config.js @@ -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: `, + 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: + 15:`, + message: 'Unused CSS selector ".b + .c"', + pos: 199, + start: { character: 199, column: 1, line: 13 }, + end: { character: 206, column: 8, line: 13 } + } + ] +}; diff --git a/test/css/samples/siblings-combinator-each-else/expected.css b/test/css/samples/siblings-combinator-each-else/expected.css new file mode 100644 index 0000000000..f82bca8215 --- /dev/null +++ b/test/css/samples/siblings-combinator-each-else/expected.css @@ -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} \ No newline at end of file diff --git a/test/css/samples/siblings-combinator-each-else/expected.html b/test/css/samples/siblings-combinator-each-else/expected.html new file mode 100644 index 0000000000..fb838a55fd --- /dev/null +++ b/test/css/samples/siblings-combinator-each-else/expected.html @@ -0,0 +1,3 @@ +
+
+
\ No newline at end of file diff --git a/test/css/samples/siblings-combinator-each-else/input.svelte b/test/css/samples/siblings-combinator-each-else/input.svelte new file mode 100644 index 0000000000..ecd48968c2 --- /dev/null +++ b/test/css/samples/siblings-combinator-each-else/input.svelte @@ -0,0 +1,24 @@ + + + + +
+ +{#each array as item} +
+{:else} +
+{/each} + +
\ No newline at end of file diff --git a/test/css/samples/siblings-combinator-each-nested/_config.js b/test/css/samples/siblings-combinator-each-nested/_config.js new file mode 100644 index 0000000000..ce9c46fb06 --- /dev/null +++ b/test/css/samples/siblings-combinator-each-nested/_config.js @@ -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: `, + 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: + 67:`, + message: 'Unused CSS selector ".g + .i"', + pos: 1418, + start: { character: 1418, column: 1, line: 65 }, + end: { character: 1425, column: 8, line: 65 } + } + ] +}; diff --git a/test/css/samples/siblings-combinator-each-nested/expected.css b/test/css/samples/siblings-combinator-each-nested/expected.css new file mode 100644 index 0000000000..616d739670 --- /dev/null +++ b/test/css/samples/siblings-combinator-each-nested/expected.css @@ -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} \ No newline at end of file diff --git a/test/css/samples/siblings-combinator-each-nested/expected.html b/test/css/samples/siblings-combinator-each-nested/expected.html new file mode 100644 index 0000000000..340d6fc4c8 --- /dev/null +++ b/test/css/samples/siblings-combinator-each-nested/expected.html @@ -0,0 +1,15 @@ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/test/css/samples/siblings-combinator-each-nested/input.svelte b/test/css/samples/siblings-combinator-each-nested/input.svelte new file mode 100644 index 0000000000..b5b9242675 --- /dev/null +++ b/test/css/samples/siblings-combinator-each-nested/input.svelte @@ -0,0 +1,113 @@ + + + + +
+ +{#each array as item} +
+
+{/each} + +{#each array as item} + {#each array as item} + {#each array as item} +
+ {/each} +
+ {/each} +
+{/each} + +{#each array as item} +
+ {#each array as item} +
+ {#each array as item} +
+ {/each} + {/each} +{/each} + +{#each array as item} +
+ {#each array as item} +
+ {#each array as item} +
+ {/each} + {/each} +{/each} + +{#each array as item} + {#each array as item} + {#each array as item} +
+ {/each} +
+ {/each} +
+{/each} \ No newline at end of file diff --git a/test/css/samples/siblings-combinator-each/expected.css b/test/css/samples/siblings-combinator-each/expected.css new file mode 100644 index 0000000000..a46fc4ed4e --- /dev/null +++ b/test/css/samples/siblings-combinator-each/expected.css @@ -0,0 +1 @@ +div.svelte-xyz+span.svelte-xyz{color:green} \ No newline at end of file diff --git a/test/css/samples/siblings-combinator-each/expected.html b/test/css/samples/siblings-combinator-each/expected.html new file mode 100644 index 0000000000..9d0416f01b --- /dev/null +++ b/test/css/samples/siblings-combinator-each/expected.html @@ -0,0 +1,6 @@ +
+ +
+ +
+ diff --git a/test/css/samples/siblings-combinator-each/input.svelte b/test/css/samples/siblings-combinator-each/input.svelte new file mode 100644 index 0000000000..de77a25180 --- /dev/null +++ b/test/css/samples/siblings-combinator-each/input.svelte @@ -0,0 +1,20 @@ + + + + +
+ +{#each array as item} + +
+ +
+{/each} + + \ No newline at end of file diff --git a/test/css/samples/siblings-combinator-if-not-exhaustive-with-each/_config.js b/test/css/samples/siblings-combinator-if-not-exhaustive-with-each/_config.js new file mode 100644 index 0000000000..0155bf0cf1 --- /dev/null +++ b/test/css/samples/siblings-combinator-if-not-exhaustive-with-each/_config.js @@ -0,0 +1,18 @@ +export default { + warnings: [ + { + code: "css-unused-selector", + frame: ` + 16: + 17: /* no match */ + 18: .b + .c { color: green; } + ^ + 19: + 20:`, + message: 'Unused CSS selector ".b + .c"', + pos: 319, + start: { character: 319, column: 1, line: 18 }, + end: { character: 326, column: 8, line: 18 } + } + ] +}; diff --git a/test/css/samples/siblings-combinator-if-not-exhaustive-with-each/expected.css b/test/css/samples/siblings-combinator-if-not-exhaustive-with-each/expected.css new file mode 100644 index 0000000000..93cd539f00 --- /dev/null +++ b/test/css/samples/siblings-combinator-if-not-exhaustive-with-each/expected.css @@ -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} \ No newline at end of file diff --git a/test/css/samples/siblings-combinator-if-not-exhaustive-with-each/expected.html b/test/css/samples/siblings-combinator-if-not-exhaustive-with-each/expected.html new file mode 100644 index 0000000000..fb838a55fd --- /dev/null +++ b/test/css/samples/siblings-combinator-if-not-exhaustive-with-each/expected.html @@ -0,0 +1,3 @@ +
+
+
\ No newline at end of file diff --git a/test/css/samples/siblings-combinator-if-not-exhaustive-with-each/input.svelte b/test/css/samples/siblings-combinator-if-not-exhaustive-with-each/input.svelte new file mode 100644 index 0000000000..ff9f10dc1c --- /dev/null +++ b/test/css/samples/siblings-combinator-if-not-exhaustive-with-each/input.svelte @@ -0,0 +1,31 @@ + + + + +
+ +{#if foo} +
+{:else} + {#each array as item} +
+ {/each} +{/if} + +
\ No newline at end of file diff --git a/test/css/samples/siblings-combinator-if-not-exhaustive/_config.js b/test/css/samples/siblings-combinator-if-not-exhaustive/_config.js new file mode 100644 index 0000000000..e01c358eff --- /dev/null +++ b/test/css/samples/siblings-combinator-if-not-exhaustive/_config.js @@ -0,0 +1,18 @@ +export default { + warnings: [ + { + code: "css-unused-selector", + frame: ` + 12: + 13: /* no match */ + 14: .b + .c { color: green; } + ^ + 15: + 16:`, + message: 'Unused CSS selector ".b + .c"', + pos: 215, + start: { character: 215, column: 1, line: 14 }, + end: { character: 222, column: 8, line: 14 } + } + ] +}; diff --git a/test/css/samples/siblings-combinator-if-not-exhaustive/expected.css b/test/css/samples/siblings-combinator-if-not-exhaustive/expected.css new file mode 100644 index 0000000000..b1225e36a1 --- /dev/null +++ b/test/css/samples/siblings-combinator-if-not-exhaustive/expected.css @@ -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} \ No newline at end of file diff --git a/test/css/samples/siblings-combinator-if-not-exhaustive/expected.html b/test/css/samples/siblings-combinator-if-not-exhaustive/expected.html new file mode 100644 index 0000000000..813e778dc6 --- /dev/null +++ b/test/css/samples/siblings-combinator-if-not-exhaustive/expected.html @@ -0,0 +1,3 @@ +
+
+
\ No newline at end of file diff --git a/test/css/samples/siblings-combinator-if-not-exhaustive/input.svelte b/test/css/samples/siblings-combinator-if-not-exhaustive/input.svelte new file mode 100644 index 0000000000..4f832b3b47 --- /dev/null +++ b/test/css/samples/siblings-combinator-if-not-exhaustive/input.svelte @@ -0,0 +1,25 @@ + + + + +
+ +{#if foo} +
+{:else if bar} +
+{/if} + +
\ No newline at end of file diff --git a/test/css/samples/siblings-combinator-if/_config.js b/test/css/samples/siblings-combinator-if/_config.js new file mode 100644 index 0000000000..c2396f08ef --- /dev/null +++ b/test/css/samples/siblings-combinator-if/_config.js @@ -0,0 +1,60 @@ +export default { + warnings: [ + { + code: "css-unused-selector", + frame: ` + 13: + 14: /* no match */ + 15: .a + .e { color: green; } + ^ + 16: .b + .c { color: green; } + 17: .b + .d { color: green; }`, + message: 'Unused CSS selector ".a + .e"', + pos: 242, + start: { character: 242, column: 1, line: 15 }, + end: { character: 249, column: 8, line: 15 } + }, + { + code: "css-unused-selector", + frame: ` + 14: /* no match */ + 15: .a + .e { color: green; } + 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: .a + .e { color: green; } + 16: .b + .c { color: green; } + 17: .b + .d { color: green; } + ^ + 18: .c + .d { color: green; } + 19: `, + 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: + 20:`, + message: 'Unused CSS selector ".c + .d"', + pos: 323, + start: { character: 323, column: 1, line: 18 }, + end: { character: 330, column: 8, line: 18 } + } + ] +}; diff --git a/test/css/samples/siblings-combinator-if/expected.css b/test/css/samples/siblings-combinator-if/expected.css new file mode 100644 index 0000000000..5ea39be7c2 --- /dev/null +++ b/test/css/samples/siblings-combinator-if/expected.css @@ -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} \ No newline at end of file diff --git a/test/css/samples/siblings-combinator-if/expected.html b/test/css/samples/siblings-combinator-if/expected.html new file mode 100644 index 0000000000..3d8ac9f966 --- /dev/null +++ b/test/css/samples/siblings-combinator-if/expected.html @@ -0,0 +1,3 @@ +
+
+
\ No newline at end of file diff --git a/test/css/samples/siblings-combinator-if/input.svelte b/test/css/samples/siblings-combinator-if/input.svelte new file mode 100644 index 0000000000..6cfc436876 --- /dev/null +++ b/test/css/samples/siblings-combinator-if/input.svelte @@ -0,0 +1,31 @@ + + + + +
+ +{#if foo} +
+{:else if bar} +
+{:else} +
+{/if} + +
\ No newline at end of file diff --git a/test/css/samples/siblings-combinator-slot/_config.js b/test/css/samples/siblings-combinator-slot/_config.js new file mode 100644 index 0000000000..c0a00500d4 --- /dev/null +++ b/test/css/samples/siblings-combinator-slot/_config.js @@ -0,0 +1,46 @@ +export default { + warnings: [ + { + code: "css-unused-selector", + frame: ` + 7: + 8: /* no match */ + 9: .a + .b { color: green; } + ^ + 10: .b + .c { color: green; } + 11: .c + .f { color: green; }`, + message: 'Unused CSS selector ".a + .b"', + pos: 84, + start: { character: 84, column: 1, line: 9 }, + end: { character: 91, column: 8, line: 9 } + }, + { + code: "css-unused-selector", + frame: ` + 8: /* no match */ + 9: .a + .b { color: green; } + 10: .b + .c { color: green; } + ^ + 11: .c + .f { color: green; } + 12: `, + message: 'Unused CSS selector ".b + .c"', + pos: 111, + start: { character: 111, column: 1, line: 10 }, + end: { character: 118, column: 8, line: 10 } + }, + { + code: "css-unused-selector", + frame: ` + 9: .a + .b { color: green; } + 10: .b + .c { color: green; } + 11: .c + .f { color: green; } + ^ + 12: + 13:`, + message: 'Unused CSS selector ".c + .f"', + pos: 138, + start: { character: 138, column: 1, line: 11 }, + end: { character: 145, column: 8, line: 11 } + } + ] +}; diff --git a/test/css/samples/siblings-combinator-slot/expected.css b/test/css/samples/siblings-combinator-slot/expected.css new file mode 100644 index 0000000000..bbdd03f274 --- /dev/null +++ b/test/css/samples/siblings-combinator-slot/expected.css @@ -0,0 +1 @@ +.d.svelte-xyz+.e.svelte-xyz{color:green} \ No newline at end of file diff --git a/test/css/samples/siblings-combinator-slot/input.svelte b/test/css/samples/siblings-combinator-slot/input.svelte new file mode 100644 index 0000000000..42fe0e4c30 --- /dev/null +++ b/test/css/samples/siblings-combinator-slot/input.svelte @@ -0,0 +1,24 @@ + + + + +
+ +
+ +
+
+
+
+ + +
\ No newline at end of file diff --git a/test/css/samples/siblings-combinator-star/_config.js b/test/css/samples/siblings-combinator-star/_config.js new file mode 100644 index 0000000000..32ff416981 --- /dev/null +++ b/test/css/samples/siblings-combinator-star/_config.js @@ -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 } + } + ] +}; diff --git a/test/css/samples/siblings-combinator-star/expected.css b/test/css/samples/siblings-combinator-star/expected.css new file mode 100644 index 0000000000..c1a06945f9 --- /dev/null +++ b/test/css/samples/siblings-combinator-star/expected.css @@ -0,0 +1 @@ +.match.svelte-xyz>.svelte-xyz+.svelte-xyz{margin-left:4px} \ No newline at end of file diff --git a/test/css/samples/siblings-combinator-star/expected.html b/test/css/samples/siblings-combinator-star/expected.html new file mode 100644 index 0000000000..1cfae6e6f7 --- /dev/null +++ b/test/css/samples/siblings-combinator-star/expected.html @@ -0,0 +1,7 @@ +
+
+
+
+
+
+
\ No newline at end of file diff --git a/test/css/samples/siblings-combinator-star/input.svelte b/test/css/samples/siblings-combinator-star/input.svelte new file mode 100644 index 0000000000..ca837f2239 --- /dev/null +++ b/test/css/samples/siblings-combinator-star/input.svelte @@ -0,0 +1,17 @@ + + +
+
+
+ +
+
+
+
\ No newline at end of file diff --git a/test/css/samples/siblings-combinator-with-spread/_config.js b/test/css/samples/siblings-combinator-with-spread/_config.js new file mode 100644 index 0000000000..c81f1a9f82 --- /dev/null +++ b/test/css/samples/siblings-combinator-with-spread/_config.js @@ -0,0 +1,3 @@ +export default { + warnings: [] +}; diff --git a/test/css/samples/siblings-combinator-with-spread/expected.css b/test/css/samples/siblings-combinator-with-spread/expected.css new file mode 100644 index 0000000000..aacf6e7db5 --- /dev/null +++ b/test/css/samples/siblings-combinator-with-spread/expected.css @@ -0,0 +1 @@ +input.svelte-xyz:focus+div.svelte-xyz{color:red}input.svelte-xyz:focus~div.svelte-xyz{color:red} \ No newline at end of file diff --git a/test/css/samples/siblings-combinator-with-spread/expected.html b/test/css/samples/siblings-combinator-with-spread/expected.html new file mode 100644 index 0000000000..d732739701 --- /dev/null +++ b/test/css/samples/siblings-combinator-with-spread/expected.html @@ -0,0 +1,2 @@ + +
Should be red, when input is focused
\ No newline at end of file diff --git a/test/css/samples/siblings-combinator-with-spread/input.svelte b/test/css/samples/siblings-combinator-with-spread/input.svelte new file mode 100644 index 0000000000..45c889c1ae --- /dev/null +++ b/test/css/samples/siblings-combinator-with-spread/input.svelte @@ -0,0 +1,11 @@ + + + + + +
Should be red, when input is focused
\ No newline at end of file diff --git a/test/css/samples/siblings-combinator/_config.js b/test/css/samples/siblings-combinator/_config.js new file mode 100644 index 0000000000..2285b5a837 --- /dev/null +++ b/test/css/samples/siblings-combinator/_config.js @@ -0,0 +1,62 @@ +export default { + warnings: [ + { + code: "css-unused-selector", + frame: ` + 3: color: green; + 4: } + 5: article + div { + ^ + 6: color: green; + 7: }`, + message: 'Unused CSS selector "article + div"', + pos: 45, + start: { character: 45, column: 1, line: 5 }, + end: { character: 58, column: 14, line: 5 } + }, + { + code: "css-unused-selector", + + frame:` + 6: color: green; + 7: } + 8: span + article { + ^ + 9: color: green; + 10: }`, + message: 'Unused CSS selector "span + article"', + pos: 81, + start: { character: 81, column: 1, line: 8 }, + end: { character: 95, column: 15, line: 8 } + }, + { + code: "css-unused-selector", + + frame: ` + 9: color: green; + 10: } + 11: b + article { + ^ + 12: color: green; + 13: }`, + message: 'Unused CSS selector "b + article"', + pos: 118, + start: { character: 118, column: 1, line: 11 }, + end: { character: 129, column: 12, line: 11 } + }, + { + code: "css-unused-selector", + frame: ` + 12: color: green; + 13: } + 14: span + div { + ^ + 15: color: green; + 16: }`, + message: 'Unused CSS selector "span + div"', + pos: 152, + start: { character: 152, column: 1, line: 14 }, + end: { character: 162, column: 11, line: 14 } + } + ] +}; diff --git a/test/css/samples/siblings-combinator/expected.css b/test/css/samples/siblings-combinator/expected.css new file mode 100644 index 0000000000..be01048cf1 --- /dev/null +++ b/test/css/samples/siblings-combinator/expected.css @@ -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} \ No newline at end of file diff --git a/test/css/samples/siblings-combinator/expected.html b/test/css/samples/siblings-combinator/expected.html new file mode 100644 index 0000000000..f4692365dd --- /dev/null +++ b/test/css/samples/siblings-combinator/expected.html @@ -0,0 +1,5 @@ +
+ + +
+
\ No newline at end of file diff --git a/test/css/samples/siblings-combinator/input.svelte b/test/css/samples/siblings-combinator/input.svelte new file mode 100644 index 0000000000..3e22076d52 --- /dev/null +++ b/test/css/samples/siblings-combinator/input.svelte @@ -0,0 +1,35 @@ + + +
+ + +
+
\ No newline at end of file diff --git a/test/js/samples/event-modifiers/expected.js b/test/js/samples/event-modifiers/expected.js index 6aa3c161f9..3901753661 100644 --- a/test/js/samples/event-modifiers/expected.js +++ b/test/js/samples/event-modifiers/expected.js @@ -16,41 +16,49 @@ import { } from "svelte/internal"; function create_fragment(ctx) { - let div; - let button0; + let div1; + let div0; let t1; - let button1; + let button0; let t3; + let button1; + let t5; let button2; let mounted; let dispose; return { c() { - div = element("div"); + div1 = element("div"); + div0 = element("div"); + div0.textContent = "touch me"; + t1 = space(); button0 = element("button"); button0.textContent = "click me"; - t1 = space(); + t3 = space(); button1 = element("button"); button1.textContent = "or me"; - t3 = space(); + t5 = space(); button2 = element("button"); button2.textContent = "or me!"; }, m(target, anchor) { - insert(target, div, anchor); - append(div, button0); - append(div, t1); - append(div, button1); - append(div, t3); - append(div, button2); + insert(target, div1, anchor); + append(div1, div0); + append(div1, t1); + append(div1, button0); + append(div1, t3); + append(div1, button1); + append(div1, t5); + append(div1, button2); if (!mounted) { dispose = [ + listen(div0, "touchstart", handleTouchstart, { passive: false }), listen(button0, "click", stop_propagation(prevent_default(handleClick))), listen(button1, "click", handleClick, { once: true, capture: true }), listen(button2, "click", handleClick, true), - listen(div, "touchstart", handleTouchstart, { passive: true }) + listen(div1, "touchstart", handleTouchstart, { passive: true }) ]; mounted = true; @@ -60,7 +68,7 @@ function create_fragment(ctx) { i: noop, o: noop, d(detaching) { - if (detaching) detach(div); + if (detaching) detach(div1); mounted = false; run_all(dispose); } diff --git a/test/js/samples/event-modifiers/input.svelte b/test/js/samples/event-modifiers/input.svelte index 225134f598..c72d58dabb 100644 --- a/test/js/samples/event-modifiers/input.svelte +++ b/test/js/samples/event-modifiers/input.svelte @@ -9,6 +9,7 @@
+
touch me
diff --git a/test/runtime/samples/each-block-keyed-dyanmic-key/_config.js b/test/runtime/samples/each-block-keyed-dyanmic-key/_config.js new file mode 100644 index 0000000000..0aed1b0e07 --- /dev/null +++ b/test/runtime/samples/each-block-keyed-dyanmic-key/_config.js @@ -0,0 +1,27 @@ +let count = 0; +let value = 'foo'; + +export default { + props: { + value() { + count++; + return value; + } + }, + + html: ` +
foo
+
foo
+ `, + + test({ assert, component, target }) { + value = 'bar'; + component.id = 1; + + assert.equal(count, 4); + assert.htmlEqual(target.innerHTML, ` +
bar
+
bar
+ `); + } +}; diff --git a/test/runtime/samples/each-block-keyed-dyanmic-key/main.svelte b/test/runtime/samples/each-block-keyed-dyanmic-key/main.svelte new file mode 100644 index 0000000000..9a15c7d98e --- /dev/null +++ b/test/runtime/samples/each-block-keyed-dyanmic-key/main.svelte @@ -0,0 +1,8 @@ + + +{#each ['foo', 'bar'] as key (id + key)} +
{value()}
+{/each} \ No newline at end of file diff --git a/test/runtime/samples/key-block-2/_config.js b/test/runtime/samples/key-block-2/_config.js new file mode 100644 index 0000000000..a7c53bd91f --- /dev/null +++ b/test/runtime/samples/key-block-2/_config.js @@ -0,0 +1,14 @@ +// with reactive content beside `key` +export default { + html: `
00
`, + async test({ assert, component, target, window }) { + const div = target.querySelector('div'); + component.reactive = 2; + assert.htmlEqual(target.innerHTML, `
02
`); + assert.strictEqual(div, target.querySelector('div')); + + component.value = 5; + assert.htmlEqual(target.innerHTML, `
52
`); + assert.notStrictEqual(div, target.querySelector('div')); + } +}; diff --git a/test/runtime/samples/key-block-2/main.svelte b/test/runtime/samples/key-block-2/main.svelte new file mode 100644 index 0000000000..466d20b10a --- /dev/null +++ b/test/runtime/samples/key-block-2/main.svelte @@ -0,0 +1,8 @@ + + +{#key value} +
{value}{reactive}
+{/key} \ No newline at end of file diff --git a/test/runtime/samples/key-block-3/_config.js b/test/runtime/samples/key-block-3/_config.js new file mode 100644 index 0000000000..4290599cb3 --- /dev/null +++ b/test/runtime/samples/key-block-3/_config.js @@ -0,0 +1,11 @@ +// key is not used in the template +export default { + html: `
`, + async test({ assert, component, target, window }) { + const div = target.querySelector('div'); + + component.value = 5; + assert.htmlEqual(target.innerHTML, `
`); + assert.notStrictEqual(div, target.querySelector('div')); + } +}; diff --git a/test/runtime/samples/key-block-3/main.svelte b/test/runtime/samples/key-block-3/main.svelte new file mode 100644 index 0000000000..1ed185c732 --- /dev/null +++ b/test/runtime/samples/key-block-3/main.svelte @@ -0,0 +1,7 @@ + + +{#key value} +
+{/key} \ No newline at end of file diff --git a/test/runtime/samples/key-block-array-immutable/_config.js b/test/runtime/samples/key-block-array-immutable/_config.js new file mode 100644 index 0000000000..fb94556c0f --- /dev/null +++ b/test/runtime/samples/key-block-array-immutable/_config.js @@ -0,0 +1,15 @@ +export default { + html: `
1
`, + async test({ assert, component, target, window }) { + let div = target.querySelector("div"); + await component.append(2); + assert.htmlEqual(target.innerHTML, `
1
`); + assert.strictEqual(div, target.querySelector("div")); + + div = target.querySelector("div"); + + component.array = [3, 4]; + assert.htmlEqual(target.innerHTML, `
3,4
`); + assert.notStrictEqual(div, target.querySelector("div")); + } +}; diff --git a/test/runtime/samples/key-block-array-immutable/main.svelte b/test/runtime/samples/key-block-array-immutable/main.svelte new file mode 100644 index 0000000000..e666275af4 --- /dev/null +++ b/test/runtime/samples/key-block-array-immutable/main.svelte @@ -0,0 +1,14 @@ + + + + +{#key array} +
{array.join(',')}
+{/key} \ No newline at end of file diff --git a/test/runtime/samples/key-block-array/_config.js b/test/runtime/samples/key-block-array/_config.js new file mode 100644 index 0000000000..05d5fe9995 --- /dev/null +++ b/test/runtime/samples/key-block-array/_config.js @@ -0,0 +1,15 @@ +export default { + html: `
1
`, + async test({ assert, component, target, window }) { + let div = target.querySelector("div"); + await component.append(2); + assert.htmlEqual(target.innerHTML, `
1,2
`); + assert.notStrictEqual(div, target.querySelector("div")); + + div = target.querySelector("div"); + + component.array = [3, 4]; + assert.htmlEqual(target.innerHTML, `
3,4
`); + assert.notStrictEqual(div, target.querySelector("div")); + } +}; diff --git a/test/runtime/samples/key-block-array/main.svelte b/test/runtime/samples/key-block-array/main.svelte new file mode 100644 index 0000000000..5a4054b043 --- /dev/null +++ b/test/runtime/samples/key-block-array/main.svelte @@ -0,0 +1,12 @@ + + +{#key array} +
{array.join(',')}
+{/key} \ No newline at end of file diff --git a/test/runtime/samples/key-block-expression-2/_config.js b/test/runtime/samples/key-block-expression-2/_config.js new file mode 100644 index 0000000000..236c72fa3d --- /dev/null +++ b/test/runtime/samples/key-block-expression-2/_config.js @@ -0,0 +1,18 @@ +export default { + html: `
3
`, + async test({ assert, component, target, window }) { + const div = target.querySelector("div"); + + await component.mutate(); + assert.htmlEqual(target.innerHTML, `
5
`); + assert.strictEqual(div, target.querySelector("div")); + + await component.reassign(); + assert.htmlEqual(target.innerHTML, `
7
`); + assert.strictEqual(div, target.querySelector("div")); + + await component.changeKey(); + assert.htmlEqual(target.innerHTML, `
7
`); + assert.notStrictEqual(div, target.querySelector("div")); + } +}; diff --git a/test/runtime/samples/key-block-expression-2/main.svelte b/test/runtime/samples/key-block-expression-2/main.svelte new file mode 100644 index 0000000000..5525f63761 --- /dev/null +++ b/test/runtime/samples/key-block-expression-2/main.svelte @@ -0,0 +1,17 @@ + + +{#key obj.key} +
{obj.value}
+{/key} \ No newline at end of file diff --git a/test/runtime/samples/key-block-expression/_config.js b/test/runtime/samples/key-block-expression/_config.js new file mode 100644 index 0000000000..78890988ea --- /dev/null +++ b/test/runtime/samples/key-block-expression/_config.js @@ -0,0 +1,28 @@ +export default { + html: `
000
`, + async test({ assert, component, target, window }) { + let div = target.querySelector("div"); + component.value = 2; + assert.htmlEqual(target.innerHTML, `
200
`); + assert.notStrictEqual(div, target.querySelector("div")); + + div = target.querySelector("div"); + + component.anotherValue = 5; + assert.htmlEqual(target.innerHTML, `
250
`); + assert.notStrictEqual(div, target.querySelector("div")); + + div = target.querySelector("div"); + + component.thirdValue = 9; + assert.htmlEqual(target.innerHTML, `
259
`); + assert.strictEqual(div, target.querySelector("div")); + + // make dirty while maintain the value of `value + anotherValue` + // should update the content, but not recreate the elements + await component.$set({ value: 4, anotherValue: 3 }); + + assert.htmlEqual(target.innerHTML, `
439
`); + assert.strictEqual(div, target.querySelector("div")); + } +}; diff --git a/test/runtime/samples/key-block-expression/main.svelte b/test/runtime/samples/key-block-expression/main.svelte new file mode 100644 index 0000000000..dd752e8b8f --- /dev/null +++ b/test/runtime/samples/key-block-expression/main.svelte @@ -0,0 +1,9 @@ + + +{#key value + anotherValue} +
{value}{anotherValue}{thirdValue}
+{/key} \ No newline at end of file diff --git a/test/runtime/samples/key-block-static/_config.js b/test/runtime/samples/key-block-static/_config.js new file mode 100644 index 0000000000..d5ea0bf687 --- /dev/null +++ b/test/runtime/samples/key-block-static/_config.js @@ -0,0 +1,9 @@ +export default { + html: `
00
`, + async test({ assert, component, target, window }) { + const div = target.querySelector('div'); + component.anotherValue = 2; + assert.htmlEqual(target.innerHTML, `
02
`); + assert.strictEqual(div, target.querySelector('div')); + } +}; diff --git a/test/runtime/samples/key-block-static/main.svelte b/test/runtime/samples/key-block-static/main.svelte new file mode 100644 index 0000000000..e4ee6b5d71 --- /dev/null +++ b/test/runtime/samples/key-block-static/main.svelte @@ -0,0 +1,8 @@ + + +{#key value} +
{value}{anotherValue}
+{/key} \ No newline at end of file diff --git a/test/runtime/samples/key-block-transition/_config.js b/test/runtime/samples/key-block-transition/_config.js new file mode 100644 index 0000000000..53de6b333c --- /dev/null +++ b/test/runtime/samples/key-block-transition/_config.js @@ -0,0 +1,24 @@ +export default { + html: '
0
', + async test({ assert, component, target, window, raf }) { + component.value = 2; + + const [div1, div2] = target.querySelectorAll('div'); + + assert.htmlEqual(div1.outerHTML, '
0
'); + assert.htmlEqual(div2.outerHTML, '
2
'); + + raf.tick(0); + + assert.equal(div1.foo, 1); + assert.equal(div1.oof, 0); + + assert.equal(div2.foo, 0); + assert.equal(div2.oof, 1); + + raf.tick(200); + + assert.htmlEqual(target.innerHTML, '
2
'); + assert.equal(div2, target.querySelector('div')); + } +}; diff --git a/test/runtime/samples/key-block-transition/main.svelte b/test/runtime/samples/key-block-transition/main.svelte new file mode 100644 index 0000000000..d7fb6ec024 --- /dev/null +++ b/test/runtime/samples/key-block-transition/main.svelte @@ -0,0 +1,17 @@ + + +{#key value} +
{value}
+{/key} \ No newline at end of file diff --git a/test/runtime/samples/key-block/_config.js b/test/runtime/samples/key-block/_config.js new file mode 100644 index 0000000000..ad206c3b06 --- /dev/null +++ b/test/runtime/samples/key-block/_config.js @@ -0,0 +1,17 @@ +export default { + html: `
0
0
`, + async test({ assert, component, target, window }) { + let [div1, div2] = target.querySelectorAll('div'); + + component.value = 5; + assert.htmlEqual(target.innerHTML, `
5
0
`); + assert.notStrictEqual(div1, target.querySelectorAll('div')[0]); + assert.strictEqual(div2, target.querySelectorAll('div')[1]); + [div1, div2] = target.querySelectorAll('div'); + + component.reactive = 10; + assert.htmlEqual(target.innerHTML, `
5
10
`); + assert.strictEqual(div1, target.querySelectorAll('div')[0]); + assert.strictEqual(div2, target.querySelectorAll('div')[1]); + } +}; diff --git a/test/runtime/samples/key-block/main.svelte b/test/runtime/samples/key-block/main.svelte new file mode 100644 index 0000000000..ac3c340770 --- /dev/null +++ b/test/runtime/samples/key-block/main.svelte @@ -0,0 +1,10 @@ + + +{#key value} +
{value}
+{/key} + +
{reactive}
\ No newline at end of file diff --git a/test/runtime/samples/reactive-assignment-in-complex-declaration-with-store-2/_config.js b/test/runtime/samples/reactive-assignment-in-complex-declaration-with-store-2/_config.js new file mode 100644 index 0000000000..f737cad2aa --- /dev/null +++ b/test/runtime/samples/reactive-assignment-in-complex-declaration-with-store-2/_config.js @@ -0,0 +1,9 @@ +// destructure to store value +export default { + skip_if_ssr: true, // pending https://github.com/sveltejs/svelte/issues/3582 + html: `

2 2 xxx 5 6 9 10 2

`, + async test({ assert, target, component }) { + await component.update(); + assert.htmlEqual(target.innerHTML, `

11 11 yyy 12 13 14 15 11

`); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/reactive-assignment-in-complex-declaration-with-store-2/main.svelte b/test/runtime/samples/reactive-assignment-in-complex-declaration-with-store-2/main.svelte new file mode 100644 index 0000000000..c1bf63d9cd --- /dev/null +++ b/test/runtime/samples/reactive-assignment-in-complex-declaration-with-store-2/main.svelte @@ -0,0 +1,29 @@ + + +

{foo} {$eid} {$u.name} {$v} {$w} {$x} {$y} {$z}

diff --git a/test/runtime/samples/reactive-assignment-in-complex-declaration-with-store/_config.js b/test/runtime/samples/reactive-assignment-in-complex-declaration-with-store/_config.js index e74cea70fe..0318e63b0a 100644 --- a/test/runtime/samples/reactive-assignment-in-complex-declaration-with-store/_config.js +++ b/test/runtime/samples/reactive-assignment-in-complex-declaration-with-store/_config.js @@ -1,3 +1,9 @@ +// destructure to store export default { - html: `

2 2 xxx 5 6

` + html: `

2 2 xxx 5 6 9 10 2

`, + skip_if_ssr: true, + async test({ assert, target, component }) { + await component.update(); + assert.htmlEqual(target.innerHTML, `

11 11 yyy 12 13 14 15 11

`); + } }; \ No newline at end of file diff --git a/test/runtime/samples/reactive-assignment-in-complex-declaration-with-store/main.svelte b/test/runtime/samples/reactive-assignment-in-complex-declaration-with-store/main.svelte index 5ad442e1da..cd49223535 100644 --- a/test/runtime/samples/reactive-assignment-in-complex-declaration-with-store/main.svelte +++ b/test/runtime/samples/reactive-assignment-in-complex-declaration-with-store/main.svelte @@ -6,11 +6,24 @@ let u; let v; let w; + let x; + let y; [u, v, w] = [ {id: eid = writable(foo = 2), name: 'xxx'}, 5, writable(6) ]; + ({ a: x, b: y } = { a: writable(9), b: writable(10) }); + $: z = u.id; + + export function update() { + [u, v, w] = [ + {id: eid = writable(foo = 11), name: 'yyy'}, + 12, + writable(13) + ]; + ({ a: x, b: y } = { a: writable(14), b: writable(15) }); + } -

{foo} {$eid} {u.name} {v} {$w}

+

{foo} {$eid} {u.name} {v} {$w} {$x} {$y} {$z}

diff --git a/test/validator/samples/action-object/input.svelte b/test/validator/samples/action-object/input.svelte new file mode 100644 index 0000000000..e0962fa594 --- /dev/null +++ b/test/validator/samples/action-object/input.svelte @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/test/validator/samples/action-object/warnings.json b/test/validator/samples/action-object/warnings.json new file mode 100644 index 0000000000..e1ccbb55a2 --- /dev/null +++ b/test/validator/samples/action-object/warnings.json @@ -0,0 +1,17 @@ +[ + { + "code": "missing-declaration", + "end": { + "character": 217, + "column": 39, + "line": 11 + }, + "message": "'foo' is not defined", + "pos": 186, + "start": { + "character": 186, + "column": 8, + "line": 11 + } + } +] diff --git a/test/validator/samples/event-modifiers-invalid-nonpassive/errors.json b/test/validator/samples/event-modifiers-invalid-nonpassive/errors.json new file mode 100644 index 0000000000..a7e5a2a76c --- /dev/null +++ b/test/validator/samples/event-modifiers-invalid-nonpassive/errors.json @@ -0,0 +1,15 @@ +[{ + "message": "The 'passive' and 'nonpassive' modifiers cannot be used together", + "code": "invalid-event-modifier", + "start": { + "line": 1, + "column": 5, + "character": 5 + }, + "end": { + "line": 1, + "column": 51, + "character": 51 + }, + "pos": 5 +}] diff --git a/test/validator/samples/event-modifiers-invalid-nonpassive/input.svelte b/test/validator/samples/event-modifiers-invalid-nonpassive/input.svelte new file mode 100644 index 0000000000..3557aa4b1d --- /dev/null +++ b/test/validator/samples/event-modifiers-invalid-nonpassive/input.svelte @@ -0,0 +1,3 @@ +
+ oops +
\ No newline at end of file diff --git a/test/validator/samples/event-modifiers-invalid/errors.json b/test/validator/samples/event-modifiers-invalid/errors.json index 8be2ca7348..59a142d632 100644 --- a/test/validator/samples/event-modifiers-invalid/errors.json +++ b/test/validator/samples/event-modifiers-invalid/errors.json @@ -1,5 +1,5 @@ [{ - "message": "Valid event modifiers are preventDefault, stopPropagation, capture, once, passive or self", + "message": "Valid event modifiers are preventDefault, stopPropagation, capture, once, passive, nonpassive or self", "code": "invalid-event-modifier", "start": { "line": 1,