From 9692524372f6423050c5f040baff47506d144490 Mon Sep 17 00:00:00 2001 From: Conduitry Date: Sun, 10 Nov 2019 08:00:26 -0500 Subject: [PATCH 1/5] fix tests --- test/js/samples/hydrated-void-element/expected.js | 3 ++- test/js/samples/src-attribute-check/expected.js | 5 ----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/test/js/samples/hydrated-void-element/expected.js b/test/js/samples/hydrated-void-element/expected.js index 992b90dd14..e53d16d925 100644 --- a/test/js/samples/hydrated-void-element/expected.js +++ b/test/js/samples/hydrated-void-element/expected.js @@ -16,6 +16,7 @@ import { function create_fragment(ctx) { let img; + let img_src_value; let t; let div; @@ -34,7 +35,7 @@ function create_fragment(ctx) { this.h(); }, h() { - attr(img, "src", "donuts.jpg"); + if (img.src !== (img_src_value = "donuts.jpg")) attr(img, "src", img_src_value); attr(img, "alt", "donuts"); }, m(target, anchor) { diff --git a/test/js/samples/src-attribute-check/expected.js b/test/js/samples/src-attribute-check/expected.js index 3e6364fa4a..8af33a962b 100644 --- a/test/js/samples/src-attribute-check/expected.js +++ b/test/js/samples/src-attribute-check/expected.js @@ -2,7 +2,6 @@ import { SvelteComponent, attr, - children, claim_element, claim_space, detach, @@ -30,12 +29,8 @@ function create_fragment(ctx) { }, l(nodes) { img0 = claim_element(nodes, "IMG", { alt: true, src: true }); - var img0_nodes = children(img0); - img0_nodes.forEach(detach); t = claim_space(nodes); img1 = claim_element(nodes, "IMG", { alt: true, src: true }); - var img1_nodes = children(img1); - img1_nodes.forEach(detach); this.h(); }, h() { From 93f507d126ea35b4be256940f037cb0daf5f9336 Mon Sep 17 00:00:00 2001 From: Shakhbulat Gazgireev Date: Sun, 10 Nov 2019 16:16:39 +0300 Subject: [PATCH 2/5] Site: add editor file association instructions (#3888) --- .../blog/2019-04-15-setting-up-your-editor.md | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/site/content/blog/2019-04-15-setting-up-your-editor.md b/site/content/blog/2019-04-15-setting-up-your-editor.md index 1db85a7974..7a107c590b 100644 --- a/site/content/blog/2019-04-15-setting-up-your-editor.md +++ b/site/content/blog/2019-04-15-setting-up-your-editor.md @@ -6,7 +6,9 @@ authorURL: https://twitter.com/Rich_Harris draft: true --- -*Coming soon* This post will walk you through setting up your editor so that recognises Svelte files: +*__Coming soon__* + +This post will walk you through setting up your editor so that recognises Svelte files: * eslint-plugin-svelte3 * svelte-vscode @@ -14,7 +16,7 @@ draft: true ## Atom -To treat `*.svelte` files as HTML, open Edit → Config... and add the following lines to your `core` section: +To treat `*.svelte` files as HTML, open *__Edit → Config...__* and add the following lines to your `core` section: ```cson "*": @@ -45,3 +47,23 @@ To set the filetype for a single file, use a [modeline](https://vim.fandom.com/w ``` ``` + +## Visual Studio Code + +To treat `*.svelte` files as HTML, add the following lines to your `settings.json` file: + +```cson + "files.associations": { + "*.svelte": "html" + } +``` + +## JetBrains WebStorm + +To treat `*.svelte` files as HTML in WebStorm, you need to create a new file type association. Please refer to the [JetBrains website](https://www.jetbrains.com/help/webstorm/creating-and-registering-file-types.html) to see how. + +## Sublime Text 3 + +Open any `.svelte` file. + +Go to *__View → Syntax → Open all with current extension as... → HTML__*. From 3f4155da2ece20da8b4823525c146008ca7621ac Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Sun, 10 Nov 2019 19:03:34 +0800 Subject: [PATCH 3/5] prevent infinite loop --- src/compiler/compile/Component.ts | 58 +++++++- test/js/samples/loop_protect/_config.js | 5 + test/js/samples/loop_protect/expected.js | 126 ++++++++++++++++++ test/js/samples/loop_protect/input.svelte | 12 ++ test/runtime/samples/loop-protect/_config.js | 6 + test/runtime/samples/loop-protect/main.svelte | 5 + 6 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 test/js/samples/loop_protect/_config.js create mode 100644 test/js/samples/loop_protect/expected.js create mode 100644 test/js/samples/loop_protect/input.svelte create mode 100644 test/runtime/samples/loop-protect/_config.js create mode 100644 test/runtime/samples/loop-protect/main.svelte diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 67b2cd4380..aea7dc3f5e 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -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; @@ -722,6 +722,8 @@ export default class Component { toRemove.unshift([parent, prop, index]); }; + const toInsert = new Map(); + walk(content, { enter(node, parent, prop, index) { if (map.has(node)) { @@ -747,12 +749,37 @@ 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 (!toInsert.has(parent)) { + toInsert.set(parent, []); + } + toInsert.get(parent).push(to_insert_for_loop_protect); + } + } + } }, leave(node) { if (map.has(node)) { scope = scope.parent; } + if (toInsert.has(node)) { + const nodes_to_insert = toInsert.get(node); + for (const { index, prop, node: node_to_insert } of nodes_to_insert.reverse()) { + node[prop].splice(index, 0, node_to_insert); + } + toInsert.delete(node); + } }, }); @@ -836,6 +863,35 @@ export default class Component { } } + loop_protect(node, prop, index) { + if (node.type === 'WhileStatement' || + node.type === 'ForStatement' || + node.type === 'DoWhileStatement') { + const id = this.get_unique_name('LP'); + this.add_var({ + name: id.name, + internal: true, + }); + + const before = b`const ${id} = Date.now();`; + const inside = b` + if (Date.now() - ${id} > 100) { + throw new Error('Infinite loop detected'); + } + `; + // 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); diff --git a/test/js/samples/loop_protect/_config.js b/test/js/samples/loop_protect/_config.js new file mode 100644 index 0000000000..b1f2518e8a --- /dev/null +++ b/test/js/samples/loop_protect/_config.js @@ -0,0 +1,5 @@ +export default { + options: { + dev: true + } +}; \ No newline at end of file diff --git a/test/js/samples/loop_protect/expected.js b/test/js/samples/loop_protect/expected.js new file mode 100644 index 0000000000..3119b4081c --- /dev/null +++ b/test/js/samples/loop_protect/expected.js @@ -0,0 +1,126 @@ +/* generated by Svelte vX.Y.Z */ +import { + SvelteComponentDev, + dispatch_dev, + init, + 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 LP = Date.now(); + + while (true) { + foo(); + + if (Date.now() - LP > 100) { + throw new Error("Infinite loop detected"); + } + } + + const LP_1 = Date.now(); + + for (; ; ) { + foo(); + + if (Date.now() - LP_1 > 100) { + throw new Error("Infinite loop detected"); + } + } + + const LP_2 = Date.now(); + + while (true) { + foo(); + + if (Date.now() - LP_2 > 100) { + throw new Error("Infinite loop detected"); + } + } + + const LP_4 = Date.now(); + + do { + foo(); + + if (Date.now() - LP_4 > 100) { + throw new Error("Infinite loop detected"); + } + } while (true); + + $$self.$capture_state = () => { + return {}; + }; + + $$self.$inject_state = $$props => { + + }; + + $: { + const LP_3 = Date.now(); + + while (true) { + foo(); + + if (Date.now() - LP_3 > 100) { + throw new Error("Infinite loop detected"); + } + } + } + + $: { + const LP_5 = Date.now(); + + do { + foo(); + + if (Date.now() - LP_5 > 100) { + throw new Error("Infinite loop detected"); + } + } 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; \ No newline at end of file diff --git a/test/js/samples/loop_protect/input.svelte b/test/js/samples/loop_protect/input.svelte new file mode 100644 index 0000000000..c39ea75f72 --- /dev/null +++ b/test/js/samples/loop_protect/input.svelte @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/test/runtime/samples/loop-protect/_config.js b/test/runtime/samples/loop-protect/_config.js new file mode 100644 index 0000000000..2a1f5cad4f --- /dev/null +++ b/test/runtime/samples/loop-protect/_config.js @@ -0,0 +1,6 @@ +export default { + error: 'Infinite loop detected', + compileOptions: { + dev: true, + } +}; diff --git a/test/runtime/samples/loop-protect/main.svelte b/test/runtime/samples/loop-protect/main.svelte new file mode 100644 index 0000000000..aff13c82f1 --- /dev/null +++ b/test/runtime/samples/loop-protect/main.svelte @@ -0,0 +1,5 @@ + \ No newline at end of file From 6b7371bfae8d0523b63864c34fd167fb5140565f Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 10 Nov 2019 15:08:05 -0500 Subject: [PATCH 4/5] -> v3.13.0 --- CHANGELOG.md | 19 ++++++++++++++++++- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ccdf043a72..62306fdbdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 `` 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 `` 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 `