Merge branch 'master' into api-reference

pull/2206/head
Rich Harris 7 years ago
commit 3da8562688

2
package-lock.json generated

@ -1,6 +1,6 @@
{ {
"name": "svelte", "name": "svelte",
"version": "3.0.0-beta.20", "version": "3.0.0-beta.21",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

@ -1,6 +1,6 @@
{ {
"name": "svelte", "name": "svelte",
"version": "3.0.0-beta.20", "version": "3.0.0-beta.21",
"description": "The magical disappearing UI framework", "description": "The magical disappearing UI framework",
"module": "index.mjs", "module": "index.mjs",
"main": "index", "main": "index",

@ -121,7 +121,7 @@ function MoreRealisticComponent(props) {
<p>Selected {selected ? selected.name : 'nothing'}</p> <p>Selected {selected ? selected.name : 'nothing'}</p>
<ul> <ul>
${props.items.map(item => {props.items.map(item =>
<li> <li>
<button onClick={() => setSelected(item)}> <button onClick={() => setSelected(item)}>
{item.name} {item.name}
@ -147,4 +147,4 @@ Svelte is explicitly designed to prevent you from ending up in that situation.
It's important to understand that virtual DOM *isn't a feature*. It's a means to an end, the end being declarative, state-driven UI development. Virtual DOM is valuable because it allows you to build apps without thinking about state transitions, with performance that is *generally good enough*. That means less buggy code, and more time spent on creative tasks instead of tedious ones. It's important to understand that virtual DOM *isn't a feature*. It's a means to an end, the end being declarative, state-driven UI development. Virtual DOM is valuable because it allows you to build apps without thinking about state transitions, with performance that is *generally good enough*. That means less buggy code, and more time spent on creative tasks instead of tedious ones.
But it turns out that we can achieve a similar programming model without using virtual DOM — and that's where Svelte comes in. But it turns out that we can achieve a similar programming model without using virtual DOM — and that's where Svelte comes in.

@ -109,8 +109,8 @@
<div> <div>
<video <video
poster="http://svelte-assets.surge.sh/caminandes-llamigos.jpg" poster="https://svelte-assets.surge.sh/caminandes-llamigos.jpg"
src="http://svelte-assets.surge.sh/caminandes-llamigos.mp4" src="https://svelte-assets.surge.sh/caminandes-llamigos.mp4"
on:mousemove={handleMousemove} on:mousemove={handleMousemove}
on:mousedown={handleMousedown} on:mousedown={handleMousedown}
></video> ></video>

@ -109,8 +109,8 @@
<div> <div>
<video <video
poster="http://svelte-assets.surge.sh/caminandes-llamigos.jpg" poster="https://svelte-assets.surge.sh/caminandes-llamigos.jpg"
src="http://svelte-assets.surge.sh/caminandes-llamigos.mp4" src="https://svelte-assets.surge.sh/caminandes-llamigos.mp4"
on:mousemove={handleMousemove} on:mousemove={handleMousemove}
on:mousedown={handleMousedown} on:mousedown={handleMousedown}
bind:currentTime={time} bind:currentTime={time}

@ -10,14 +10,13 @@
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { locate } from 'locate-character';
import { process_example } from '../../components/Repl/process_example.js'; import { process_example } from '../../components/Repl/process_example.js';
import AppControls from './_components/AppControls/index.svelte'; import AppControls from './_components/AppControls/index.svelte';
import Repl from '../../components/Repl/index.svelte'; import Repl from '../../components/Repl/index.svelte';
export let version, example, gist_id; export let version;
export let example;
console.log({ example }); export let gist_id;
let repl; let repl;
let gist; let gist;
@ -52,7 +51,7 @@
relaxed = false; relaxed = false;
fetch(`gist/${gist_id}`).then(r => r.json()).then(data => { fetch(`gist/${gist_id}`).then(r => r.json()).then(data => {
gist = data; gist = data;
const { id, description, files } = data; const { description, files } = data;
name = description; name = description;
@ -84,36 +83,28 @@
repl.set({ components }); repl.set({ components });
}); });
} } else {
}); relaxed = true;
fetch(`examples/${example}.json`).then(async response => {
if (response.ok) {
const data = await response.json();
function load_example(slug) { name = data.title;
console.log(`loading ${slug}`);
relaxed = true; const components = process_example(data.files);
fetch(`examples/${slug}.json`).then(async response => { repl.set({ components });
if (response.ok) {
const data = await response.json();
name = data.title;
const components = process_example(data.files);
repl.set({ components });
gist = null; gist = null;
} }
}); });
} }
});
function handle_fork(event) { function handle_fork(event) {
example = null; example = null;
gist = event.detail.gist; gist = event.detail.gist;
gist_id = gist.id; gist_id = gist.id;
} }
$: if (process.browser && example) {
load_example(example);
}
</script> </script>
<style> <style>
@ -134,7 +125,7 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
top: 0; top: 0;
z-index: 11; z-index: 111;
} }
.pane { width: 100%; height: 100% } .pane { width: 100%; height: 100% }

@ -648,7 +648,7 @@ export default class Component {
this.add_reference(name.slice(1)); this.add_reference(name.slice(1));
const variable = this.var_lookup.get(name.slice(1)); const variable = this.var_lookup.get(name.slice(1));
variable.subscribable = true; if (variable) variable.subscribable = true;
} else { } else {
this.add_var({ this.add_var({
name, name,
@ -1164,9 +1164,11 @@ export default class Component {
const variable = this.var_lookup.get(name); const variable = this.var_lookup.get(name);
if (!variable) return name; if (!variable) return name;
if (variable && variable.hoistable) return name;
this.add_reference(name); // TODO we can probably remove most other occurrences of this this.add_reference(name); // TODO we can probably remove most other occurrences of this
if (variable.hoistable) return name;
return `ctx.${name}`; return `ctx.${name}`;
} }

@ -493,11 +493,12 @@ export default class Element extends Node {
}); });
} }
if (check_type_attribute() !== 'checkbox') { const type = check_type_attribute();
component.error(binding, {
code: `invalid-binding`, if (type !== 'checkbox') {
message: `'${name}' binding can only be used with <input type="checkbox">` let message = `'${name}' binding can only be used with <input type="checkbox">`;
}); if (type === 'radio') message += ` — for <input type="radio">, use 'group' binding`;
component.error(binding, { code: `invalid-binding`, message });
} }
} else if (name === 'group') { } else if (name === 'group') {
if (this.name !== 'input') { if (this.name !== 'input') {
@ -512,14 +513,14 @@ export default class Element extends Node {
if (type !== 'checkbox' && type !== 'radio') { if (type !== 'checkbox' && type !== 'radio') {
component.error(binding, { component.error(binding, {
code: `invalid-binding`, code: `invalid-binding`,
message: `'checked' binding can only be used with <input type="checkbox"> or <input type="radio">` message: `'group' binding can only be used with <input type="checkbox"> or <input type="radio">`
}); });
} }
} else if (name == 'files') { } else if (name == 'files') {
if (this.name !== 'input') { if (this.name !== 'input') {
component.error(binding, { component.error(binding, {
code: `invalid-binding`, code: `invalid-binding`,
message: `'files' binding acn only be used with <input type="file">` message: `'files' is not a valid binding on <${this.name}> elements`
}); });
} }
@ -635,23 +636,6 @@ export default class Element extends Node {
}); });
} }
get_static_attribute_value(name: string) {
const attribute = this.attributes.find(
(attr: Attribute) => attr.type === 'Attribute' && attr.name.toLowerCase() === name
);
if (!attribute) return null;
if (attribute.is_true) return true;
if (attribute.chunks.length === 0) return '';
if (attribute.chunks.length === 1 && attribute.chunks[0].type === 'Text') {
return attribute.chunks[0].data;
}
return null;
}
is_media_node() { is_media_node() {
return this.name === 'audio' || this.name === 'video'; return this.name === 'audio' || this.name === 'video';
} }

