Merge pull request #5 from sveltejs/master

Sync Fork from Upstream Repo
pull/3941/head
Stefan Hagen 6 years ago committed by GitHub
commit 3d50a212b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,6 +1,6 @@
# Svelte changelog
## Unreleased
## 3.13.0
* New structured code generation, which eliminates a number of edge cases and obscure bugs ([#3539](https://github.com/sveltejs/svelte/pull/3539))
@ -25,6 +25,23 @@ Also:
* 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))
* Deconflict generated var names with builtins ([#3724](https://github.com/sveltejs/svelte/issues/3724))
* Allow spring/tweened values to be initially undefined ([#3761](https://github.com/sveltejs/svelte/issues/3761))
* Warn if using `<svelte:options tag="...">` without `customElement: true` option ([#3782](https://github.com/sveltejs/svelte/pull/3782))
* Add `Event` to list of known globals ([#3810](https://github.com/sveltejs/svelte/pull/3810))
* Throw helpful error on empty CSS declaration ([#3801](https://github.com/sveltejs/svelte/issues/3801))
* Support `easing` param on `fade` transition ([#3823](https://github.com/sveltejs/svelte/pull/3823))
* Generate valid names from filenames with unicode characters ([#3845](https://github.com/sveltejs/svelte/issues/3845))
* Don't generate any code for markup-less components ([#2200](https://github.com/sveltejs/svelte/issues/2200))
* Deconflict with internal name `block` ([#3854](https://github.com/sveltejs/svelte/issues/3854))
* Set attributes before bindings, to prevent erroneous assignments to `input.files` ([#3828](https://github.com/sveltejs/svelte/issues/3828))
* Smarter unused CSS detection ([#3825](https://github.com/sveltejs/svelte/pull/3825))
* Allow dynamic event handlers ([#3040](https://github.com/sveltejs/svelte/issues/3040))
* Prevent erroneous `"undefined"` class name ([#3876](https://github.com/sveltejs/svelte/pull/3876))
* Prevent resetting of `src` attribute unless changed ([#3579](https://github.com/sveltejs/svelte/pull/3579))
* Prevent hydration of void element 'children' ([#3882](https://github.com/sveltejs/svelte/issues/3882))
* Hoist globals even if mentioned in `<script>` block ([#3745](https://github.com/sveltejs/svelte/pull/3745))
## 3.12.1

2
package-lock.json generated

@ -1,6 +1,6 @@
{
"name": "svelte",
"version": "3.13.0-alpha.2",
"version": "3.13.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

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

@ -1291,9 +1291,9 @@
}
},
"@sveltejs/svelte-repl": {
"version": "0.1.9",
"resolved": "https://registry.npmjs.org/@sveltejs/svelte-repl/-/svelte-repl-0.1.9.tgz",
"integrity": "sha512-OXDfHwT5O7UXVYnf4ndTk3dKMITTmWcMty4/lOFte80ui01i47QiVy3GEe9G8FkcU1YBe+c06MMnIgm7j0Ln7Q==",
"version": "0.1.11",
"resolved": "https://registry.npmjs.org/@sveltejs/svelte-repl/-/svelte-repl-0.1.11.tgz",
"integrity": "sha512-z0Cv9fNggmL6C2bphYa2A5Bku91U3ukCmJTh9pFS68X0sJxDFJPsBgxAmWhrOfOe7NdGvm/s+fBEOo8cce66/w==",
"dev": true,
"requires": {
"codemirror": "^5.48.4",
@ -1587,9 +1587,9 @@
"dev": true
},
"codemirror": {
"version": "5.48.4",
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.48.4.tgz",
"integrity": "sha512-pUhZXDQ6qXSpWdwlgAwHEkd4imA0kf83hINmUEzJpmG80T/XLtDDEzZo8f6PQLuRCcUQhmzqqIo3ZPTRaWByRA==",
"version": "5.49.2",
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.49.2.tgz",
"integrity": "sha512-dwJ2HRPHm8w51WB5YTF9J7m6Z5dtkqbU9ntMZ1dqXyFB9IpjoUFDj80ahRVEoVanfIp6pfASJbOlbWdEf8FOzQ==",
"dev": true
},
"color-convert": {

@ -36,7 +36,7 @@
"@babel/runtime": "^7.6.0",
"@sindresorhus/slugify": "^0.9.1",
"@sveltejs/site-kit": "^1.1.4",
"@sveltejs/svelte-repl": "^0.1.9",
"@sveltejs/svelte-repl": "^0.1.11",
"degit": "^2.1.4",
"dotenv": "^8.1.0",
"esm": "^3.2.25",

@ -27,7 +27,7 @@ import Slot from './nodes/Slot';
import { Node, ImportDeclaration, Identifier, Program, ExpressionStatement, AssignmentExpression, Literal } from 'estree';
import add_to_set from './utils/add_to_set';
import check_graph_for_cycles from './utils/check_graph_for_cycles';
import { print, x } from 'code-red';
import { print, x, b } from 'code-red';
interface ComponentOptions {
namespace?: string;
@ -717,11 +717,13 @@ export default class Component {
let scope = instance_scope;
const toRemove = [];
const to_remove = [];
const remove = (parent, prop, index) => {
toRemove.unshift([parent, prop, index]);
to_remove.unshift([parent, prop, index]);
};
const to_insert = new Map();
walk(content, {
enter(node, parent, prop, index) {
if (map.has(node)) {
@ -747,16 +749,41 @@ export default class Component {
}
component.warn_on_undefined_store_value_references(node, parent, scope);
if (component.compile_options.dev) {
const to_insert_for_loop_protect = component.loop_protect(node, prop, index);
if (to_insert_for_loop_protect) {
if (!Array.isArray(parent[prop])) {
parent[prop] = {
type: 'BlockStatement',
body: [to_insert_for_loop_protect.node, node],
};
} else {
// can't insert directly, will screw up the index in the for-loop of estree-walker
if (!to_insert.has(parent)) {
to_insert.set(parent, []);
}
to_insert.get(parent).push(to_insert_for_loop_protect);
}
}
}
},
leave(node) {
if (map.has(node)) {
scope = scope.parent;
}
if (to_insert.has(node)) {
const nodes_to_insert = to_insert.get(node);
for (const { index, prop, node: node_to_insert } of nodes_to_insert.reverse()) {
node[prop].splice(index, 0, node_to_insert);
}
to_insert.delete(node);
}
},
});
for (const [parent, prop, index] of toRemove) {
for (const [parent, prop, index] of to_remove) {
if (parent) {
if (index !== null) {
parent[prop].splice(index, 1);
@ -836,6 +863,32 @@ export default class Component {
}
}
loop_protect(node, prop, index) {
if (node.type === 'WhileStatement' ||
node.type === 'ForStatement' ||
node.type === 'DoWhileStatement') {
const guard = this.get_unique_name('guard');
this.add_var({
name: guard.name,
internal: true,
});
const before = b`const ${guard} = @loop_guard()`;
const inside = b`${guard}();`;
// wrap expression statement with BlockStatement
if (node.body.type !== 'BlockStatement') {
node.body = {
type: 'BlockStatement',
body: [node.body],
};
}
node.body.body.push(inside[0]);
return { index, prop, node: before[0] };
}
return null;
}
invalidate(name, value?) {
const variable = this.var_lookup.get(name);

@ -351,9 +351,9 @@ export default class ElementWrapper extends Wrapper {
block.maintain_context = true;
}
this.add_attributes(block);
this.add_bindings(block);
this.add_event_handlers(block);
this.add_attributes(block);
this.add_transitions(block);
this.add_animation(block);
this.add_actions(block);

@ -300,7 +300,9 @@ export default class InlineComponentWrapper extends Wrapper {
updates.push(b`
if (!${updating} && ${changed(Array.from(binding.expression.dependencies))}) {
${updating} = true;
${name_changes}.${binding.name} = ${snippet};
@add_flush_callback(() => ${updating} = false);
}
`);
@ -337,8 +339,6 @@ export default class InlineComponentWrapper extends Wrapper {
block.chunks.init.push(b`
function ${id}(${value}) {
#ctx.${id}.call(null, ${value}, #ctx);
${updating} = true;
@add_flush_callback(() => ${updating} = false);
}
`);
@ -347,8 +347,6 @@ export default class InlineComponentWrapper extends Wrapper {
block.chunks.init.push(b`
function ${id}(${value}) {
#ctx.${id}.call(null, ${value});
${updating} = true;
@add_flush_callback(() => ${updating} = false);
}
`);
}

@ -95,3 +95,12 @@ export class SvelteComponentDev extends SvelteComponent {
};
}
}
export function loop_guard() {
const start = Date.now();
return () => {
if (Date.now() - start > 100) {
throw new Error(`Infinite loop detected`);
}
};
}

@ -0,0 +1,5 @@
export default {
options: {
dev: true
}
};

@ -0,0 +1,109 @@
/* generated by Svelte vX.Y.Z */
import {
SvelteComponentDev,
dispatch_dev,
init,
loop_guard,
noop,
safe_not_equal
} from "svelte/internal";
const file = undefined;
function create_fragment(ctx) {
const block = {
c: noop,
l: function claim(nodes) {
throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option");
},
m: noop,
p: noop,
i: noop,
o: noop,
d: noop
};
dispatch_dev("SvelteRegisterBlock", {
block,
id: create_fragment.name,
type: "component",
source: "",
ctx
});
return block;
}
function instance($$self) {
const guard = loop_guard();
while (true) {
foo();
guard();
}
const guard_1 = loop_guard();
for (; ; ) {
foo();
guard_1();
}
const guard_2 = loop_guard();
while (true) {
foo();
guard_2();
}
const guard_4 = loop_guard();
do {
foo();
guard_4();
} while (true);
$$self.$capture_state = () => {
return {};
};
$$self.$inject_state = $$props => {
};
$: {
const guard_3 = loop_guard();
while (true) {
foo();
guard_3();
}
}
$: {
const guard_5 = loop_guard();
do {
foo();
guard_5();
} while (true);
}
return {};
}
class Component extends SvelteComponentDev {
constructor(options) {
super(options);
init(this, options, instance, create_fragment, safe_not_equal, {});
dispatch_dev("SvelteRegisterComponent", {
component: this,
tagName: "Component",
options,
id: create_fragment.name
});
}
}
export default Component;

@ -0,0 +1,12 @@
<script>
while(true) {
foo();
}
for(;;) {
foo();
}
while(true) foo();
$: while(true) foo();
do foo(); while(true);
$: do foo(); while(true);
</script>

@ -0,0 +1,33 @@
export default {
html: `
<button></button>
<input type=range min=0 max=10>
<p>10 of 10</p>
`,
ssrHtml: `
<button></button>
<input type=range min=0 max=10 value=10>
<p>10 of 10</p>
`,
async test({ assert, target, window }) {
const input = target.querySelector('input');
assert.equal(input.value, '10');
// should not change because max is 10, input range behaviour
// seems there is bug in jsdom (HTMLInputElement-impl) which behaviour is different from real browsers
// input.value = '20';
// assert.equal(input.value, '10');
const button = target.querySelector('button');
await button.dispatchEvent(new window.Event('click'));
assert.equal(input.value, '20');
assert.htmlEqual(target.innerHTML, `
<button></button>
<input type=range min=0 max=20>
<p>20 of 20</p>
`);
},
};

@ -0,0 +1,13 @@
<script>
let value=10;
let max=10;
function change() {
value=20;
max=20;
}
</script>
<button on:click={change}/>
<input type=range min=0 max={max} bind:value>
<p>{value} of {max}</p>

@ -0,0 +1,11 @@
<script>
export let count
function handleClick() {
count += 1;
}
</script>
<button on:click={handleClick}>
button {count}
</button>

@ -0,0 +1,38 @@
export default {
html: `
<button>main 0</button>
<button>button 0</button>
`,
async test({ assert, component, target, window }) {
const event = new window.MouseEvent('click');
const buttons = target.querySelectorAll('button');
await buttons[0].dispatchEvent(event);
assert.htmlEqual(target.innerHTML, `
<button>main 1</button>
<button>button 1</button>
`);
await buttons[1].dispatchEvent(event);
assert.htmlEqual(target.innerHTML, `
<button>main 2</button>
<button>button 2</button>
`);
// reactive update, reset to 2
await buttons[0].dispatchEvent(event);
assert.htmlEqual(target.innerHTML, `
<button>main 2</button>
<button>button 2</button>
`);
// bound to main, reset to 2
await buttons[1].dispatchEvent(event);
assert.htmlEqual(target.innerHTML, `
<button>main 2</button>
<button>button 2</button>
`);
}
};

@ -0,0 +1,19 @@
<script>
import Button from './Button.svelte';
let count = 0;
$: if (count > 2) {
count = 2;
}
function handleClick() {
count += 1;
}
</script>
<button on:click={handleClick}>
main {count}
</button>
<Button bind:count />

@ -0,0 +1,6 @@
export default {
error: 'Infinite loop detected',
compileOptions: {
dev: true,
}
};

@ -0,0 +1,5 @@
<script>
while(true) {
// do nothing
}
</script>
Loading…
Cancel
Save