Merge branch 'master' of github.com:sveltejs/svelte into tanhauhau/use-periscopic

pull/3785/head
Rich Harris 6 years ago
commit b44ee82464

@ -24,6 +24,7 @@ Also:
* Flush changes in newly attached block when using `{#await}` ([#3660](https://github.com/sveltejs/svelte/issues/3660))
* Throw exception immediately when calling `createEventDispatcher()` after component instantiation ([#3667](https://github.com/sveltejs/svelte/pull/3667))
* Fix globals shadowing contextual template scope ([#3674](https://github.com/sveltejs/svelte/issues/3674))
* Fix `<svelte:window>` bindings to stores ([#3832](https://github.com/sveltejs/svelte/issues/3832))
## 3.12.1

@ -60,6 +60,7 @@
"@types/node": "^8.10.53",
"@typescript-eslint/eslint-plugin": "^1.13.0",
"@typescript-eslint/parser": "^2.1.0",
"@rollup/plugin-replace": "^2.2.1",
"acorn": "^7.1.0",
"agadoo": "^1.1.0",
"c8": "^5.0.1",
@ -82,7 +83,6 @@
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-json": "^4.0.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-replace": "^2.2.0",
"rollup-plugin-sucrase": "^2.1.0",
"rollup-plugin-typescript": "^1.0.1",
"rollup-plugin-virtual": "^1.0.1",

@ -1,5 +1,5 @@
import fs from 'fs';
import replace from 'rollup-plugin-replace';
import replace from '@rollup/plugin-replace';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import json from 'rollup-plugin-json';

@ -43,8 +43,8 @@
width: 100%;
height: 100%;
background-color: #666;
-webkit-mask: url(logo-mask.svg) 50% 50% no-repeat;
mask: url(logo-mask.svg) 50% 50% no-repeat;
-webkit-mask: url(svelte-logo-mask.svg) 50% 50% no-repeat;
mask: url(svelte-logo-mask.svg) 50% 50% no-repeat;
}
</style>

@ -43,8 +43,8 @@
width: 100%;
height: 100%;
background-color: #666;
-webkit-mask: url(logo-mask.svg) 50% 50% no-repeat;
mask: url(logo-mask.svg) 50% 50% no-repeat;
-webkit-mask: url(svelte-logo-mask.svg) 50% 50% no-repeat;
mask: url(svelte-logo-mask.svg) 50% 50% no-repeat;
}
</style>

@ -43,8 +43,8 @@
width: 100%;
height: 100%;
background-color: #666;
-webkit-mask: url(logo-mask.svg) 50% 50% no-repeat;
mask: url(logo-mask.svg) 50% 50% no-repeat;
-webkit-mask: url(svelte-logo-mask.svg) 50% 50% no-repeat;
mask: url(svelte-logo-mask.svg) 50% 50% no-repeat;
}
</style>

@ -3,7 +3,6 @@
import flash from './flash.js';
export let todo;
export let toggle;
let div;

@ -5,7 +5,6 @@
import flash from './flash.js';
export let todo;
export let toggle;
let div;

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 103 124">
<path style="fill:black" d='M96.33,20.61C85.38,4.93,63.74.28,48.09,10.25L20.61,27.77A31.46,31.46,0,0,0,6.37,48.88,33.22,33.22,0,0,0,9.64,70.2,31.52,31.52,0,0,0,4.93,82a33.61,33.61,0,0,0,5.73,25.41c11,15.68,32.6,20.33,48.25,10.36l27.48-17.52a31.48,31.48,0,0,0,14.24-21.11A33.22,33.22,0,0,0,97.36,57.8,31.52,31.52,0,0,0,102.07,46a33.57,33.57,0,0,0-5.74-25.41
M45.41,108.86A21.81,21.81,0,0,1,22,100.18,20.2,20.2,0,0,1,18.53,84.9a19,19,0,0,1,.65-2.57l.52-1.58,1.41,1a35.32,35.32,0,0,0,10.75,5.37l1,.31-.1,1a6.2,6.2,0,0,0,1.11,4.08A6.57,6.57,0,0,0,41,95.19a6,6,0,0,0,1.68-.74L70.11,76.94a5.76,5.76,0,0,0,2.59-3.83,6.09,6.09,0,0,0-1-4.6,6.58,6.58,0,0,0-7.06-2.62,6.21,6.21,0,0,0-1.69.74L52.43,73.31a19.88,19.88,0,0,1-5.58,2.45,21.82,21.82,0,0,1-23.43-8.68A20.2,20.2,0,0,1,20,51.8a19,19,0,0,1,8.56-12.7L56,21.59a19.88,19.88,0,0,1,5.58-2.45A21.81,21.81,0,0,1,85,27.82,20.2,20.2,0,0,1,88.47,43.1a19,19,0,0,1-.65,2.57l-.52,1.58-1.41-1a35.32,35.32,0,0,0-10.75-5.37l-1-.31.1-1a6.2,6.2,0,0,0-1.11-4.08,6.57,6.57,0,0,0-7.06-2.62,6,6,0,0,0-1.68.74L36.89,51.06a5.71,5.71,0,0,0-2.58,3.83,6,6,0,0,0,1,4.6,6.58,6.58,0,0,0,7.06,2.62,6.21,6.21,0,0,0,1.69-.74l10.48-6.68a19.88,19.88,0,0,1,5.58-2.45,21.82,21.82,0,0,1,23.43,8.68A20.2,20.2,0,0,1,87,76.2a19,19,0,0,1-8.56,12.7L51,106.41a19.88,19.88,0,0,1-5.58,2.45' />
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

@ -3,6 +3,7 @@ import Stylesheet from './Stylesheet';
import { gather_possible_values, UNKNOWN } from './gather_possible_values';
import { CssNode } from './interfaces';
import Component from '../Component';
import Element from '../nodes/Element';
enum BlockAppliesToNode {
NotPossible,
@ -34,8 +35,8 @@ export default class Selector {
this.used = this.blocks[0].global;
}
apply(node: CssNode, stack: CssNode[]) {
const to_encapsulate: CssNode[] = [];
apply(node: Element, stack: Element[]) {
const to_encapsulate: any[] = [];
apply_selector(this.local_blocks.slice(), node, stack.slice(), to_encapsulate);
@ -132,7 +133,7 @@ export default class Selector {
}
}
function apply_selector(blocks: Block[], node: CssNode, stack: CssNode[], to_encapsulate: any[]): boolean {
function apply_selector(blocks: Block[], node: Element, stack: Element[], to_encapsulate: any[]): boolean {
const block = blocks.pop();
if (!block) return false;
@ -259,16 +260,84 @@ function attribute_matches(node: CssNode, name: string, expected_value: string,
const attr = node.attributes.find((attr: CssNode) => attr.name === name);
if (!attr) return false;
if (attr.is_true) return operator === null;
if (attr.chunks.length > 1) return true;
if (!expected_value) return true;
const value = attr.chunks[0];
if (!value) return false;
if (value.type === 'Text') return test_attribute(operator, expected_value, case_insensitive, value.data);
if (attr.chunks.length === 1) {
const value = attr.chunks[0];
if (!value) return false;
if (value.type === 'Text') return test_attribute(operator, expected_value, case_insensitive, value.data);
}
const possible_values = new Set();
gather_possible_values(value.node, possible_values);
let prev_values = [];
for (const chunk of attr.chunks) {
const current_possible_values = new Set();
if (chunk.type === 'Text') {
current_possible_values.add(chunk.data);
} else {
gather_possible_values(chunk.node, current_possible_values);
}
// impossible to find out all combinations
if (current_possible_values.has(UNKNOWN)) return true;
if (prev_values.length > 0) {
const start_with_space = [];
const remaining = [];
current_possible_values.forEach((current_possible_value: string) => {
if (/^\s/.test(current_possible_value)) {
start_with_space.push(current_possible_value);
} else {
remaining.push(current_possible_value);
}
});
if (remaining.length > 0) {
if (start_with_space.length > 0) {
prev_values.forEach(prev_value => possible_values.add(prev_value));
}
const combined = [];
prev_values.forEach((prev_value: string) => {
remaining.forEach((value: string) => {
combined.push(prev_value + value);
});
});
prev_values = combined;
start_with_space.forEach((value: string) => {
if (/\s$/.test(value)) {
possible_values.add(value);
} else {
prev_values.push(value);
}
});
continue;
} else {
prev_values.forEach(prev_value => possible_values.add(prev_value));
prev_values = [];
}
}
current_possible_values.forEach((current_possible_value: string) => {
if (/\s$/.test(current_possible_value)) {
possible_values.add(current_possible_value);
} else {
prev_values.push(current_possible_value);
}
});
if (prev_values.length < current_possible_values.size) {
prev_values.push(' ');
}
if (prev_values.length > 20) {
// might grow exponentially, bail out
return true;
}
}
prev_values.forEach(prev_value => possible_values.add(prev_value));
if (possible_values.has(UNKNOWN)) return true;
for (const value of possible_values) {

@ -151,6 +151,10 @@ export default class Element extends Node {
}
}
// Binding relies on Attribute, defer its evaluation
const order = ['Binding']; // everything else is -1
info.attributes.sort((a, b) => order.indexOf(a.type) - order.indexOf(b.type));
info.attributes.forEach(node => {
switch (node.type) {
case 'Action':

@ -1,8 +1,6 @@
import Node from './shared/Node';
import Expression from './shared/Expression';
import Component from '../Component';
import { b, x } from 'code-red';
import Block from '../render_dom/Block';
import { sanitize } from '../../utils/names';
import { Identifier } from 'estree';
@ -14,6 +12,7 @@ export default class EventHandler extends Node {
handler_name: Identifier;
uses_context = false;
can_make_passive = false;
reassigned?: boolean;
constructor(component: Component, parent, template_scope, info) {
super(component, parent, template_scope, info);
@ -22,7 +21,7 @@ export default class EventHandler extends Node {
this.modifiers = new Set(info.modifiers);
if (info.expression) {
this.expression = new Expression(component, this, template_scope, info.expression, true);
this.expression = new Expression(component, this, template_scope, info.expression);
this.uses_context = this.expression.uses_context;
if (/FunctionExpression/.test(info.expression.type) && info.expression.params.length === 0) {
@ -42,34 +41,12 @@ export default class EventHandler extends Node {
if (node && (node.type === 'FunctionExpression' || node.type === 'FunctionDeclaration' || node.type === 'ArrowFunctionExpression') && node.params.length === 0) {
this.can_make_passive = true;
}
this.reassigned = component.var_lookup.get(info.expression.name).reassigned;
}
}
} else {
const id = component.get_unique_name(`${sanitize(this.name)}_handler`);
component.add_var({
name: id.name,
internal: true,
referenced: true
});
component.partly_hoisted.push(b`
function ${id}(event) {
@bubble($$self, event);
}
`);
this.handler_name = id;
this.handler_name = component.get_unique_name(`${sanitize(this.name)}_handler`);
}
}
// TODO move this? it is specific to render-dom
render(block: Block) {
if (this.expression) {
return this.expression.manipulate(block);
}
// this.component.add_reference(this.handler_name);
return x`#ctx.${this.handler_name}`;
}
}

@ -203,13 +203,11 @@ export default class Block {
}
add_variable(id: Identifier, init?: Node) {
this.variables.forEach(v => {
if (v.id.name === id.name) {
throw new Error(
`Variable '${id.name}' already initialised with a different value`
);
}
});
if (this.variables.has(id.name)) {
throw new Error(
`Variable '${id.name}' already initialised with a different value`
);
}
this.variables.set(id.name, { id, init });
}
@ -376,6 +374,8 @@ export default class Block {
d: ${properties.destroy}
}`;
const block = dev && this.get_unique_name('block');
const body = b`
${Array.from(this.variables.values()).map(({ id, init }) => {
return init
@ -387,9 +387,15 @@ export default class Block {
${dev
? b`
const block = ${return_value};
@dispatch_dev("SvelteRegisterBlock", { block, id: ${this.name || 'create_fragment'}.name, type: "${this.type}", source: "${this.comment ? this.comment.replace(/"/g, '\\"') : ''}", ctx: #ctx });
return block;`
const ${block} = ${return_value};
@dispatch_dev("SvelteRegisterBlock", {
block: ${block},
id: ${this.name || 'create_fragment'}.name,
type: "${this.type}",
source: "${this.comment ? this.comment.replace(/"/g, '\\"') : ''}",
ctx: #ctx
});
return ${block};`
: b`
return ${return_value};`
}
@ -398,6 +404,21 @@ export default class Block {
return body;
}
has_content() {
return this.renderer.options.dev ||
this.first ||
this.event_listeners.length > 0 ||
this.chunks.intro.length > 0 ||
this.chunks.outro.length > 0 ||
this.chunks.create.length > 0 ||
this.chunks.hydrate.length > 0 ||
this.chunks.claim.length > 0 ||
this.chunks.mount.length > 0 ||
this.chunks.update.length > 0 ||
this.chunks.destroy.length > 0 ||
this.has_animation;
}
render() {
const key = this.key && this.get_unique_name('key');

@ -241,11 +241,16 @@ export default function dom(
args.push(x`$$props`, x`$$invalidate`);
}
body.push(b`
function create_fragment(#ctx) {
${block.get_contents()}
}
const has_create_fragment = block.has_content();
if (has_create_fragment) {
body.push(b`
function create_fragment(#ctx) {
${block.get_contents()}
}
`);
}
body.push(b`
${component.extract_javascript(component.ast.module)}
${component.fully_hoisted}
@ -437,7 +442,7 @@ export default function dom(
${css.code && b`this.shadowRoot.innerHTML = \`<style>${css.code.replace(/\\/g, '\\\\')}${options.dev ? `\n/*# sourceMappingURL=${css.map.toUrl()} */` : ''}</style>\`;`}
@init(this, { target: this.shadowRoot }, ${definition}, create_fragment, ${not_equal}, ${prop_names});
@init(this, { target: this.shadowRoot }, ${definition}, ${has_create_fragment ? 'create_fragment': 'null'}, ${not_equal}, ${prop_names});
${dev_props_check}
@ -489,7 +494,7 @@ export default function dom(
constructor(options) {
super(${options.dev && `options`});
${should_add_css && b`if (!@_document.getElementById("${component.stylesheet.id}-style")) ${add_css}();`}
@init(this, options, ${definition}, create_fragment, ${not_equal}, ${prop_names});
@init(this, options, ${definition}, ${has_create_fragment ? 'create_fragment': 'null'}, ${not_equal}, ${prop_names});
${options.dev && b`@dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "${name.name}", options, id: create_fragment.name });`}
${dev_props_check}

@ -3,21 +3,24 @@ import Wrapper from './shared/Wrapper';
import { b } from 'code-red';
import Body from '../../nodes/Body';
import { Identifier } from 'estree';
import EventHandler from './Element/EventHandler';
export default class BodyWrapper extends Wrapper {
node: Body;
render(block: Block, _parent_node: Identifier, _parent_nodes: Identifier) {
this.node.handlers.forEach(handler => {
const snippet = handler.render(block);
this.node.handlers
.map(handler => new EventHandler(handler, this))
.forEach(handler => {
const snippet = handler.get_snippet(block);
block.chunks.init.push(b`
@_document.body.addEventListener("${handler.name}", ${snippet});
`);
block.chunks.init.push(b`
@_document.body.addEventListener("${handler.node.name}", ${snippet});
`);
block.chunks.destroy.push(b`
@_document.body.removeEventListener("${handler.name}", ${snippet});
`);
});
block.chunks.destroy.push(b`
@_document.body.removeEventListener("${handler.node.name}", ${snippet});
`);
});
}
}

@ -0,0 +1,69 @@
import EventHandler from '../../../nodes/EventHandler';
import Wrapper from '../shared/Wrapper';
import Block from '../../Block';
import { b, x, p } from 'code-red';
const TRUE = x`true`;
const FALSE = x`false`;
export default class EventHandlerWrapper {
node: EventHandler;
parent: Wrapper;
constructor(node: EventHandler, parent: Wrapper) {
this.node = node;
this.parent = parent;
if (!node.expression) {
this.parent.renderer.component.add_var({
name: node.handler_name.name,
internal: true,
referenced: true,
});
this.parent.renderer.component.partly_hoisted.push(b`
function ${node.handler_name.name}(event) {
@bubble($$self, event);
}
`);
}
}
get_snippet(block) {
const snippet = this.node.expression ? this.node.expression.manipulate(block) : x`#ctx.${this.node.handler_name}`;
if (this.node.reassigned) {
block.maintain_context = true;
return x`function () { ${snippet}.apply(this, arguments); }`;
}
return snippet;
}
render(block: Block, target: string) {
let snippet = this.get_snippet(block);
if (this.node.modifiers.has('preventDefault')) snippet = x`@prevent_default(${snippet})`;
if (this.node.modifiers.has('stopPropagation')) snippet = x`@stop_propagation(${snippet})`;
if (this.node.modifiers.has('self')) snippet = x`@self(${snippet})`;
const args = [];
const opts = ['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`)} }`);
} else if (block.renderer.options.dev) {
args.push(FALSE);
}
if (block.renderer.options.dev) {
args.push(this.node.modifiers.has('stopPropagation') ? TRUE : FALSE);
args.push(this.node.modifiers.has('preventDefault') ? TRUE : FALSE);
}
block.event_listeners.push(
x`@listen(${target}, "${this.node.name}", ${snippet}, ${args})`
);
}
}

@ -24,6 +24,7 @@ import bind_this from '../shared/bind_this';
import { changed } from '../shared/changed';
import { is_head } from '../shared/is_head';
import { Identifier } from 'estree';
import EventHandler from './EventHandler';
const events = [
{
@ -113,6 +114,7 @@ export default class ElementWrapper extends Wrapper {
fragment: FragmentWrapper;
attributes: AttributeWrapper[];
bindings: Binding[];
event_handlers: EventHandler[];
class_dependencies: string[];
slot_block: Block;
@ -194,6 +196,8 @@ export default class ElementWrapper extends Wrapper {
// e.g. <audio bind:paused bind:currentTime>
this.bindings = this.node.bindings.map(binding => new Binding(block, binding, this));
this.event_handlers = this.node.handlers.map(event_handler => new EventHandler(event_handler, this));
if (node.intro || node.outro) {
if (node.intro) block.add_intro(node.intro.is_local);
if (node.outro) block.add_outro(node.outro.is_local);
@ -643,7 +647,7 @@ export default class ElementWrapper extends Wrapper {
}
add_event_handlers(block: Block) {
add_event_handlers(block, this.var, this.node.handlers);
add_event_handlers(block, this.var, this.event_handlers);
}
add_transitions(
@ -894,7 +898,7 @@ function to_html(wrappers: Array<ElementWrapper | TextWrapper | TagWrapper>, blo
attr.node.chunks.forEach(chunk => {
if (chunk.type === 'Text') {
state.quasi.value.raw += chunk.data;
state.quasi.value.raw += escape_html(chunk.data);
} else {
literal.quasis.push(state.quasi);
literal.expressions.push(chunk.manipulate(block));

@ -16,6 +16,7 @@ import is_dynamic from '../shared/is_dynamic';
import bind_this from '../shared/bind_this';
import { changed } from '../shared/changed';
import { Node, Identifier, ObjectExpression } from 'estree';
import EventHandler from '../Element/EventHandler';
export default class InlineComponentWrapper extends Wrapper {
var: Identifier;
@ -365,7 +366,8 @@ export default class InlineComponentWrapper extends Wrapper {
});
const munged_handlers = this.node.handlers.map(handler => {
let snippet = handler.render(block);
const event_handler = new EventHandler(handler, this);
let snippet = event_handler.get_snippet(block);
if (handler.modifiers.has('once')) snippet = x`@once(${snippet})`;
return b`${name}.$on("${handler.name}", ${snippet});`;
@ -396,12 +398,12 @@ export default class InlineComponentWrapper extends Wrapper {
`);
block.chunks.create.push(
b`if (${name}) ${name}.$$.fragment.c();`
b`if (${name}) @create_component(${name}.$$.fragment);`
);
if (parent_nodes && this.renderer.options.hydratable) {
block.chunks.claim.push(
b`if (${name}) ${name}.$$.fragment.l(${parent_nodes});`
b`if (${name}) @claim_component(${name}.$$.fragment, ${parent_nodes});`
);
}
@ -437,7 +439,7 @@ export default class InlineComponentWrapper extends Wrapper {
${munged_bindings}
${munged_handlers}
${name}.$$.fragment.c();
@create_component(${name}.$$.fragment);
@transition_in(${name}.$$.fragment, 1);
@mount_component(${name}, ${update_mount_node}, ${anchor});
} else {
@ -472,11 +474,11 @@ export default class InlineComponentWrapper extends Wrapper {
${munged_handlers}
`);
block.chunks.create.push(b`${name}.$$.fragment.c();`);
block.chunks.create.push(b`@create_component(${name}.$$.fragment);`);
if (parent_nodes && this.renderer.options.hydratable) {
block.chunks.claim.push(
b`${name}.$$.fragment.l(${parent_nodes});`
b`@claim_component(${name}.$$.fragment, ${parent_nodes});`
);
}

@ -8,6 +8,7 @@ import add_actions from './shared/add_actions';
import { changed } from './shared/changed';
import { Identifier } from 'estree';
import { TemplateNode } from '../../../interfaces';
import EventHandler from './Element/EventHandler';
const associated_events = {
innerWidth: 'resize',
@ -34,9 +35,11 @@ const readonly = new Set([
export default class WindowWrapper extends Wrapper {
node: Window;
handlers: EventHandler[];
constructor(renderer: Renderer, block: Block, parent: Wrapper, node: TemplateNode) {
super(renderer, block, parent, node);
this.handlers = this.node.handlers.map(handler => new EventHandler(handler, this));
}
render(block: Block, _parent_node: Identifier, _parent_nodes: Identifier) {
@ -47,7 +50,7 @@ export default class WindowWrapper extends Wrapper {
const bindings: Record<string, string> = {};
add_actions(component, block, '@_window', this.node.actions);
add_event_handlers(block, '@_window', this.node.handlers);
add_event_handlers(block, '@_window', this.handlers);
this.node.bindings.forEach(binding => {
// in dev mode, throw if read-only values are written to
@ -127,7 +130,7 @@ export default class WindowWrapper extends Wrapper {
component.partly_hoisted.push(b`
function ${id}() {
${props.map(prop => b`$$invalidate('${prop.name}', ${prop.name} = @_window.${prop.value});`)}
${props.map(prop => component.invalidate(prop.name, x`${prop.name} = @_window.${prop.value}`))}
}
`);
@ -167,7 +170,7 @@ export default class WindowWrapper extends Wrapper {
component.partly_hoisted.push(b`
function ${id}() {
$$invalidate('${name}', ${name} = @_navigator.onLine);
${component.invalidate(name, x`${name} = @_navigator.onLine`)}
}
`);

@ -5,6 +5,7 @@ import Block from '../../Block';
import MustacheTag from '../../../nodes/MustacheTag';
import RawMustacheTag from '../../../nodes/RawMustacheTag';
import { Node } from 'estree';
import { changed } from './changed';
export default class Tag extends Wrapper {
node: MustacheTag | RawMustacheTag;
@ -39,10 +40,7 @@ export default class Tag extends Wrapper {
if (this.node.should_cache) block.add_variable(value, snippet); // TODO may need to coerce snippet to string
if (dependencies.length > 0) {
let condition = x`#changed.${dependencies[0]}`;
for (let i = 1; i < dependencies.length; i += 1) {
condition = x`${condition} || #changed.${dependencies[i]}`;
}
let condition = changed(dependencies);
if (block.has_outros) {
condition = x`!#current || ${condition}`;

@ -1,39 +1,10 @@
import Block from '../../Block';
import EventHandler from '../../../nodes/EventHandler';
import { x, p } from 'code-red';
const TRUE = x`true`;
const FALSE = x`false`;
import EventHandler from '../Element/EventHandler';
export default function add_event_handlers(
block: Block,
target: string,
handlers: EventHandler[]
) {
handlers.forEach(handler => {
let snippet = handler.render(block);
if (handler.modifiers.has('preventDefault')) snippet = x`@prevent_default(${snippet})`;
if (handler.modifiers.has('stopPropagation')) snippet = x`@stop_propagation(${snippet})`;
if (handler.modifiers.has('self')) snippet = x`@self(${snippet})`;
const args = [];
const opts = ['passive', 'once', 'capture'].filter(mod => handler.modifiers.has(mod));
if (opts.length) {
args.push((opts.length === 1 && opts[0] === 'capture')
? TRUE
: x`{ ${opts.map(opt => p`${opt}: true`)} }`);
} else if (block.renderer.options.dev) {
args.push(FALSE);
}
if (block.renderer.options.dev) {
args.push(handler.modifiers.has('stopPropagation') ? TRUE : FALSE);
args.push(handler.modifiers.has('preventDefault') ? TRUE : FALSE);
}
block.event_listeners.push(
x`@listen(${target}, "${handler.name}", ${snippet}, ${args})`
);
});
handlers.forEach(handler => handler.render(block, target));
}

@ -1,7 +1,7 @@
export default function get_name_from_filename(filename: string) {
if (!filename) return null;
// eslint-disable-next-line no-useless-escape
const parts = filename.split(/[\/\\]/);
const parts = filename.split(/[/\\]/).map(encodeURI);
if (parts.length > 1) {
const index_match = parts[parts.length - 1].match(/^index(\.\w+)/);
@ -12,6 +12,7 @@ export default function get_name_from_filename(filename: string) {
}
const base = parts.pop()
.replace(/%/g, 'u')
.replace(/\.[^.]+$/, "")
.replace(/[^a-zA-Z_$0-9]+/g, '_')
.replace(/^_/, '')

@ -12,13 +12,15 @@ export function escape(data: string, { only_escape_at_symbol = false } = {}) {
}
const escaped = {
'"': '&quot;',
"'": '&#39;',
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
};
export function escape_html(html) {
return String(html).replace(/[&<>]/g, match => escaped[match]);
return String(html).replace(/["'&<>]/g, match => escaped[match]);
}
export function escape_template(str) {

@ -4,6 +4,21 @@ import { blank_object, is_function, run, run_all, noop, has_prop } from './utils
import { children } from './dom';
import { transition_in } from './transitions';
interface Fragment {
key: string|null;
first: null;
/* create */ c: () => void;
/* claim */ l: (nodes: any) => void;
/* hydrate */ h: () => void;
/* mount */ m: (target: HTMLElement, anchor: any) => void;
/* update */ p: (changed: any, ctx: any) => void;
/* measure */ r: () => void;
/* fix */ f: () => void;
/* animate */ a: () => void;
/* intro */ i: (local: any) => void;
/* outro */ o: (local: any) => void;
/* destroy */ d: (detaching: 0|1) => void;
}
// eslint-disable-next-line @typescript-eslint/class-name-casing
interface T$$ {
dirty: null;
@ -13,7 +28,7 @@ interface T$$ {
callbacks: any;
after_update: any[];
props: Record<string, 0 | string>;
fragment: null|any;
fragment: null|false|Fragment;
not_equal: any;
before_update: any[];
context: Map<any, any>;
@ -29,10 +44,18 @@ export function bind(component, name, callback) {
}
}
export function create_component(block) {
block && block.c();
}
export function claim_component(block, parent_nodes) {
block && block.l(parent_nodes);
}
export function mount_component(component, target, anchor) {
const { fragment, on_mount, on_destroy, after_update } = component.$$;
fragment.m(target, anchor);
fragment && fragment.m(target, anchor);
// onMount happens before the initial afterUpdate
add_render_callback(() => {
@ -51,15 +74,16 @@ export function mount_component(component, target, anchor) {
}
export function destroy_component(component, detaching) {
if (component.$$.fragment) {
run_all(component.$$.on_destroy);
const $$ = component.$$;
if ($$.fragment !== null) {
run_all($$.on_destroy);
component.$$.fragment.d(detaching);
$$.fragment && $$.fragment.d(detaching);
// TODO null out other refs, including component.$$ (but need to
// preserve final state?)
component.$$.on_destroy = component.$$.fragment = null;
component.$$.ctx = {};
$$.on_destroy = $$.fragment = null;
$$.ctx = {};
}
}
@ -115,15 +139,17 @@ export function init(component, options, instance, create_fragment, not_equal, p
$$.update();
ready = true;
run_all($$.before_update);
$$.fragment = create_fragment($$.ctx);
// `false` as a special case of no DOM component
$$.fragment = create_fragment ? create_fragment($$.ctx) : false;
if (options.target) {
if (options.hydrate) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
$$.fragment!.l(children(options.target));
$$.fragment && $$.fragment!.l(children(options.target));
} else {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
$$.fragment!.c();
$$.fragment && $$.fragment!.c();
}
if (options.intro) transition_in(component.$$.fragment);

@ -70,10 +70,10 @@ export function flush() {
}
function update($$) {
if ($$.fragment) {
if ($$.fragment !== null) {
$$.update($$.dirty);
run_all($$.before_update);
$$.fragment.p($$.dirty, $$.ctx);
$$.fragment && $$.fragment.p($$.dirty, $$.ctx);
$$.dirty = null;
$$.after_update.forEach(add_render_callback);

@ -1,4 +1,4 @@
import { cubicOut, cubicInOut } from 'svelte/easing';
import { cubicOut, cubicInOut, linear } from 'svelte/easing';
import { assign, is_function } from 'svelte/internal';
type EasingFunction = (t: number) => number;
@ -43,17 +43,20 @@ export function blur(node: Element, {
interface FadeParams {
delay: number;
duration: number;
easing: EasingFunction;
}
export function fade(node: Element, {
delay = 0,
duration = 400
duration = 400,
easing = linear
}: FadeParams): TransitionConfig {
const o = +getComputedStyle(node).opacity;
return {
delay,
duration,
easing,
css: t => `opacity: ${t * o}`
};
}

@ -0,0 +1,143 @@
export default {
warnings: [
{
code: 'css-unused-selector',
message: 'Unused CSS selector',
frame:
` 9: <style>
10: .foo {color: red;}
11: .fooaa {color: red;}
^
12: .foobb {color: red;}
13: .foocc {color: red;}`,
start: { line: 11, column: 2, character: 206 },
end: { line: 11, column: 8, character: 212 },
pos: 206,
},
{
code: 'css-unused-selector',
message: 'Unused CSS selector',
frame:
`10: .foo {color: red;}
11: .fooaa {color: red;}
12: .foobb {color: red;}
^
13: .foocc {color: red;}
14: .foodd {color: red;}`,
start: { line: 12, column: 2, character: 229 },
end: { line: 12, column: 8, character: 235 },
pos: 229,
},
{
code: 'css-unused-selector',
message: 'Unused CSS selector',
frame:
`12: .foobb {color: red;}
13: .foocc {color: red;}
14: .foodd {color: red;}
^
15: .aa {color: red;}
16: .bb {color: red;}`,
start: { line: 14, column: 2, character: 275 },
end: { line: 14, column: 8, character: 281 },
pos: 275,
},
{
code: 'css-unused-selector',
message: 'Unused CSS selector',
frame:
`18: .dd {color: red;}
19: .aabar {color: red;}
20: .bbbar {color: red;}
^
21: .ccbar {color: red;}
22: .ddbar {color: red;}`,
start: { line: 20, column: 2, character: 401 },
end: { line: 20, column: 8, character: 407 },
pos: 401,
},
{
code: 'css-unused-selector',
message: 'Unused CSS selector',
frame:
`19: .aabar {color: red;}
20: .bbbar {color: red;}
21: .ccbar {color: red;}
^
22: .ddbar {color: red;}
23: .fooaabar {color: red;}`,
start: { line: 21, column: 2, character: 424 },
end: { line: 21, column: 8, character: 430 },
pos: 424,
},
{
code: 'css-unused-selector',
message: 'Unused CSS selector',
frame:
`20: .bbbar {color: red;}
21: .ccbar {color: red;}
22: .ddbar {color: red;}
^
23: .fooaabar {color: red;}
24: .foobbbar {color: red;}`,
start: { line: 22, column: 2, character: 447 },
end: { line: 22, column: 8, character: 453 },
pos: 447,
},
{
code: 'css-unused-selector',
message: 'Unused CSS selector',
frame:
`21: .ccbar {color: red;}
22: .ddbar {color: red;}
23: .fooaabar {color: red;}
^
24: .foobbbar {color: red;}
25: .fooccbar {color: red;}`,
start: { line: 23, column: 2, character: 470 },
end: { line: 23, column: 11, character: 479 },
pos: 470,
},
{
code: 'css-unused-selector',
message: 'Unused CSS selector',
frame:
`22: .ddbar {color: red;}
23: .fooaabar {color: red;}
24: .foobbbar {color: red;}
^
25: .fooccbar {color: red;}
26: .fooddbar {color: red;}`,
start: { line: 24, column: 2, character: 496 },
end: { line: 24, column: 11, character: 505 },
pos: 496,
},
{
code: 'css-unused-selector',
message: 'Unused CSS selector',
frame:
`23: .fooaabar {color: red;}
24: .foobbbar {color: red;}
25: .fooccbar {color: red;}
^
26: .fooddbar {color: red;}
27: .baz {color: red;}`,
start: { line: 25, column: 2, character: 522 },
end: { line: 25, column: 11, character: 531 },
pos: 522,
},
{
code: 'css-unused-selector',
message: 'Unused CSS selector',
frame:
`26: .fooddbar {color: red;}
27: .baz {color: red;}
28: .unused {color: red;}
^
29: </style>`,
start: { line: 28, column: 2, character: 595 },
end: { line: 28, column: 9, character: 602 },
pos: 595,
},
],
};

@ -0,0 +1 @@
.foo.svelte-xyz{color:red}.foocc.svelte-xyz{color:red}.aa.svelte-xyz{color:red}.bb.svelte-xyz{color:red}.cc.svelte-xyz{color:red}.dd.svelte-xyz{color:red}.aabar.svelte-xyz{color:red}.fooddbar.svelte-xyz{color:red}.baz.svelte-xyz{color:red}

@ -0,0 +1,29 @@
<script>
export let a, b, c;
</script>
<div class="foo{a ? ' aa' : b ? ' bb ' : c ? 'cc ' : 'dd'}bar baz {a ? ' aa' : b ? ' bb ' : c ? 'cc ' : 'dd'}">
some stuff
</div>
<style>
.foo {color: red;}
.fooaa {color: red;}
.foobb {color: red;}
.foocc {color: red;}
.foodd {color: red;}
.aa {color: red;}
.bb {color: red;}
.cc {color: red;}
.dd {color: red;}
.aabar {color: red;}
.bbbar {color: red;}
.ccbar {color: red;}
.ddbar {color: red;}
.fooaabar {color: red;}
.foobbbar {color: red;}
.fooccbar {color: red;}
.fooddbar {color: red;}
.baz {color: red;}
.unused {color: red;}
</style>

@ -0,0 +1,3 @@
export default {
warnings: [],
};

@ -0,0 +1 @@
.thing.svelte-xyz{color:blue}.active.svelte-xyz{color:blue}.thing.active.svelte-xyz{color:blue}.hover.svelte-xyz{color:blue}.hover.unused.svelte-xyz{color:blue}.unused.svelte-xyz{color:blue}

@ -0,0 +1,18 @@
<script>
export let active;
export let hover;
</script>
<div class="thing {active ? 'active' : hover}">
some stuff
</div>
<style>
.thing {color: blue;}
.active {color: blue;}
.thing.active {color: blue;}
.hover { color: blue; }
.hover.unused { color: blue; }
.unused {color: blue;}
</style>

@ -0,0 +1,25 @@
export default {
warnings: [
{
code: 'css-unused-selector',
end: {
character: 205,
column: 9,
line: 14,
},
frame: `
12: .thing.active {color: blue;}
13:
14: .unused {color: blue;}
^
15: </style>`,
message: 'Unused CSS selector',
pos: 198,
start: {
character: 198,
column: 2,
line: 14,
},
},
],
};

@ -0,0 +1 @@
.thing.svelte-xyz{color:blue}.active.svelte-xyz{color:blue}.thing.active.svelte-xyz{color:blue}

@ -0,0 +1,15 @@
<script>
export let active;
</script>
<div class="thing {active ? 'active' : ''}">
some stuff
</div>
<style>
.thing {color: blue;}
.active {color: blue;}
.thing.active {color: blue;}
.unused {color: blue;}
</style>

@ -0,0 +1,31 @@
export default {
warnings: [
{
code: 'css-unused-selector',
message: 'Unused CSS selector',
frame: `
13: .thing.active {color: blue;}
14: .hover { color: blue; }
15: .hover.unused { color: blue; }
^
16:
17: .unused {color: blue;}`,
start: { line: 15, column: 2, character: 261 },
end: { line: 15, column: 15, character: 274 },
pos: 261,
},
{
code: 'css-unused-selector',
message: 'Unused CSS selector',
frame: `
15: .hover.unused { color: blue; }
16:
17: .unused {color: blue;}
^
18: </style>`,
start: { line: 17, column: 2, character: 295 },
end: { line: 17, column: 9, character: 302 },
pos: 295,
},
],
};

@ -0,0 +1 @@
.thing.svelte-xyz{color:blue}.active.svelte-xyz{color:blue}.thing.active.svelte-xyz{color:blue}.hover.svelte-xyz{color:blue}

@ -0,0 +1,18 @@
<script>
export let active;
export let hover;
</script>
<div class="thing {active ? 'active' : hover ? 'hover' : ''}">
some stuff
</div>
<style>
.thing {color: blue;}
.active {color: blue;}
.thing.active {color: blue;}
.hover { color: blue; }
.hover.unused { color: blue; }
.unused {color: blue;}
</style>

@ -52,12 +52,19 @@ global.document = window.document;
global.navigator = window.navigator;
global.getComputedStyle = window.getComputedStyle;
global.requestAnimationFrame = null; // placeholder, filled in using set_raf
global.window = window;
// add missing ecmascript globals to window
for (const key of Object.getOwnPropertyNames(global)) {
window[key] = window[key] || global[key];
}
// implement mock scroll
window.scrollTo = function(pageXOffset, pageYOffset) {
window.pageXOffset = pageXOffset;
window.pageYOffset = pageYOffset;
};
export function env() {
window.document.title = '';
window.document.body.innerHTML = '<main></main>';
@ -204,3 +211,25 @@ export function spaces(i) {
while (i--) result += ' ';
return result;
}
// fake timers
const original_set_timeout = global.setTimeout;
export function useFakeTimers() {
const callbacks = [];
global.setTimeout = function(fn) {
callbacks.push(fn);
};
return {
flush() {
callbacks.forEach(fn => fn());
callbacks.splice(0, callbacks.length);
},
removeFakeTimers() {
callbacks.splice(0, callbacks.length);
global.setTimeout = original_set_timeout;
}
};
}

@ -0,0 +1,82 @@
import {
SvelteComponent,
attr,
detach,
element,
init,
insert,
listen,
noop,
run_all,
safe_not_equal,
space
} from "svelte/internal";
function create_fragment(ctx) {
let input0;
let t;
let input1;
let dispose;
return {
c() {
input0 = element("input");
t = space();
input1 = element("input");
attr(input0, "type", "file");
attr(input1, "type", "file");
dispose = [
listen(input0, "change", ctx.input0_change_handler),
listen(input1, "change", ctx.input1_change_handler)
];
},
m(target, anchor) {
insert(target, input0, anchor);
insert(target, t, anchor);
insert(target, input1, anchor);
},
p: noop,
i: noop,
o: noop,
d(detaching) {
if (detaching) detach(input0);
if (detaching) detach(t);
if (detaching) detach(input1);
run_all(dispose);
}
};
}
function instance($$self, $$props, $$invalidate) {
let { files } = $$props;
function input0_change_handler() {
files = this.files;
$$invalidate("files", files);
}
function input1_change_handler() {
files = this.files;
$$invalidate("files", files);
}
$$self.$set = $$props => {
if ("files" in $$props) $$invalidate("files", files = $$props.files);
};
return {
files,
input0_change_handler,
input1_change_handler
};
}
class Component extends SvelteComponent {
constructor(options) {
super();
init(this, options, instance, create_fragment, safe_not_equal, { files: 0 });
}
}
export default Component;

@ -0,0 +1,6 @@
<script>
export let files;
</script>
<input type="file" bind:files>
<input bind:files type="file">

@ -1,5 +1,6 @@
import {
SvelteComponent,
create_component,
destroy_component,
init,
mount_component,
@ -15,7 +16,7 @@ function create_fragment(ctx) {
return {
c() {
nested.$$.fragment.c();
create_component(nested.$$.fragment);
},
m(target, anchor) {
mount_component(nested, target, anchor);

@ -1,5 +1,6 @@
import {
SvelteComponent,
create_component,
destroy_component,
init,
mount_component,
@ -15,7 +16,7 @@ function create_fragment(ctx) {
return {
c() {
nested.$$.fragment.c();
create_component(nested.$$.fragment);
},
m(target, anchor) {
mount_component(nested, target, anchor);

@ -1,5 +1,6 @@
import {
SvelteComponent,
create_component,
destroy_component,
init,
mount_component,
@ -15,7 +16,7 @@ function create_fragment(ctx) {
return {
c() {
nested.$$.fragment.c();
create_component(nested.$$.fragment);
},
m(target, anchor) {
mount_component(nested, target, anchor);

@ -1,5 +1,6 @@
import {
SvelteComponent,
create_component,
destroy_component,
detach,
element,
@ -28,9 +29,9 @@ function create_fragment(ctx) {
return {
c() {
foo.$$.fragment.c();
create_component(foo.$$.fragment);
t0 = space();
bar.$$.fragment.c();
create_component(bar.$$.fragment);
t1 = space();
input = element("input");
dispose = listen(input, "input", ctx.input_input_handler);

@ -1,5 +1,6 @@
import {
SvelteComponent,
create_component,
destroy_component,
init,
mount_component,
@ -15,7 +16,7 @@ function create_fragment(ctx) {
return {
c() {
nested.$$.fragment.c();
create_component(nested.$$.fragment);
},
m(target, anchor) {
mount_component(nested, target, anchor);

@ -2,24 +2,12 @@ import {
SvelteComponent,
component_subscribe,
init,
noop,
safe_not_equal,
set_store_value
} from "svelte/internal";
import { count } from "./store.js";
function create_fragment(ctx) {
return {
c: noop,
m: noop,
p: noop,
i: noop,
o: noop,
d: noop
};
}
function instance($$self, $$props, $$invalidate) {
let $count;
component_subscribe($$self, count, $$value => $$invalidate("$count", $count = $$value));
@ -34,7 +22,7 @@ function instance($$self, $$props, $$invalidate) {
class Component extends SvelteComponent {
constructor(options) {
super();
init(this, options, instance, create_fragment, safe_not_equal, { increment: 0 });
init(this, options, instance, null, safe_not_equal, { increment: 0 });
}
get increment() {

@ -1,15 +1,4 @@
import { SvelteComponent, init, noop, safe_not_equal } from "svelte/internal";
function create_fragment(ctx) {
return {
c: noop,
m: noop,
p: noop,
i: noop,
o: noop,
d: noop
};
}
import { SvelteComponent, init, safe_not_equal } from "svelte/internal";
function instance($$self, $$props, $$invalidate) {
let { x } = $$props;
@ -32,7 +21,7 @@ function instance($$self, $$props, $$invalidate) {
class Component extends SvelteComponent {
constructor(options) {
super();
init(this, options, instance, create_fragment, safe_not_equal, { x: 0, a: 0, b: 0 });
init(this, options, instance, null, safe_not_equal, { x: 0, a: 0, b: 0 });
}
get a() {

@ -1,17 +1,6 @@
import { SvelteComponent, init, noop, safe_not_equal } from "svelte/internal";
import { SvelteComponent, init, safe_not_equal } from "svelte/internal";
import { onMount } from "svelte";
function create_fragment(ctx) {
return {
c: noop,
m: noop,
p: noop,
i: noop,
o: noop,
d: noop
};
}
function instance($$self, $$props, $$invalidate) {
let { foo = "bar" } = $$props;
@ -29,7 +18,7 @@ function instance($$self, $$props, $$invalidate) {
class Component extends SvelteComponent {
constructor(options) {
super();
init(this, options, instance, create_fragment, safe_not_equal, { foo: 0 });
init(this, options, instance, null, safe_not_equal, { foo: 0 });
}
}

@ -1,5 +1,6 @@
import {
SvelteComponent,
create_component,
destroy_component,
init,
mount_component,
@ -17,7 +18,7 @@ function create_fragment(ctx) {
return {
c() {
lazyload.$$.fragment.c();
create_component(lazyload.$$.fragment);
},
m(target, anchor) {
mount_component(lazyload, target, anchor);

@ -0,0 +1,15 @@
import { SvelteComponent, init, safe_not_equal } from "svelte/internal";
function instance($$self) {
const a = 1 + 2;
return {};
}
class Component extends SvelteComponent {
constructor(options) {
super();
init(this, options, instance, null, safe_not_equal, {});
}
}
export default Component;

@ -0,0 +1,3 @@
<script>
const a = 1 + 2;
</script>

@ -0,0 +1,107 @@
import {
SvelteComponent,
append,
detach,
element,
init,
insert,
listen,
noop,
run_all,
safe_not_equal,
set_data,
space,
text
} from "svelte/internal";
function create_fragment(ctx) {
let p0;
let button0;
let t1;
let button1;
let t3;
let p1;
let t4;
let t5;
let button2;
let dispose;
return {
c() {
p0 = element("p");
button0 = element("button");
button0.textContent = "set handler 1";
t1 = space();
button1 = element("button");
button1.textContent = "set handler 2";
t3 = space();
p1 = element("p");
t4 = text(ctx.number);
t5 = space();
button2 = element("button");
button2.textContent = "click";
dispose = [
listen(button0, "click", ctx.updateHandler1),
listen(button1, "click", ctx.updateHandler2),
listen(button2, "click", function () {
ctx.clickHandler.apply(this, arguments);
})
];
},
m(target, anchor) {
insert(target, p0, anchor);
append(p0, button0);
append(p0, t1);
append(p0, button1);
insert(target, t3, anchor);
insert(target, p1, anchor);
append(p1, t4);
insert(target, t5, anchor);
insert(target, button2, anchor);
},
p(changed, new_ctx) {
ctx = new_ctx;
if (changed.number) set_data(t4, ctx.number);
},
i: noop,
o: noop,
d(detaching) {
if (detaching) detach(p0);
if (detaching) detach(t3);
if (detaching) detach(p1);
if (detaching) detach(t5);
if (detaching) detach(button2);
run_all(dispose);
}
};
}
function instance($$self, $$props, $$invalidate) {
let clickHandler;
let number = 0;
function updateHandler1() {
$$invalidate("clickHandler", clickHandler = () => $$invalidate("number", number = 1));
}
function updateHandler2() {
$$invalidate("clickHandler", clickHandler = () => $$invalidate("number", number = 2));
}
return {
clickHandler,
number,
updateHandler1,
updateHandler2
};
}
class Component extends SvelteComponent {
constructor(options) {
super();
init(this, options, instance, create_fragment, safe_not_equal, {});
}
}
export default Component;

@ -0,0 +1,23 @@
<script>
let clickHandler;
let number = 0;
function updateHandler1(){
clickHandler = () => number = 1;
}
function updateHandler2(){
clickHandler = () => number = 2;
}
</script>
<p>
<button on:click={updateHandler1}>set handler 1</button>
<button on:click={updateHandler2}>set handler 2</button>
</p>
<p>{ number }</p>
<button on:click={clickHandler}>click</button>

@ -1,5 +1,6 @@
import {
SvelteComponent,
create_component,
destroy_component,
detach,
init,
@ -22,9 +23,9 @@ function create_fragment(ctx) {
return {
c() {
imported.$$.fragment.c();
create_component(imported.$$.fragment);
t = space();
nonimported.$$.fragment.c();
create_component(nonimported.$$.fragment);
},
m(target, anchor) {
mount_component(imported, target, anchor);

@ -1,15 +1,4 @@
import { SvelteComponent, init, noop, safe_not_equal } from "svelte/internal";
function create_fragment(ctx) {
return {
c: noop,
m: noop,
p: noop,
i: noop,
o: noop,
d: noop
};
}
import { SvelteComponent, init, safe_not_equal } from "svelte/internal";
function instance($$self, $$props, $$invalidate) {
let { x } = $$props;
@ -36,7 +25,7 @@ function instance($$self, $$props, $$invalidate) {
class Component extends SvelteComponent {
constructor(options) {
super();
init(this, options, instance, create_fragment, safe_not_equal, { x: 0 });
init(this, options, instance, null, safe_not_equal, { x: 0 });
}
}

@ -1,15 +1,4 @@
import { SvelteComponent, init, noop, safe_not_equal } from "svelte/internal";
function create_fragment(ctx) {
return {
c: noop,
m: noop,
p: noop,
i: noop,
o: noop,
d: noop
};
}
import { SvelteComponent, init, safe_not_equal } from "svelte/internal";
function instance($$self, $$props, $$invalidate) {
let { a = 1 } = $$props;
@ -32,7 +21,7 @@ function instance($$self, $$props, $$invalidate) {
class Component extends SvelteComponent {
constructor(options) {
super();
init(this, options, instance, create_fragment, safe_not_equal, { a: 0, b: 0 });
init(this, options, instance, null, safe_not_equal, { a: 0, b: 0 });
}
}

@ -1,16 +1,4 @@
import { SvelteComponent, init, noop, safe_not_equal } from "svelte/internal";
function create_fragment(ctx) {
return {
c: noop,
m: noop,
p: noop,
i: noop,
o: noop,
d: noop
};
}
import { SvelteComponent, init, safe_not_equal } from "svelte/internal";
const SOME_CONSTANT = 42;
function foo(bar) {
@ -20,7 +8,7 @@ function foo(bar) {
class Component extends SvelteComponent {
constructor(options) {
super();
init(this, options, null, create_fragment, safe_not_equal, { foo: 0 });
init(this, options, null, null, safe_not_equal, { foo: 0 });
}
get foo() {

@ -68,7 +68,7 @@ function instance($$self, $$props, $$invalidate) {
let { y } = $$props;
function onwindowscroll() {
$$invalidate("y", y = window.pageYOffset);
$$invalidate("y", y = window.pageYOffset)
}
$$self.$set = $$props => {

@ -190,7 +190,7 @@ describe("runtime", () => {
if (typeof config.error === 'function') {
config.error(assert, err);
} else {
assert.equal(config.error, err.message);
assert.equal(err.message, config.error);
}
} else {
throw err;

@ -1,3 +1,8 @@
export default {
html: `<span title='"foo"'>foo</span>`
html: `
<span title='"foo"'>
foo
<span title='"bar"'>bar</span>
</span>
`
};

@ -1 +1,4 @@
<span title='"foo"'>foo</span>
<span title='"foo"'>
foo
<span title='"bar"'>bar</span>
</span>

@ -1,5 +1,16 @@
export default {
skip: true, // JSDOM...
ssrHtml: `
<select value='hullo'>
<option value='hullo'>Hullo</option>
<option value='world'>World</option>
</select>
<select value='world'>
<option value='hullo'>Hullo</option>
<option value='world'>World</option>
</select>
`,
html: `
<select>

@ -1,3 +1,6 @@
<script>
export let items;
</script>
{#each items as item}
<select bind:value={item.value}>
<option value="hullo">Hullo</option>

@ -1,49 +1,58 @@
export default {
skip: true, // JSDOM
props: {
selected: [ 'two', 'three' ]
},
ssrHtml: `
<select multiple value="two,three">
<option value="one">one</option>
<option value="two">two</option>
<option value="three">three</option>
</select>
<p>selected: two, three</p>
`,
html: `
<select multiple>
<option>one</option>
<option>two</option>
<option>three</option>
<option value="one">one</option>
<option value="two">two</option>
<option value="three">three</option>
</select>
<p>selected: two, three</p>
`,
test({ assert, component, target, window }) {
async test({ assert, component, target, window }) {
const select = target.querySelector( 'select' );
const options = [ ...target.querySelectorAll( 'option' ) ];
const change = new window.Event( 'change' );
options[1].selected = false;
select.dispatchEvent( change );
await select.dispatchEvent( change );
assert.deepEqual( component.selected, [ 'three' ] );
assert.htmlEqual( target.innerHTML, `
<select multiple>
<option>one</option>
<option>two</option>
<option>three</option>
<option value="one">one</option>
<option value="two">two</option>
<option value="three">three</option>
</select>
<p>selected: three</p>
` );
options[0].selected = true;
select.dispatchEvent( change );
await select.dispatchEvent( change );
assert.deepEqual( component.selected, [ 'one', 'three' ] );
assert.htmlEqual( target.innerHTML, `
<select multiple>
<option>one</option>
<option>two</option>
<option>three</option>
<option value="one">one</option>
<option value="two">two</option>
<option value="three">three</option>
</select>
<p>selected: one, three</p>
@ -57,9 +66,9 @@ export default {
assert.htmlEqual( target.innerHTML, `
<select multiple>
<option>one</option>
<option>two</option>
<option>three</option>
<option value="one">one</option>
<option value="two">two</option>
<option value="three">three</option>
</select>
<p>selected: one, two</p>

@ -1,5 +1,15 @@
export default {
skip: true, // JSDOM
ssrHtml: `
<h1>Hello undefined!</h1>
<select>
<option value="Harry">Harry</option>
<optgroup label="Group">
<option value="World">World</option>
</optgroup>
</select>
`,
html: `
<h1>Hello Harry!</h1>
@ -12,17 +22,17 @@ export default {
</select>
`,
test({ assert, component, target, window }) {
async test({ assert, component, target, window }) {
const select = target.querySelector('select');
const options = [...target.querySelectorAll('option')];
assert.deepEqual(options, select.options);
assert.deepEqual(options, [...select.options]);
assert.equal(component.name, 'Harry');
const change = new window.Event('change');
options[1].selected = true;
select.dispatchEvent(change);
await select.dispatchEvent(change);
assert.equal(component.name, 'World');
assert.htmlEqual(target.innerHTML, `

@ -0,0 +1,18 @@
export default {
html: `
<button>update handler</button>
<button>0</button>
`,
async test({ assert, component, target, window }) {
const [updateButton, button] = target.querySelectorAll('button');
const event = new window.MouseEvent('click');
await button.dispatchEvent(event);
assert.equal(component.count, 1);
await updateButton.dispatchEvent(event);
await button.dispatchEvent(event);
assert.equal(component.count, 11);
}
};

@ -0,0 +1,11 @@
<script>
import Button from './Button.svelte';
export let count = 0;
let clickHandler = () => count += 1;
function updateHandler(){
clickHandler = () => count += 10;
}
</script>
<button on:click={updateHandler}>update handler</button>
<Button on:click={clickHandler}>{count}</Button>

@ -0,0 +1,18 @@
export default {
html: `
<button>update handler</button>
<button>0</button>
`,
async test({ assert, component, target, window }) {
const [updateButton, button] = target.querySelectorAll('button');
const event = new window.MouseEvent('click');
await updateButton.dispatchEvent(event);
await button.dispatchEvent(event);
assert.equal(component.count, 10);
await button.dispatchEvent(event);
assert.equal(component.count, 10);
}
};

@ -0,0 +1,11 @@
<script>
import Button from './Button.svelte';
export let count = 0;
let clickHandler = () => count += 1;
function updateHandler(){
clickHandler = () => count += 10;
}
</script>
<button on:click={updateHandler}>update handler</button>
<Button on:click|once={clickHandler}>{count}</Button>

@ -0,0 +1,3 @@
export default {
html: '',
};

@ -0,0 +1,3 @@
<script>
const a = 1 + 2;
</script>

@ -0,0 +1,50 @@
export default {
html: `
<p>
<button>set handler 1</button>
<button>set handler 2</button>
</p>
<p>0</p>
<button>click</button>
`,
async test({ assert, component, target, window }) {
const [updateButton1, updateButton2, button] = target.querySelectorAll(
'button'
);
const event = new window.MouseEvent('click');
await button.dispatchEvent(event);
assert.htmlEqual(target.innerHTML, `
<p>
<button>set handler 1</button>
<button>set handler 2</button>
</p>
<p>0</p>
<button>click</button>
`);
await updateButton1.dispatchEvent(event);
await button.dispatchEvent(event);
assert.htmlEqual(target.innerHTML, `
<p>
<button>set handler 1</button>
<button>set handler 2</button>
</p>
<p>1</p>
<button>click</button>
`);
await updateButton2.dispatchEvent(event);
await button.dispatchEvent(event);
assert.htmlEqual(target.innerHTML, `
<p>
<button>set handler 1</button>
<button>set handler 2</button>
</p>
<p>2</p>
<button>click</button>
`);
},
};

@ -0,0 +1,23 @@
<script>
let clickHandler;
let number = 0;
function updateHandler1(){
clickHandler = () => number = 1;
}
function updateHandler2(){
clickHandler = () => number = 2;
}
</script>
<p>
<button on:click={updateHandler1}>set handler 1</button>
<button on:click={updateHandler2}>set handler 2</button>
</p>
<p>{ number }</p>
<button on:click={clickHandler}>click</button>

@ -1,10 +1,37 @@
import { env, useFakeTimers } from "../../../helpers";
let clock;
export default {
skip: true, // JSDOM
before_test() {
clock = useFakeTimers();
const window = env();
Object.defineProperties(window, {
pageYOffset: {
value: 0,
configurable: true
},
pageXOffset: {
value: 0,
configurable: true
}
});
},
test({ assert, component, target, window }) {
after_test() {
clock.removeFakeTimers();
clock = null;
},
async test({ assert, component, target, window }) {
assert.equal(window.pageYOffset, 0);
// clear the previous 'scrolling' state
clock.flush();
component.scrollY = 100;
clock.flush();
assert.equal(window.pageYOffset, 100);
}
};
},
};

@ -1,16 +1,25 @@
export default {
html: `<div>1024x768</div>`,
skip: true, // some weird stuff happening with JSDOM 11
// skip: /^v4/.test(process.version), // node 4 apparently does some dumb stuff
before_test() {
Object.defineProperties(window, {
innerWidth: {
value: 1024,
configurable: true
},
innerHeight: {
value: 768,
configurable: true
}
});
},
skip_if_ssr: true, // there's some kind of weird bug with this test... it compiles with the wrong require.extensions hook for some bizarre reason
async test({ assert, component, target, window }) {
const event = new window.Event('resize');
// JSDOM executes window event listeners with `global` rather than
// `window` (bug?) so we need to do this
Object.defineProperties(global, {
Object.defineProperties(window, {
innerWidth: {
value: 567,
configurable: true

@ -0,0 +1,29 @@
export default {
skip_if_ssr: true,
before_test() {
Object.defineProperties(window, {
pageYOffset: {
value: 0,
configurable: true,
},
});
},
async test({ assert, component, target, window }) {
assert.equal(window.pageYOffset, 0);
const event = new window.Event('scroll');
Object.defineProperties(window, {
pageYOffset: {
value: 234,
configurable: true,
},
});
await window.dispatchEvent(event);
assert.htmlEqual(
target.innerHTML,
`<p style="position: fixed; top: 1em; left: 1em;">scroll\ny\nis\n234.\n234\n*\n234\n=\n54756</p><div style="height: 9999px;"></div>`
);
},
};

@ -0,0 +1,15 @@
<script>
import { writable, derived } from 'svelte/store';
const y = writable(0);
const y_squared = derived(y, $y => $y * $y);
</script>
<svelte:window bind:scrollY={$y}/>
<p style="position: fixed; top: 1em; left: 1em;">
scroll y is {$y}. {$y} * {$y} = {$y_squared}
</p>
<div style="height: 9999px">
</div>

@ -1,16 +1,12 @@
export default {
html: `<div>undefinedxundefined</div>`,
skip: true, // some weird stuff happening with JSDOM 11
// skip: /^v4/.test(process.version), // node 4 apparently does some dumb stuff
skip_if_ssr: true, // there's some kind of weird bug with this test... it compiles with the wrong require.extensions hook for some bizarre reason
async test({ assert, component, target, window }) {
const event = new window.Event('resize');
// JSDOM executes window event listeners with `global` rather than
// `window` (bug?) so we need to do this
Object.defineProperties(global, {
Object.defineProperties(window, {
innerWidth: {
value: 567,
configurable: true

@ -3,6 +3,6 @@
export let height;
</script>
<svelte:window on:resize='{() => width = this.innerWidth, height = this.innerHeight}'/>
<svelte:window on:resize={function () { width = this.innerWidth, height = this.innerHeight; }}/>
<div>{width}x{height}</div>

@ -138,7 +138,7 @@ describe("ssr", () => {
if (typeof config.error === 'function') {
config.error(assert, err);
} else {
assert.equal(config.error, err.message);
assert.equal(err.message, config.error);
}
} else {
showOutput(cwd, compileOptions);

Loading…
Cancel
Save