@ -5,6 +5,7 @@ import Attribute from './Attribute';
export default class Slot extends Element { export default class Slot extends Element {
type: 'Element'; type: 'Element';
name: string; name: string;
slot_name: string;
attributes: Attribute[]; attributes: Attribute[];
children: Node[]; children: Node[];
@ -27,8 +28,8 @@ export default class Slot extends Element {
}); });
} }
const slot_name = attr.value[0].data; this.slot_name = attr.value[0].data;
if (slot_name === 'default') { if (this.slot_name === 'default') {
component.error(attr, { component.error(attr, {
code: `invalid-slot-name`, code: `invalid-slot-name`,
message: `default is a reserved word — it cannot be used as a slot name` message: `default is a reserved word — it cannot be used as a slot name`
@ -46,6 +47,8 @@ export default class Slot extends Element {
// validator.slots.add(slot_name); // validator.slots.add(slot_name);
}); });
if (!this.slot_name) this.slot_name = 'default';
// if (node.attributes.length === 0) && validator.slots.has('default')) { // if (node.attributes.length === 0) && validator.slots.has('default')) {
// validator.error(node, { // validator.error(node, {
// code: `duplicate-slot`, // code: `duplicate-slot`,
@ -53,21 +56,4 @@ export default class Slot extends Element {
// }); // });
// } // }
} }
get_static_attribute_value(name: string) {
const attribute = this.attributes.find(
attr => attr.name.toLowerCase() === name
);
if (!attribute) return null;
if (attribute.is_true) return true;
if (attribute.chunks.length === 0) return '';
if (attribute.chunks.length === 1 && attribute.chunks[0].type === 'Text') {
return attribute.chunks[0].data;
}
return null;
}
} }

