Merge remote-tracking branch 'upstream/master' into hmr-capture-state

pull/3822/head
rixo 6 years ago
commit e478e1f7b1

@ -1,5 +1,15 @@
# Svelte changelog
## Unreleased
* Prevent text input cursor jumping in Safari with one-way binding ([#3449](https://github.com/sveltejs/svelte/issues/3449))
## 3.16.7
* Also apply actions in the order they're given along with other directives ([#2446](https://github.com/sveltejs/svelte/issues/2446), [#4156](https://github.com/sveltejs/svelte/pull/4156))
* Check whether a dynamic event handler is a function before calling it ([#4090](https://github.com/sveltejs/svelte/issues/4090))
* Correctly mark event handlers as dynamic when they involve an expression used in a `bind:` elsewhere ([#4155](https://github.com/sveltejs/svelte/pull/4155))
## 3.16.6
* Fix CSS specificity bug when encapsulating styles ([#1277](https://github.com/sveltejs/svelte/issues/1277))

200
package-lock.json generated

@ -1,6 +1,6 @@
{
"name": "svelte",
"version": "3.16.6",
"version": "3.16.7",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -30,16 +30,113 @@
"integrity": "sha512-KioOCsSvSvXx6xUNLiJz+P+VMb7NRcePjoefOr74Y5P6lEKsiOn35eZyZzgpK4XCNJdXTDR7+zykj0lwxRvZ2g==",
"dev": true
},
"@rollup/plugin-commonjs": {
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-11.0.0.tgz",
"integrity": "sha512-jnm//T5ZWOZ6zmJ61fReSCBOif+Ax8dHVoVggA+d2NA7T4qCWgQ3KYr+zN2faGEYLpe1wa03IzvhR+sqVLxUWg==",
"dev": true,
"requires": {
"@rollup/pluginutils": "^3.0.0",
"estree-walker": "^0.6.1",
"is-reference": "^1.1.2",
"magic-string": "^0.25.2",
"resolve": "^1.11.0"
},
"dependencies": {
"estree-walker": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
"integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
"dev": true
}
}
},
"@rollup/plugin-json": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.0.1.tgz",
"integrity": "sha512-soxllkhOGgchswBAAaTe7X9G80U2tjjHvXv0sBrriLJcC/89PkP59iTrKPOfbz3SjX088mKDmMhAscuyLz8ZSg==",
"dev": true,
"requires": {
"rollup-pluginutils": "^2.5.0"
}
},
"@rollup/plugin-node-resolve": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-6.0.0.tgz",
"integrity": "sha512-GqWz1CfXOsqpeVMcoM315+O7zMxpRsmhWyhJoxLFHVSp9S64/u02i7len/FnbTNbmgYs+sZyilasijH8UiuboQ==",
"dev": true,
"requires": {
"@rollup/pluginutils": "^3.0.0",
"@types/resolve": "0.0.8",
"builtin-modules": "^3.1.0",
"is-module": "^1.0.0",
"resolve": "^1.11.1"
}
},
"@rollup/plugin-replace": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.2.1.tgz",
"integrity": "sha512-dgq5ijT8fK18KTb1inenZ61ivTayV7pvbz2+ivT+VN20BOgJVM1fqoBETqGHKgFVm/J9BhR82mQyAtxfpPv1lQ==",
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.3.0.tgz",
"integrity": "sha512-rzWAMqXAHC1w3eKpK6LxRqiF4f3qVFaa1sGii6Bp3rluKcwHNOpPt+hWRCmAH6SDEPtbPiLFf0pfNQyHs6Btlg==",
"dev": true,
"requires": {
"magic-string": "^0.25.2",
"rollup-pluginutils": "^2.6.0"
}
},
"@rollup/plugin-sucrase": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-sucrase/-/plugin-sucrase-3.0.0.tgz",
"integrity": "sha512-sUQkoAXdw+bnd/cNZHGy5yQKW6OYYU7QlYBGhReI95uZljxO8t1LlbqCO2viIMV/u9pcCjgi8N9PcApcrJCA8Q==",
"dev": true,
"requires": {
"@rollup/pluginutils": "^3.0.1",
"sucrase": "^3.10.1"
}
},
"@rollup/plugin-typescript": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-2.0.1.tgz",
"integrity": "sha512-UA/bN/DlHN19xdOllXmp7G7pM2ac9dQMg0q2T1rg4Bogzb7oHXj2WGafpiNpEm54PivcJdzGRJvRnI6zCISW3w==",
"dev": true,
"requires": {
"@rollup/pluginutils": "^3.0.0",
"resolve": "^1.12.2"
},
"dependencies": {
"resolve": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.14.1.tgz",
"integrity": "sha512-fn5Wobh4cxbLzuHaE+nphztHy43/b++4M6SsGFC2gB8uYwf0C8LcarfCz1un7UTW8OFQg9iNjZ4xpcFVGebDPg==",
"dev": true,
"requires": {
"path-parse": "^1.0.6"
}
}
}
},
"@rollup/plugin-virtual": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-2.0.0.tgz",
"integrity": "sha512-yUyQjcflsN1DGcUHj3I0NYL6Y6xrna6qjdaGjM93LjFLq8NFowhR0655ICeV9bNDbk+LI4pz7Q6xqeDdj1RdlA==",
"dev": true
},
"@rollup/pluginutils": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.0.1.tgz",
"integrity": "sha512-PmNurkecagFimv7ZdKCVOfQuqKDPkrcpLFxRBcQ00LYr4HAjJwhCFxBiY2Xoletll2htTIiXBg6g0Yg21h2M3w==",
"dev": true,
"requires": {
"estree-walker": "^0.6.1"
},
"dependencies": {
"estree-walker": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
"integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
"dev": true
}
}
},
"@types/eslint-visitor-keys": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
@ -1496,9 +1593,9 @@
"dev": true
},
"handlebars": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz",
"integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==",
"version": "4.5.3",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz",
"integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==",
"dev": true,
"requires": {
"neo-async": "^2.6.0",
@ -3058,85 +3155,14 @@
}
},
"rollup": {
"version": "1.21.4",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-1.21.4.tgz",
"integrity": "sha512-Pl512XVCmVzgcBz5h/3Li4oTaoDcmpuFZ+kdhS/wLreALz//WuDAMfomD3QEYl84NkDu6Z6wV9twlcREb4qQsw==",
"dev": true,
"requires": {
"@types/estree": "0.0.39",
"@types/node": "^12.7.5",
"acorn": "^7.0.0"
},
"dependencies": {
"@types/node": {
"version": "12.7.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.5.tgz",
"integrity": "sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w==",
"dev": true
}
}
},
"rollup-plugin-commonjs": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz",
"integrity": "sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q==",
"dev": true,
"requires": {
"estree-walker": "^0.6.1",
"is-reference": "^1.1.2",
"magic-string": "^0.25.2",
"resolve": "^1.11.0",
"rollup-pluginutils": "^2.8.1"
},
"dependencies": {
"estree-walker": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
"integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
"dev": true
}
}
},
"rollup-plugin-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/rollup-plugin-json/-/rollup-plugin-json-4.0.0.tgz",
"integrity": "sha512-hgb8N7Cgfw5SZAkb3jf0QXii6QX/FOkiIq2M7BAQIEydjHvTyxXHQiIzZaTFgx1GK0cRCHOCBHIyEkkLdWKxow==",
"dev": true,
"requires": {
"rollup-pluginutils": "^2.5.0"
}
},
"rollup-plugin-node-resolve": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz",
"integrity": "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==",
"version": "1.27.14",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-1.27.14.tgz",
"integrity": "sha512-DuDjEyn8Y79ALYXMt+nH/EI58L5pEw5HU9K38xXdRnxQhvzUTI/nxAawhkAHUQeudANQ//8iyrhVRHJBuR6DSQ==",
"dev": true,
"requires": {
"@types/resolve": "0.0.8",
"builtin-modules": "^3.1.0",
"is-module": "^1.0.0",
"resolve": "^1.11.1",
"rollup-pluginutils": "^2.8.1"
}
},
"rollup-plugin-sucrase": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/rollup-plugin-sucrase/-/rollup-plugin-sucrase-2.1.0.tgz",
"integrity": "sha512-chdA3OruR1FH/IIKrzZCpGKLXAx3DOHoK24RIPtlVccK0wbTpHE0HpGEQYCxte1XaB17NgRe/frFyKR7g45qxQ==",
"dev": true,
"requires": {
"rollup-pluginutils": "^2.3.0",
"sucrase": "3.x"
}
},
"rollup-plugin-typescript": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/rollup-plugin-typescript/-/rollup-plugin-typescript-1.0.1.tgz",
"integrity": "sha512-rwJDNn9jv/NsKZuyBb/h0jsclP4CJ58qbvZt2Q9zDIGILF2LtdtvCqMOL+Gq9IVq5MTrTlHZNrn8h7VjQgd8tw==",
"dev": true,
"requires": {
"resolve": "^1.10.0",
"rollup-pluginutils": "^2.5.0"
"@types/estree": "*",
"@types/node": "*",
"acorn": "^7.1.0"
}
},
"rollup-plugin-virtual": {
@ -3146,9 +3172,9 @@
"dev": true
},
"rollup-pluginutils": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.1.tgz",
"integrity": "sha512-J5oAoysWar6GuZo0s+3bZ6sVZAC0pfqKz68De7ZgDi5z63jOVZn1uJL/+z1jeKHNbGII8kAyHF5q8LnxSX5lQg==",
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
"integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
"dev": true,
"requires": {
"estree-walker": "^0.6.1"

@ -1,6 +1,6 @@
{
"name": "svelte",
"version": "3.16.6",
"version": "3.16.7",
"description": "Cybernetically enhanced web apps",
"module": "index.mjs",
"main": "index",
@ -56,7 +56,13 @@
},
"homepage": "https://github.com/sveltejs/svelte#README",
"devDependencies": {
"@rollup/plugin-replace": "^2.2.1",
"@rollup/plugin-commonjs": "^11.0.0",
"@rollup/plugin-json": "^4.0.1",
"@rollup/plugin-node-resolve": "^6.0.0",
"@rollup/plugin-replace": "^2.3.0",
"@rollup/plugin-sucrase": "^3.0.0",
"@rollup/plugin-typescript": "^2.0.1",
"@rollup/plugin-virtual": "^2.0.0",
"@types/mocha": "^5.2.7",
"@types/node": "^8.10.53",
"@typescript-eslint/eslint-plugin": "^1.13.0",
@ -79,13 +85,7 @@
"mocha": "^6.2.0",
"periscopic": "^2.0.1",
"puppeteer": "^1.19.0",
"rollup": "^1.21.4",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-json": "^4.0.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-sucrase": "^2.1.0",
"rollup-plugin-typescript": "^1.0.1",
"rollup-plugin-virtual": "^1.0.1",
"rollup": "^1.27.14",
"source-map": "^0.7.3",
"source-map-support": "^0.5.13",
"tiny-glob": "^0.2.6",

@ -1,10 +1,10 @@
import fs from 'fs';
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';
import sucrase from 'rollup-plugin-sucrase';
import typescript from 'rollup-plugin-typescript';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import json from '@rollup/plugin-json';
import sucrase from '@rollup/plugin-sucrase';
import typescript from '@rollup/plugin-typescript';
import pkg from './package.json';
const is_publish = !!process.env.PUBLISH;

@ -0,0 +1,26 @@
<script>
import contributors from '../_contributors.js';
</script>
<style>
.contributor {
width: 2.4em;
height: 2.4em;
border-radius: 50%;
text-indent: -9999px;
display: inline-block;
background: no-repeat url(/contributors.jpg);
background-size: auto 102%;
margin: 0 0.5em 0.5em 0;
border: 2px solid var(--second);
}
</style>
{#each contributors as contributor, i}
<a
class="contributor"
style="background-position: {(100 * i) / (contributors.length - 1)}% 0"
href="https://github.com/{contributor}">
{contributor}
</a>
{/each}

@ -1,9 +1,9 @@
<script>
import { Blurb, Hero, Section } from '@sveltejs/site-kit';
import Contributors from './_components/Contributors.svelte';
import Example from './_components/Example.svelte';
import WhosUsingSvelte from './_components/WhosUsingSvelte.svelte';
// import Lazy from '../components/Lazy.svelte';
import contributors from './_contributors.js';
// TODO this causes a Sapper CSS bug...
// function loadReplWidget() {
@ -24,18 +24,6 @@
color: white;
overflow: hidden;
}
.contributor {
width: 2.4em;
height: 2.4em;
border-radius: 50%;
text-indent: -9999px;
display: inline-block;
background: no-repeat url(/contributors.jpg);
background-size: auto 102%;
margin: 0 0.5em 0.5em 0;
border: 2px solid var(--second);
}
</style>
<svelte:head>
@ -128,11 +116,5 @@ npm run dev
<p>Svelte is free and open source software, made possible by the work of dozens of volunteers. <a href="https://github.com/sveltejs/svelte">Join us!</a></p>
{#each contributors as contributor, i}
<a
class="contributor"
style="background-position: {100 * i / (contributors.length - 1)}% 0"
href="https://github.com/{contributor}"
>{contributor}</a>
{/each}
<Contributors/>
</Section>

@ -73,6 +73,18 @@ export async function get(req, res) {
});
}
if (process.env.NODE_ENV === 'development') {
// In dev, proxy requests to load particular REPLs to the real server.
// This avoids needing to connect to the real database server.
req.pipe(
require('https').request({ host: 'svelte.dev', path: req.url })
).once('response', res_proxy => {
res_proxy.pipe(res);
res.writeHead(res_proxy.statusCode, res_proxy.headers);
}).once('error', () => res.end());
return;
}
const [row] = await query(`
select g.*, u.uid as owner from gists g
left join users u on g.user_id = u.id

@ -76,6 +76,8 @@ export default class AttributeWrapper {
const is_select_value_attribute =
name === 'value' && element.node.name === 'select';
const is_input_value = name === 'value' && element.node.name === 'input';
const should_cache = is_src || this.node.should_cache() || is_select_value_attribute; // TODO is this necessary?
const last = should_cache && block.get_unique_name(
@ -147,6 +149,14 @@ export default class AttributeWrapper {
: x`${condition} && (${last} !== (${last} = ${value}))`;
}
if (is_input_value) {
const type = element.node.get_static_attribute_value('type');
if (type === null || type === "" || type === "text" || type === "email" || type === "password") {
condition = x`${condition} && ${element.var}.${property_name} !== ${should_cache ? last : value}`;
}
}
if (block.has_outros) {
condition = x`!#current || ${condition}`;
}

@ -30,7 +30,7 @@ export default class EventHandlerWrapper {
if (this.node.reassigned) {
block.maintain_context = true;
return x`function () { ${snippet}.apply(this, arguments); }`;
return x`function () { if (@is_function(${snippet})) ${snippet}.apply(this, arguments); }`;
}
return snippet;
}

@ -16,8 +16,8 @@ import { dimensions } from '../../../../utils/patterns';
import Binding from './Binding';
import InlineComponentWrapper from '../InlineComponent';
import add_to_set from '../../../utils/add_to_set';
import add_event_handlers from '../shared/add_event_handlers';
import add_actions from '../shared/add_actions';
import { add_event_handler } from '../shared/add_event_handlers';
import { add_action } from '../shared/add_actions';
import create_debugging_comment from '../shared/create_debugging_comment';
import { get_slot_definition } from '../shared/get_slot_definition';
import bind_this from '../shared/bind_this';
@ -25,6 +25,7 @@ import { is_head } from '../shared/is_head';
import { Identifier } from 'estree';
import EventHandler from './EventHandler';
import { extract_names } from 'periscopic';
import Action from '../../../nodes/Action';
const events = [
{
@ -380,7 +381,6 @@ export default class ElementWrapper extends Wrapper {
this.add_directives_in_order(block);
this.add_transitions(block);
this.add_animation(block);
this.add_actions(block);
this.add_classes(block);
this.add_manual_style_scoping(block);
@ -441,6 +441,8 @@ export default class ElementWrapper extends Wrapper {
bindings: Binding[];
}
type OrderedAttribute = EventHandler | BindingGroup | Binding | Action;
const bindingGroups = events
.map(event => ({
events: event.event_names,
@ -452,29 +454,37 @@ export default class ElementWrapper extends Wrapper {
const this_binding = this.bindings.find(b => b.node.name === 'this');
function getOrder (item: EventHandler | BindingGroup | Binding) {
function getOrder (item: OrderedAttribute) {
if (item instanceof EventHandler) {
return item.node.start;
} else if (item instanceof Binding) {
return item.node.start;
} else if (item instanceof Action) {
return item.start;
} else {
return item.bindings[0].node.start;
}
}
const ordered: Array<EventHandler | BindingGroup | Binding> = [].concat(bindingGroups, this.event_handlers, this_binding).filter(Boolean);
ordered.sort((a, b) => getOrder(a) - getOrder(b));
ordered.forEach(bindingGroupOrEventHandler => {
if (bindingGroupOrEventHandler instanceof EventHandler) {
add_event_handlers(block, this.var, [bindingGroupOrEventHandler]);
} else if (bindingGroupOrEventHandler instanceof Binding) {
this.add_this_binding(block, bindingGroupOrEventHandler);
} else {
this.add_bindings(block, bindingGroupOrEventHandler);
}
});
([
...bindingGroups,
...this.event_handlers,
this_binding,
...this.node.actions
] as OrderedAttribute[])
.filter(Boolean)
.sort((a, b) => getOrder(a) - getOrder(b))
.forEach(item => {
if (item instanceof EventHandler) {
add_event_handler(block, this.var, item);
} else if (item instanceof Binding) {
this.add_this_binding(block, item);
} else if (item instanceof Action) {
add_action(block, this.var, item);
} else {
this.add_bindings(block, item);
}
});
}
add_bindings(block: Block, bindingGroup) {
@ -701,10 +711,6 @@ export default class ElementWrapper extends Wrapper {
`);
}
add_event_handlers(block: Block) {
add_event_handlers(block, this.var, this.event_handlers);
}
add_transitions(
block: Block
) {
@ -866,10 +872,6 @@ export default class ElementWrapper extends Wrapper {
`);
}
add_actions(block: Block) {
add_actions(block, this.var, this.node.actions);
}
add_classes(block: Block) {
const has_spread = this.node.attributes.some(attr => attr.is_spread);
this.node.classes.forEach(class_directive => {

@ -7,42 +7,40 @@ export default function add_actions(
target: string,
actions: Action[]
) {
actions.forEach(action => {
const { expression } = action;
let snippet;
let dependencies;
if (expression) {
snippet = expression.manipulate(block);
dependencies = expression.dynamic_dependencies();
}
actions.forEach(action => add_action(block, target, action));
}
const id = block.get_unique_name(
`${action.name.replace(/[^a-zA-Z0-9_$]/g, '_')}_action`
);
export function add_action(block: Block, target: string, action: Action) {
const { expression } = action;
let snippet;
let dependencies;
block.add_variable(id);
if (expression) {
snippet = expression.manipulate(block);
dependencies = expression.dynamic_dependencies();
}
const fn = block.renderer.reference(action.name);
const id = block.get_unique_name(
`${action.name.replace(/[^a-zA-Z0-9_$]/g, '_')}_action`
);
block.chunks.mount.push(
b`${id} = ${fn}.call(null, ${target}, ${snippet}) || {};`
);
block.add_variable(id);
const fn = block.renderer.reference(action.name);
if (dependencies && dependencies.length > 0) {
let condition = x`@is_function(${id}.update)`;
block.event_listeners.push(
x`@action_destroyer(${id} = ${fn}.call(null, ${target}, ${snippet}))`
);
if (dependencies.length > 0) {
condition = x`${condition} && ${block.renderer.dirty(dependencies)}`;
}
if (dependencies && dependencies.length > 0) {
let condition = x`${id} && @is_function(${id}.update)`;
block.chunks.update.push(
b`if (${condition}) ${id}.update.call(null, ${snippet});`
);
if (dependencies.length > 0) {
condition = x`${condition} && ${block.renderer.dirty(dependencies)}`;
}
block.chunks.destroy.push(
b`if (${id} && @is_function(${id}.destroy)) ${id}.destroy();`
block.chunks.update.push(
b`if (${condition}) ${id}.update.call(null, ${snippet});`
);
});
}
}

@ -6,5 +6,13 @@ export default function add_event_handlers(
target: string,
handlers: EventHandler[]
) {
handlers.forEach(handler => handler.render(block, target));
handlers.forEach(handler => add_event_handler(block, target, handler));
}
export function add_event_handler(
block: Block,
target: string,
handler: EventHandler
) {
handler.render(block, target);
}

@ -120,4 +120,8 @@ export function set_store_value(store, ret, value = ret) {
return ret;
}
export const has_prop = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
export const has_prop = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
export function action_destroyer(action_result) {
return action_result && is_function(action_result.destroy) ? action_result.destroy : noop;
}

@ -2,7 +2,7 @@ import * as fs from 'fs';
import * as path from 'path';
import * as http from 'http';
import { rollup } from 'rollup';
import * as virtual from 'rollup-plugin-virtual';
import * as virtual from '@rollup/plugin-virtual';
import * as puppeteer from 'puppeteer';
import { addLineNumbers, loadConfig, loadSvelte } from "../helpers.js";
import { deepEqual } from 'assert';

@ -1,6 +1,7 @@
/* generated by Svelte vX.Y.Z */
import {
SvelteComponent,
action_destroyer,
detach,
element,
init,
@ -13,24 +14,25 @@ import {
function create_fragment(ctx) {
let button;
let foo_action;
let dispose;
return {
c() {
button = element("button");
button.textContent = "foo";
dispose = action_destroyer(foo_action = foo.call(null, button, /*foo_function*/ ctx[1]));
},
m(target, anchor) {
insert(target, button, anchor);
foo_action = foo.call(null, button, /*foo_function*/ ctx[1]) || ({});
},
p(ctx, [dirty]) {
if (is_function(foo_action.update) && dirty & /*bar*/ 1) foo_action.update.call(null, /*foo_function*/ ctx[1]);
if (foo_action && is_function(foo_action.update) && dirty & /*bar*/ 1) foo_action.update.call(null, /*foo_function*/ ctx[1]);
},
i: noop,
o: noop,
d(detaching) {
if (detaching) detach(button);
if (foo_action && is_function(foo_action.destroy)) foo_action.destroy();
dispose();
}
};
}
@ -40,7 +42,7 @@ function handleFoo(bar) {
}
function foo(node, callback) {
}
function instance($$self, $$props, $$invalidate) {

@ -1,12 +1,12 @@
/* generated by Svelte vX.Y.Z */
import {
SvelteComponent,
action_destroyer,
attr,
detach,
element,
init,
insert,
is_function,
noop,
safe_not_equal
} from "svelte/internal";
@ -14,23 +14,24 @@ import {
function create_fragment(ctx) {
let a;
let link_action;
let dispose;
return {
c() {
a = element("a");
a.textContent = "Test";
attr(a, "href", "#");
dispose = action_destroyer(link_action = link.call(null, a));
},
m(target, anchor) {
insert(target, a, anchor);
link_action = link.call(null, a) || ({});
},
p: noop,
i: noop,
o: noop,
d(detaching) {
if (detaching) detach(a);
if (link_action && is_function(link_action.destroy)) link_action.destroy();
dispose();
}
};
}

@ -6,6 +6,7 @@ import {
element,
init,
insert,
is_function,
listen,
noop,
run_all,
@ -46,7 +47,7 @@ function create_fragment(ctx) {
listen(button0, "click", /*updateHandler1*/ ctx[2]),
listen(button1, "click", /*updateHandler2*/ ctx[3]),
listen(button2, "click", function () {
/*clickHandler*/ ctx[0].apply(this, arguments);
if (is_function(/*clickHandler*/ ctx[0])) /*clickHandler*/ ctx[0].apply(this, arguments);
})
];
},

@ -0,0 +1,77 @@
/* generated by Svelte vX.Y.Z */
import {
SvelteComponent,
append,
detach,
element,
init,
insert,
listen,
noop,
safe_not_equal,
set_data,
space,
text
} from "svelte/internal";
function create_fragment(ctx) {
let input;
let t0;
let h1;
let t1;
let t2;
let dispose;
return {
c() {
input = element("input");
t0 = space();
h1 = element("h1");
t1 = text(/*name*/ ctx[0]);
t2 = text("!");
input.value = /*name*/ ctx[0];
dispose = listen(input, "input", /*onInput*/ ctx[1]);
},
m(target, anchor) {
insert(target, input, anchor);
insert(target, t0, anchor);
insert(target, h1, anchor);
append(h1, t1);
append(h1, t2);
},
p(ctx, [dirty]) {
if (dirty & /*name*/ 1 && input.value !== /*name*/ ctx[0]) {
input.value = /*name*/ ctx[0];
}
if (dirty & /*name*/ 1) set_data(t1, /*name*/ ctx[0]);
},
i: noop,
o: noop,
d(detaching) {
if (detaching) detach(input);
if (detaching) detach(t0);
if (detaching) detach(h1);
dispose();
}
};
}
function instance($$self, $$props, $$invalidate) {
let name = "change me";
function onInput(event) {
$$invalidate(0, name = event.target.value);
}
return [name, onInput];
}
class Component extends SvelteComponent {
constructor(options) {
super();
init(this, options, instance, create_fragment, safe_not_equal, {});
}
}
export default Component;

@ -0,0 +1,11 @@
<script>
let name = 'change me';
function onInput(event) {
name = event.target.value
}
</script>
<input value={name} on:input={onInput}>
<h1>{name}!</h1>

@ -2,7 +2,7 @@ import * as assert from "assert";
import * as path from "path";
import * as fs from "fs";
import { rollup } from 'rollup';
import * as virtual from 'rollup-plugin-virtual';
import * as virtual from '@rollup/plugin-virtual';
import * as glob from 'tiny-glob/sync.js';
import { clear_loops, flush, set_now, set_raf } from "../../internal";

@ -0,0 +1,38 @@
const value = [];
export default {
props: {
value,
},
async test({ assert, component, target, window }) {
const inputs = target.querySelectorAll('input');
const event = new window.Event('input');
for (const input of inputs) {
input.value = 'h';
await input.dispatchEvent(event);
}
assert.deepEqual(value, [
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'10',
'11',
'12',
'13',
'14',
'15',
'16',
'17',
'18',
]);
},
};

@ -0,0 +1,34 @@
<script>
export let value = [];
function one(elem) { elem.addEventListener('input', () => { value.push('1'); }); }
function four(elem) { elem.addEventListener('input', () => { value.push('4'); }); }
function eight(elem) { elem.addEventListener('input', () => { value.push('8'); }); }
function twelve(elem) { elem.addEventListener('input', () => { value.push('12'); }); }
function fifteen(elem) { elem.addEventListener('input', () => { value.push('15'); }); }
function seventeen(elem) { elem.addEventListener('input', () => { value.push('17'); }); }
const foo = {
set two(v) { value.push('2'); },
set six(v) { value.push('6'); },
set nine(v) { value.push('9'); },
set eleven(v) { value.push('11'); },
set thirteen(v) { value.push('13'); },
set sixteen(v) { value.push('16'); },
}
function three() { value.push('3'); }
function five() { value.push('5'); }
function seven() { value.push('7'); }
function ten() { value.push('10'); }
function fourteen() { value.push('14'); }
function eighteen() { value.push('18'); }
</script>
<input use:one bind:value={foo.two} on:input={three} />
<input use:four on:input={five} bind:value={foo.six} />
<input on:input={seven} use:eight bind:value={foo.nine} />
<input on:input={ten} bind:value={foo.eleven} use:twelve />
<input bind:value={foo.thirteen} on:input={fourteen} use:fifteen />
<input bind:value={foo.sixteen} use:seventeen on:input={eighteen} />

@ -0,0 +1,56 @@
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');
let err = "";
window.addEventListener('error', (e) => {
e.preventDefault();
err = e.message;
});
await button.dispatchEvent(event);
assert.equal(err, "", err);
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.f = () => number = 1;
}
function updateHandler2(){
clickHandler.f = () => 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.f}>click</button>

@ -0,0 +1,28 @@
export default {
html: `<button>undef</button>
<button>null</button>
<button>invalid</button>`,
async test({ assert, component, target, window }) {
const [buttonUndef, buttonNull, buttonInvalid] = target.querySelectorAll(
'button'
);
const event = new window.MouseEvent('click');
let err = "";
window.addEventListener('error', (e) => {
e.preventDefault();
err = e.message;
});
// All three should not throw if proper checking is done in runtime code
await buttonUndef.dispatchEvent(event);
assert.equal(err, "", err);
await buttonNull.dispatchEvent(event);
assert.equal(err, "", err);
await buttonInvalid.dispatchEvent(event);
assert.equal(err, "", err);
},
};

@ -0,0 +1,13 @@
<script>
let handlerUndef;
let handlerNull;
let handlerInvalid;
handlerUndef = undefined;
handlerNull = null;
handlerInvalid = 42;
</script>
<button on:click={handlerUndef}>undef</button>
<button on:click={handlerNull}>null</button>
<button on:click={handlerInvalid}>invalid</button>

@ -0,0 +1,16 @@
export default {
html: `
<button>0</button>
`,
async test({ assert, component, target, window }) {
const button = target.querySelector('button');
const event = new window.MouseEvent('click');
await button.dispatchEvent(event);
assert.equal(component.count, 1);
await button.dispatchEvent(event);
assert.equal(component.count, 1);
}
};

@ -0,0 +1,7 @@
<script>
let f;
export let count = 0;
f = () => count += 1;
</script>
<button on:click|once="{f}">{count}</button>

@ -0,0 +1,16 @@
export default {
html: `
<button>click me</button>
`,
async test({ assert, component, target, window }) {
const button = target.querySelector('button');
const event = new window.MouseEvent('click', {
cancelable: true
});
await button.dispatchEvent(event);
assert.ok(component.default_was_prevented);
}
};

@ -0,0 +1,11 @@
<script>
export let default_was_prevented;
let f;
function handle_click(event) {
default_was_prevented = event.defaultPrevented;
}
f = handle_click;
</script>
<button on:click|preventDefault={f}>click me</button>

@ -0,0 +1,16 @@
export default {
html: `
<div>
<button>click me</button>
</div>
`,
async test({ assert, component, target, window }) {
const button = target.querySelector('button');
const event = new window.MouseEvent('click');
await button.dispatchEvent(event);
assert.ok(!component.inner_clicked);
},
};

@ -0,0 +1,13 @@
<script>
export let inner_clicked;
let f;
function handle_click(event) {
inner_clicked = true;
}
f = handle_click;
</script>
<div on:click|self={f}>
<button>click me</button>
</div>

@ -0,0 +1,19 @@
export default {
html: `
<div>
<button>click me</button>
</div>
`,
async test({ assert, component, target, window }) {
const button = target.querySelector('button');
const event = new window.MouseEvent('click', {
bubbles: true
});
await button.dispatchEvent(event);
assert.ok(component.inner_clicked);
assert.ok(!component.outer_clicked);
}
};

@ -0,0 +1,20 @@
<script>
export let inner_clicked;
export let outer_clicked;
let f1;
let f2;
function handle_inner_click(event) {
inner_clicked = true;
}
function handle_outer_click(event) {
outer_clicked = true;
}
f1 = handle_inner_click;
f2 = handle_outer_click;
</script>
<div on:click={f2}>
<button on:click|stopPropagation={f1}>click me</button>
</div>

@ -0,0 +1,14 @@
export default {
html: `
<button>click me</button>
`,
async test({ assert, component, target, window }) {
const button = target.querySelector('button');
const event = new window.MouseEvent('click');
await button.dispatchEvent(event);
assert.equal(component.clickHandlerOne, 1);
assert.equal(component.clickHandlerTwo, 1);
}
};

@ -0,0 +1,11 @@
<script>
export let clickHandlerOne = 0;
export let clickHandlerTwo = 0;
let f1;
let f2;
f1 = () => clickHandlerOne++;
f2 = () => clickHandlerTwo++;
</script>
<button on:click='{f1}' on:click='{f2}'>click me</button>

@ -14,8 +14,14 @@ export default {
);
const event = new window.MouseEvent('click');
let err = "";
window.addEventListener('error', (e) => {
e.preventDefault();
err = e.message;
});
await button.dispatchEvent(event);
assert.equal(err, "", err);
assert.htmlEqual(target.innerHTML, `
<p>
<button>set handler 1</button>
@ -24,7 +30,7 @@ export default {
<p>0</p>
<button>click</button>
`);
await updateButton1.dispatchEvent(event);
await button.dispatchEvent(event);
assert.htmlEqual(target.innerHTML, `
@ -35,7 +41,7 @@ export default {
<p>1</p>
<button>click</button>
`);
await updateButton2.dispatchEvent(event);
await button.dispatchEvent(event);
assert.htmlEqual(target.innerHTML, `

Loading…
Cancel
Save