@ -364,7 +364,18 @@ export default class Expression {
let body = code.slice(node.body.start, node.body.end).trim(); let body = code.slice(node.body.start, node.body.end).trim();
if (node.body.type !== 'BlockStatement') { if (node.body.type !== 'BlockStatement') {
if (pending_assignments.size > 0) { if (pending_assignments.size > 0) {
const insert = Array.from(pending_assignments).map(name => component.invalidate(name)).join('; '); const dependencies = new Set();
pending_assignments.forEach(name => {
if (template_scope.names.has(name)) {
template_scope.dependencies_for_name.get(name).forEach(dependency => {
dependencies.add(dependency);
});
} else {
dependencies.add(name);
}
});
const insert = Array.from(dependencies).map(name => component.invalidate(name)).join('; ');
pending_assignments = new Set(); pending_assignments = new Set();
component.has_reactive_assignments = true; component.has_reactive_assignments = true;

@ -37,17 +37,34 @@ export default class Node {
} }
} }
find_nearest(selector: RegExp) {
if (selector.test(this.type)) return this;
if (this.parent) return this.parent.find_nearest(selector);
}
get_static_attribute_value(name: string) {
const attribute = this.attributes.find(
(attr: Attribute) => attr.type === 'Attribute' && attr.name.toLowerCase() === name
);
if (!attribute) return null;
if (attribute.is_true) return true;
if (attribute.chunks.length === 0) return '';
if (attribute.chunks.length === 1 && attribute.chunks[0].type === 'Text') {
return attribute.chunks[0].data;
}
return null;
}
has_ancestor(type: string) { has_ancestor(type: string) {
return this.parent ? return this.parent ?
this.parent.type === type || this.parent.has_ancestor(type) : this.parent.type === type || this.parent.has_ancestor(type) :
false; false;
} }
find_nearest(selector: RegExp) {
if (selector.test(this.type)) return this;
if (this.parent) return this.parent.find_nearest(selector);
}
warn_if_empty_block() { warn_if_empty_block() {
if (!/Block$/.test(this.type) || !this.children) return; if (!/Block$/.test(this.type) || !this.children) return;
if (this.children.length > 1) return; if (this.children.length > 1) return;

@ -10,7 +10,6 @@ import add_to_set from '../utils/add_to_set';
import get_object from '../utils/get_object'; import get_object from '../utils/get_object';
import { extract_names } from '../utils/scope'; import { extract_names } from '../utils/scope';
import { nodes_match } from '../../utils/nodes_match'; import { nodes_match } from '../../utils/nodes_match';
import { sanitize } from '../../utils/names';
export default function dom( export default function dom(
component: Component, component: Component,
@ -305,8 +304,7 @@ export default function dom(
const reactive_stores = component.vars.filter(variable => variable.name[0] === '$' && variable.name[1] !== '$'); const reactive_stores = component.vars.filter(variable => variable.name[0] === '$' && variable.name[1] !== '$');
if (renderer.slots.size > 0) { if (renderer.slots.size > 0) {
const arr = Array.from(renderer.slots); filtered_declarations.push('$$slots', '$$scope');
filtered_declarations.push(...arr.map(name => `$$slot_${sanitize(name)}`), '$$scope');
} }
if (renderer.binding_groups.length > 0) { if (renderer.binding_groups.length > 0) {
@ -399,7 +397,7 @@ export default function dom(
${component.javascript} ${component.javascript}
${renderer.slots.size && `let { ${[...renderer.slots].map(name => `$$slot_${sanitize(name)}`).join(', ')}, $$scope } = $$props;`} ${renderer.slots.size && `let { $$slots = {}, $$scope } = $$props;`}
${renderer.binding_groups.length > 0 && `const $$binding_groups = [${renderer.binding_groups.map(_ => `[]`).join(', ')}];`} ${renderer.binding_groups.length > 0 && `const $$binding_groups = [${renderer.binding_groups.map(_ => `[]`).join(', ')}];`}

@ -207,8 +207,8 @@ export default class EachBlockWrapper extends Wrapper {
if (needs_anchor) { if (needs_anchor) {
block.add_element( block.add_element(
this.vars.anchor, this.vars.anchor,
`@comment()`, `@empty()`,
parent_nodes && `@comment()`, parent_nodes && `@empty()`,
parent_node parent_node
); );
} }
@ -300,8 +300,8 @@ export default class EachBlockWrapper extends Wrapper {
this.block.first = this.block.get_unique_name('first'); this.block.first = this.block.get_unique_name('first');
this.block.add_element( this.block.add_element(
this.block.first, this.block.first,
`@comment()`, `@empty()`,
parent_nodes && `@comment()`, parent_nodes && `@empty()`,
null null
); );
} }

@ -117,7 +117,7 @@ export default class AttributeWrapper {
updater = `@set_input_type(${element.var}, ${should_cache ? last : value});`; updater = `@set_input_type(${element.var}, ${should_cache ? last : value});`;
} else if (is_select_value_attribute) { } else if (is_select_value_attribute) {
// annoying special case // annoying special case
const is_multiple_select = element.get_static_attribute_value('multiple'); const is_multiple_select = element.node.get_static_attribute_value('multiple');
const i = block.get_unique_name('i'); const i = block.get_unique_name('i');
const option = block.get_unique_name('option'); const option = block.get_unique_name('option');

@ -153,7 +153,7 @@ export default class BindingWrapper {
break; break;
case 'value': case 'value':
if (parent.get_static_attribute_value('type') === 'file') { if (parent.node.get_static_attribute_value('type') === 'file') {
update_dom = null; update_dom = null;
} }
} }

@ -20,6 +20,7 @@ import add_event_handlers from '../shared/add_event_handlers';
import add_actions from '../shared/add_actions'; import add_actions from '../shared/add_actions';
import create_debugging_comment from '../shared/create_debugging_comment'; import create_debugging_comment from '../shared/create_debugging_comment';
import { get_context_merger } from '../shared/get_context_merger'; import { get_context_merger } from '../shared/get_context_merger';
import Slot from '../../../nodes/Slot';
const events = [ const events = [
{ {
@ -213,8 +214,7 @@ export default class ElementWrapper extends Wrapper {
const { renderer } = this; const { renderer } = this;
if (this.node.name === 'slot') { if (this.node.name === 'slot') {
const slotName = this.get_static_attribute_value('name') || 'default'; renderer.slots.add((this.node as Slot).slot_name);
renderer.slots.add(slotName);
} }
if (this.node.name === 'noscript') return; if (this.node.name === 'noscript') return;
@ -804,23 +804,6 @@ export default class ElementWrapper extends Wrapper {
}); });
} }
get_static_attribute_value(name: string) {
const attribute = this.node.attributes.find(
(attr: Attribute) => attr.type === 'Attribute' && attr.name.toLowerCase() === name
);
if (!attribute) return null;
if (attribute.is_true) return true;
if (attribute.chunks.length === 0) return '';
if (attribute.chunks.length === 1 && attribute.chunks[0].type === 'Text') {
return attribute.chunks[0].data;
}
return null;
}
add_css_class(class_name = this.component.stylesheet.id) { add_css_class(class_name = this.component.stylesheet.id) {
const class_attribute = this.attributes.find(a => a.name === 'class'); const class_attribute = this.attributes.find(a => a.name === 'class');
if (class_attribute && !class_attribute.is_true) { if (class_attribute && !class_attribute.is_true) {

@ -185,8 +185,8 @@ export default class IfBlockWrapper extends Wrapper {
if (needs_anchor) { if (needs_anchor) {
block.add_element( block.add_element(
anchor, anchor,
`@comment()`, `@empty()`,
parent_nodes && `@comment()`, parent_nodes && `@empty()`,
parent_node parent_node
); );
} }

@ -119,16 +119,19 @@ export default class InlineComponentWrapper extends Wrapper {
const uses_spread = !!this.node.attributes.find(a => a.is_spread); const uses_spread = !!this.node.attributes.find(a => a.is_spread);
const slot_props = Array.from(this.slots).map(([name, slot]) => `$$slot_${sanitize(name)}: [${slot.block.name}${slot.fn ? `, ${slot.fn}` : ''}]`); const slot_props = Array.from(this.slots).map(([name, slot]) => `${quote_name_if_necessary(name)}: [${slot.block.name}${slot.fn ? `, ${slot.fn}` : ''}]`);
if (slot_props.length > 0) slot_props.push(`$$scope: { ctx }`);
const initial_props = slot_props.length > 0
? [`$$slots: ${stringify_props(slot_props)}`, `$$scope: { ctx }`]
: [];
const attribute_object = uses_spread const attribute_object = uses_spread
? stringify_props(slot_props) ? stringify_props(initial_props)
: stringify_props( : stringify_props(
this.node.attributes.map(attr => `${quote_name_if_necessary(attr.name)}: ${attr.get_value(block)}`).concat(slot_props) this.node.attributes.map(attr => `${quote_name_if_necessary(attr.name)}: ${attr.get_value(block)}`).concat(initial_props)
); );
if (this.node.attributes.length || this.node.bindings.length || slot_props.length) { if (this.node.attributes.length || this.node.bindings.length || initial_props.length) {
if (!uses_spread && this.node.bindings.length === 0) { if (!uses_spread && this.node.bindings.length === 0) {
component_opts.push(`props: ${attribute_object}`); component_opts.push(`props: ${attribute_object}`);
} else { } else {

@ -4,7 +4,7 @@ import Block from '../Block';
import Slot from '../../nodes/Slot'; import Slot from '../../nodes/Slot';
import FragmentWrapper from './Fragment'; import FragmentWrapper from './Fragment';
import deindent from '../../utils/deindent'; import deindent from '../../utils/deindent';
import { sanitize } from '../../../utils/names'; import { sanitize, quote_prop_if_necessary } from '../../../utils/names';
import add_to_set from '../../utils/add_to_set'; import add_to_set from '../../utils/add_to_set';
import get_slot_data from '../../utils/get_slot_data'; import get_slot_data from '../../utils/get_slot_data';
import { stringify_props } from '../../utils/stringify_props'; import { stringify_props } from '../../utils/stringify_props';
@ -42,6 +42,10 @@ export default class SlotWrapper extends Wrapper {
}); });
block.add_dependencies(this.dependencies); block.add_dependencies(this.dependencies);
// we have to do this, just in case
block.add_intro();
block.add_outro();
} }
render( render(
@ -51,7 +55,7 @@ export default class SlotWrapper extends Wrapper {
) { ) {
const { renderer } = this; const { renderer } = this;
const slot_name = this.node.get_static_attribute_value('name') || 'default'; const { slot_name } = this.node;
renderer.slots.add(slot_name); renderer.slots.add(slot_name);
let get_slot_changes; let get_slot_changes;
@ -95,7 +99,7 @@ export default class SlotWrapper extends Wrapper {
const slot_definition = block.get_unique_name(`${sanitize(slot_name)}_slot`); const slot_definition = block.get_unique_name(`${sanitize(slot_name)}_slot`);
block.builders.init.add_block(deindent` block.builders.init.add_block(deindent`
const ${slot_definition} = ctx.$$slot_${sanitize(slot_name)}; const ${slot_definition} = ctx.$$slots${quote_prop_if_necessary(slot_name)};
const ${slot} = @create_slot(${slot_definition}, ctx, ${get_slot_context}); const ${slot} = @create_slot(${slot_definition}, ctx, ${get_slot_context});
`); `);
@ -137,6 +141,14 @@ export default class SlotWrapper extends Wrapper {
} }
`); `);
block.builders.intro.add_line(
`if (${slot} && ${slot}.i) ${slot}.i(#local);`
);
block.builders.outro.add_line(
`if (${slot} && ${slot}.o) ${slot}.o(#local);`
);
let update_conditions = [...this.dependencies].map(name => `changed.${name}`).join(' || '); let update_conditions = [...this.dependencies].map(name => `changed.${name}`).join(' || ');
if (this.dependencies.size > 1) update_conditions = `(${update_conditions})`; if (this.dependencies.size > 1) update_conditions = `(${update_conditions})`;

@ -53,8 +53,8 @@ export default class Wrapper {
if (needs_anchor) { if (needs_anchor) {
block.add_element( block.add_element(
anchor, anchor,
`@comment()`, `@empty()`,
parent_nodes && `@comment()`, parent_nodes && `@empty()`,
parent_node parent_node
); );
} }

@ -2,10 +2,7 @@ import { quote_prop_if_necessary } from '../../../utils/names';
import get_slot_data from '../../utils/get_slot_data'; import get_slot_data from '../../utils/get_slot_data';
export default function(node, renderer, options) { export default function(node, renderer, options) {
const name = node.attributes.find(attribute => attribute.name === 'name'); const prop = quote_prop_if_necessary(node.slot_name);
const slot_name = name && name.chunks[0].data || 'default';
const prop = quote_prop_if_necessary(slot_name);
const slot_data = get_slot_data(node.attributes, true); const slot_data = get_slot_data(node.attributes, true);

@ -50,8 +50,8 @@ export function space() {
return text(' '); return text(' ');
} }
export function comment() { export function empty() {
return document.createComment(''); return text('');
} }
export function listen(node, event, handler, options) { export function listen(node, event, handler, options) {

@ -191,8 +191,7 @@ export default function tag(parser: Parser) {
} }
if (name === 'svelte:component') { if (name === 'svelte:component') {
// TODO post v2, treat this just as any other attribute const index = element.attributes.findIndex(attr => attr.type === 'Attribute' && attr.name === 'this');
const index = element.attributes.findIndex(attr => attr.name === 'this');
if (!~index) { if (!~index) {
parser.error({ parser.error({
code: `missing-component-definition`, code: `missing-component-definition`,

@ -111,5 +111,9 @@ export function quote_prop_if_necessary(name: string) {
} }
export function sanitize(name: string) { export function sanitize(name: string) {
return name.replace(/[^a-zA-Z]+/g, '_').replace(/^_/, '').replace(/_$/, ''); return name
} .replace(/[^a-zA-Z0-9_]+/g, '_')
.replace(/^_/, '')
.replace(/_$/, '')
.replace(/^[0-9]/, '_$&');
}

@ -1,8 +1,9 @@
import { run_all, noop, get_store_value, safe_not_equal } from './internal'; import { run_all, noop, get_store_value, safe_not_equal } from './internal';
export function readable(start, value) { export function readable(value, start) {
const { set, subscribe } = writable(value, () => start(set)); return {
return { subscribe }; subscribe: writable(value, start).subscribe
};
} }
export function writable(value, start = noop) { export function writable(value, start = noop) {
@ -25,7 +26,7 @@ export function writable(value, start = noop) {
function subscribe(run, invalidate = noop) { function subscribe(run, invalidate = noop) {
const subscriber = [run, invalidate]; const subscriber = [run, invalidate];
subscribers.push(subscriber); subscribers.push(subscriber);
if (subscribers.length === 1) stop = start() || noop; if (subscribers.length === 1) stop = start(set) || noop;
run(value); run(value);
return () => { return () => {
@ -45,7 +46,7 @@ export function derive(stores, fn) {
const auto = fn.length < 2; const auto = fn.length < 2;
let value = {}; let value = {};
return readable(set => { return readable(undefined, set => {
let inited = false; let inited = false;
const values = []; const values = [];

@ -2,10 +2,10 @@
import { import {
SvelteComponent as SvelteComponent_1, SvelteComponent as SvelteComponent_1,
append, append,
comment,
destroy_each, destroy_each,
detach, detach,
element, element,
empty,
init, init,
insert, insert,
noop, noop,
@ -66,7 +66,7 @@ function create_fragment(ctx) {
each_blocks[i].c(); each_blocks[i].c();
} }
each_1_anchor = comment(); each_1_anchor = empty();
}, },
m(target, anchor) { m(target, anchor) {

@ -2,10 +2,10 @@
import { import {
SvelteComponent as SvelteComponent_1, SvelteComponent as SvelteComponent_1,
append, append,
comment,
destroy_each, destroy_each,
detach, detach,
element, element,
empty,
init, init,
insert, insert,
noop, noop,
@ -66,7 +66,7 @@ function create_fragment(ctx) {
each_blocks[i].c(); each_blocks[i].c();
} }
each_1_anchor = comment(); each_1_anchor = empty();
}, },
m(target, anchor) { m(target, anchor) {

@ -3,10 +3,10 @@ import {
SvelteComponent as SvelteComponent_1, SvelteComponent as SvelteComponent_1,
append, append,
blank_object, blank_object,
comment,
create_animation, create_animation,
detach, detach,
element, element,
empty,
fix_and_outro_and_destroy_block, fix_and_outro_and_destroy_block,
fix_position, fix_position,
init, init,
@ -89,7 +89,7 @@ function create_fragment(ctx) {
c() { c() {
for (i = 0; i < each_blocks.length; i += 1) each_blocks[i].c(); for (i = 0; i < each_blocks.length; i += 1) each_blocks[i].c();
each_1_anchor = comment(); each_1_anchor = empty();
}, },
m(target, anchor) { m(target, anchor) {

@ -3,10 +3,10 @@ import {
SvelteComponent as SvelteComponent_1, SvelteComponent as SvelteComponent_1,
append, append,
blank_object, blank_object,
comment,
destroy_block, destroy_block,
detach, detach,
element, element,
empty,
init, init,
insert, insert,
noop, noop,
@ -73,7 +73,7 @@ function create_fragment(ctx) {
c() { c() {
for (i = 0; i < each_blocks.length; i += 1) each_blocks[i].c(); for (i = 0; i < each_blocks.length; i += 1) each_blocks[i].c();
each_1_anchor = comment(); each_1_anchor = empty();
}, },
m(target, anchor) { m(target, anchor) {

@ -1,9 +1,9 @@
/* generated by Svelte vX.Y.Z */ /* generated by Svelte vX.Y.Z */
import { import {
SvelteComponent as SvelteComponent_1, SvelteComponent as SvelteComponent_1,
comment,
detach, detach,
element, element,
empty,
init, init,
insert, insert,
noop, noop,
@ -68,7 +68,7 @@ function create_fragment(ctx) {
return { return {
c() { c() {
if_block.c(); if_block.c();
if_block_anchor = comment(); if_block_anchor = empty();
}, },
m(target, anchor) { m(target, anchor) {

@ -1,9 +1,9 @@
/* generated by Svelte vX.Y.Z */ /* generated by Svelte vX.Y.Z */
import { import {
SvelteComponent as SvelteComponent_1, SvelteComponent as SvelteComponent_1,
comment,
detach, detach,
element, element,
empty,
init, init,
insert, insert,
noop, noop,
@ -40,7 +40,7 @@ function create_fragment(ctx) {
return { return {
c() { c() {
if (if_block) if_block.c(); if (if_block) if_block.c();
if_block_anchor = comment(); if_block_anchor = empty();
}, },
m(target, anchor) { m(target, anchor) {

@ -2,10 +2,10 @@
import { import {
SvelteComponent as SvelteComponent_1, SvelteComponent as SvelteComponent_1,
add_render_callback, add_render_callback,
comment,
create_in_transition, create_in_transition,
detach, detach,
element, element,
empty,
init, init,
insert, insert,
noop, noop,
@ -21,7 +21,7 @@ function create_if_block(ctx) {
return { return {
c() { c() {
if (if_block) if_block.c(); if (if_block) if_block.c();
if_block_anchor = comment(); if_block_anchor = empty();
}, },
m(target, anchor) { m(target, anchor) {
@ -98,7 +98,7 @@ function create_fragment(ctx) {
return { return {
c() { c() {
if (if_block) if_block.c(); if (if_block) if_block.c();
if_block_anchor = comment(); if_block_anchor = empty();
}, },
m(target, anchor) { m(target, anchor) {

@ -2,9 +2,9 @@
import { import {
SvelteComponent as SvelteComponent_1, SvelteComponent as SvelteComponent_1,
append, append,
comment,
detach, detach,
element, element,
empty,
init, init,
insert, insert,
noop, noop,
@ -153,7 +153,7 @@ function create_fragment(ctx) {
if (if_block3) if_block3.c(); if (if_block3) if_block3.c();
t7 = space(); t7 = space();
if (if_block4) if_block4.c(); if (if_block4) if_block4.c();
if_block4_anchor = comment(); if_block4_anchor = empty();
}, },
m(target, anchor) { m(target, anchor) {

@ -0,0 +1,8 @@
<div>
<slot name="header1" />
<slot name="-header2_" />
<slot name="3header" />
<slot name="_header4" />
<slot name="header-5" />
<slot name="header&5" />
</div>

@ -0,0 +1,12 @@
export default {
html: `
<div>
<h1 slot="header1">Header 1</h1>
<h2 slot="-header2_">Header 2</h2>
<h3 slot="3header">Header 3</h3>
<h4 slot="_header4">Header 4</h4>
<h5 slot="header-5">Header 5</h5>
<h5 slot="header&5">Header 5b</h5>
</div>
`
};

@ -0,0 +1,12 @@
<script>
import Nested from './Nested.svelte';
</script>
<Nested>
<h1 slot="header1">Header 1</h1>
<h2 slot="-header2_">Header 2</h2>
<h3 slot="3header">Header 3</h3>
<h4 slot="_header4">Header 4</h4>
<h5 slot="header-5">Header 5</h5>
<h5 slot="header&5">Header 5b</h5>
</Nested>

@ -4,4 +4,4 @@
export let test; export let test;
</script> </script>
<svelte:component this={Foo} bind:this={test}/> <svelte:component bind:this={test} this={Foo}/>

@ -0,0 +1,35 @@
export default {
html: `
<button>off</button>
<button>on</button>
<button>off</button>
<p>on: 1</p>
`,
async test({ assert, component, target, window }) {
const buttons = target.querySelectorAll('button');
const event = new window.MouseEvent('click');
await buttons[0].dispatchEvent(event);
assert.htmlEqual(target.innerHTML, `
<button>on</button>
<button>on</button>
<button>off</button>
<p>on: 2</p>
`);
await buttons[2].dispatchEvent(event);
assert.htmlEqual(target.innerHTML, `
<button>on</button>
<button>on</button>
<button>on</button>
<p>on: 3</p>
`);
assert.deepEqual(component.switches, [
{ on: true },
{ on: true },
{ on: true }
]);
}
};

@ -0,0 +1,15 @@
<script>
export let switches = [
{ on: false },
{ on: true },
{ on: false }
];
</script>
{#each switches as s}
<button on:click="{() => s.on = !s.on}">
{s.on ? 'on' : 'off'}
</button>
{/each}
<p>on: {switches.filter(s => !!s.on).length}</p>

@ -0,0 +1,3 @@
export default {
error: 'missingGlobal is not defined'
};

@ -0,0 +1,9 @@
<script>
export let visible;
</script>
<div>
{#if visible}
<slot/>
{/if}
</div>

@ -0,0 +1,26 @@
export default {
props: {
visible: false
},
html: `
<div></div>
`,
test({ assert, component, target, window, raf }) {
component.visible = true;
const p = target.querySelector('p');
assert.equal(p.foo, 0);
raf.tick(50);
assert.equal(p.foo, 0.5);
component.visible = false;
raf.tick(75);
assert.equal(p.foo, 0.25);
raf.tick(100);
assert.equal(p.foo, 0);
}
};

@ -0,0 +1,18 @@
<script>
import Nested from './Nested.svelte';
export let visible;
function foo(node, params) {
return {
duration: 100,
tick: t => {
node.foo = t;
}
};
}
</script>
<Nested {visible}>
<p transition:foo>slotted</p>
</Nested>

@ -66,7 +66,7 @@ describe('store', () => {
let running; let running;
let tick; let tick;
const store = readable(set => { const store = readable(undefined, set => {
tick = set; tick = set;
running = true; running = true;
@ -192,7 +192,7 @@ describe('store', () => {
describe('get', () => { describe('get', () => {
it('gets the current value of a store', () => { it('gets the current value of a store', () => {
const store = readable(() => {}, 42); const store = readable(42, () => {});
assert.equal(get(store), 42); assert.equal(get(store), 42);
}); });
}); });

@ -1,6 +1,16 @@
export default { export default {
test(assert, vars) { test(assert, vars) {
assert.deepEqual(vars, [ assert.deepEqual(vars, [
{
export_name: null,
injected: false,
module: false,
mutated: false,
name: 'hoistable_foo',
reassigned: false,
referenced: true,
writable: false
},
{ {
export_name: null, export_name: null,
injected: false, injected: false,

@ -1,5 +1,7 @@
<script> <script>
import hoistable_foo from '';
let foo; let foo;
</script> </script>
<div use:hoistable_foo/>
<div use:foo/> <div use:foo/>

@ -1,6 +1,16 @@
export default { export default {
test(assert, vars) { test(assert, vars) {
assert.deepEqual(vars, [ assert.deepEqual(vars, [
{
export_name: null,
injected: false,
module: false,
mutated: false,
name: 'hoistable_foo',
reassigned: false,
referenced: true,
writable: false
},
{ {
export_name: null, export_name: null,
injected: false, injected: false,

@ -1,7 +1,11 @@
<script> <script>
import hoistable_foo from '';
let foo; let foo;
</script> </script>
{#each [] as x (x)}
<div animate:hoistable_foo/>
{/each}
{#each [] as x (x)} {#each [] as x (x)}
<div animate:foo/> <div animate:foo/>
{/each} {/each}

@ -1,6 +1,36 @@
export default { export default {
test(assert, vars) { test(assert, vars) {
assert.deepEqual(vars, [ assert.deepEqual(vars, [
{
export_name: null,
injected: false,
module: false,
mutated: false,
name: 'hoistable_foo',
reassigned: false,
referenced: true,
writable: false
},
{
export_name: null,
injected: false,
module: false,
mutated: false,
name: 'hoistable_bar',
reassigned: false,
referenced: true,
writable: false
},
{
export_name: null,
injected: false,
module: false,
mutated: false,
name: 'hoistable_baz',
reassigned: false,
referenced: true,
writable: false
},
{ {
export_name: null, export_name: null,
injected: false, injected: false,

@ -1,9 +1,13 @@
<script> <script>
import { hoistable_foo, hoistable_bar, hoistable_baz } from '';
let foo; let foo;
let bar; let bar;
let baz; let baz;
</script> </script>
<div in:hoistable_foo/>
<div out:hoistable_bar/>
<div transition:hoistable_baz/>
<div in:foo/> <div in:foo/>
<div out:bar/> <div out:bar/>
<div transition:baz/> <div transition:baz/>

Loading…
Cancel
Save