diff --git a/CHANGELOG.md b/CHANGELOG.md index 62306fdbdb..566fde5005 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Svelte changelog +## 3.14.1 + +* Deconflict block method names with other variables ([#3900](https://github.com/sveltejs/svelte/issues/3900)) +* Fix entity encoding issue in text nodes with constant expressions ([#3911](https://github.com/sveltejs/svelte/issues/3911)) +* Make code for unknown prop warnings compatible with older js engines ([#3914](https://github.com/sveltejs/svelte/issues/3914)) + +## 3.14.0 + +* Add `loopGuardTimeout` option that augments `for`/`while` loops to prevent infinite loops, primarily for use in the REPL ([#3887](https://github.com/sveltejs/svelte/pull/3887)) +* Keep component bindings in sync when changed in reactive statements ([#3382](https://github.com/sveltejs/svelte/issues/3382)) +* Update attributes before bindings ([#3857](https://github.com/sveltejs/svelte/issues/3857)) +* Prevent variable naming conflict ([#3899](https://github.com/sveltejs/svelte/issues/3899)) + + ## 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)) diff --git a/package-lock.json b/package-lock.json index b11cf80a83..238b6d04d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "3.13.0", + "version": "3.14.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -500,26 +500,15 @@ "dev": true }, "code-red": { - "version": "0.0.19", - "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.19.tgz", - "integrity": "sha512-pzkA9ikMLR7KatByUJVz33kQKkrDnsJhyuvxSSUnyJNBggkGNStmDe/ezYvfP4CZ9XM7vYIID+YIaMJnlYGzLg==", + "version": "0.0.21", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.21.tgz", + "integrity": "sha512-luUVxyGNwTU/lG+lY+pitXHJzgDvFa0WfxA4Nsd7uk/S366mHY8B86pwAcyRcKY9BE/HvryVNXCR691Q5ry+Ww==", "dev": true, "requires": { "acorn": "^7.1.0", "is-reference": "^1.1.4", - "periscopic": "^1.0.2", + "periscopic": "^2.0.1", "sourcemap-codec": "^1.4.6" - }, - "dependencies": { - "periscopic": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-1.1.0.tgz", - "integrity": "sha512-sUdDgd8G35JjpBqHGnuc2MECoyUryHGfjtsKFPS6N8MEGHtxoIML8yEWydL1zf+W8EoChX4L7A9AvVRJuM6Lqg==", - "dev": true, - "requires": { - "is-reference": "^1.1.4" - } - } } }, "codecov": { @@ -2734,9 +2723,9 @@ "dev": true }, "periscopic": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-2.0.0.tgz", - "integrity": "sha512-2YVtztswd6ud5b0+IDD26UhEm1QvlTsR3s7G59CD0txGyhfvQ39YhNuueSmzT5VzHUxiIH0E8S04JSQpXMJ8/g==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-2.0.1.tgz", + "integrity": "sha512-twJ8e4RatllMAcbmBqKj8cvZ94HtqSzbb8hJoGj4iSCcCHXxKb06HRxOq4heyq2x/6mKynJDvTTreHCz+m6lJw==", "dev": true, "requires": { "is-reference": "^1.1.4" diff --git a/package.json b/package.json index 771dbc194f..703df57e22 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "3.13.0", + "version": "3.14.1", "description": "Cybernetically enhanced web apps", "module": "index.mjs", "main": "index", @@ -64,7 +64,7 @@ "acorn": "^7.1.0", "agadoo": "^1.1.0", "c8": "^5.0.1", - "code-red": "0.0.19", + "code-red": "0.0.21", "codecov": "^3.5.0", "css-tree": "1.0.0-alpha22", "eslint": "^6.3.0", @@ -77,7 +77,7 @@ "locate-character": "^2.0.5", "magic-string": "^0.25.3", "mocha": "^6.2.0", - "periscopic": "^2.0.0", + "periscopic": "^2.0.1", "puppeteer": "^1.19.0", "rollup": "^1.21.4", "rollup-plugin-commonjs": "^10.1.0", diff --git a/site/rollup.config.js b/site/rollup.config.js index c713be33c1..9cb963a87d 100644 --- a/site/rollup.config.js +++ b/site/rollup.config.js @@ -13,6 +13,9 @@ const mode = process.env.NODE_ENV; const dev = mode === 'development'; const legacy = !!process.env.SAPPER_LEGACY_BUILD; +const onwarn = (warning, onwarn) => (warning.code === 'CIRCULAR_DEPENDENCY' && /[/\\]@sapper[/\\]/.test(warning.message)) || onwarn(warning); +const dedupe = importee => importee === 'svelte' || importee.startsWith('svelte/'); + export default { client: { input: config.client.input(), @@ -28,7 +31,10 @@ export default { hydratable: true, emitCss: true }), - resolve(), + resolve({ + browser: true, + dedupe + }), commonjs(), json(), @@ -53,6 +59,7 @@ export default { module: true }) ], + onwarn }, server: { @@ -67,7 +74,9 @@ export default { generate: 'ssr', dev }), - resolve(), + resolve({ + dedupe + }), commonjs(), json() ], @@ -78,6 +87,7 @@ export default { require('module').builtinModules || Object.keys(process.binding('natives')) ) ], + onwarn }, serviceworker: { diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index 0b9784a6e8..74822ef9be 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -266,7 +266,7 @@ export default class Block { : this.chunks.hydrate ); - properties.create = x`function create() { + properties.create = x`function #create() { ${this.chunks.create} ${hydrate} }`; @@ -276,7 +276,7 @@ export default class Block { if (this.chunks.claim.length === 0 && this.chunks.hydrate.length === 0) { properties.claim = noop; } else { - properties.claim = x`function claim(#nodes) { + properties.claim = x`function #claim(#nodes) { ${this.chunks.claim} ${this.renderer.options.hydratable && this.chunks.hydrate.length > 0 && b`this.h();`} }`; @@ -284,7 +284,7 @@ export default class Block { } if (this.renderer.options.hydratable && this.chunks.hydrate.length > 0) { - properties.hydrate = x`function hydrate() { + properties.hydrate = x`function #hydrate() { ${this.chunks.hydrate} }`; } @@ -292,7 +292,7 @@ export default class Block { if (this.chunks.mount.length === 0) { properties.mount = noop; } else { - properties.mount = x`function mount(#target, anchor) { + properties.mount = x`function #mount(#target, anchor) { ${this.chunks.mount} }`; } @@ -302,7 +302,7 @@ export default class Block { properties.update = noop; } else { const ctx = this.maintain_context ? x`#new_ctx` : x`#ctx`; - properties.update = x`function update(#changed, ${ctx}) { + properties.update = x`function #update(#changed, ${ctx}) { ${this.maintain_context && b`#ctx = ${ctx};`} ${this.chunks.update} }`; @@ -310,15 +310,15 @@ export default class Block { } if (this.has_animation) { - properties.measure = x`function measure() { + properties.measure = x`function #measure() { ${this.chunks.measure} }`; - properties.fix = x`function fix() { + properties.fix = x`function #fix() { ${this.chunks.fix} }`; - properties.animate = x`function animate() { + properties.animate = x`function #animate() { ${this.chunks.animate} }`; } @@ -327,7 +327,7 @@ export default class Block { if (this.chunks.intro.length === 0) { properties.intro = noop; } else { - properties.intro = x`function intro(#local) { + properties.intro = x`function #intro(#local) { ${this.has_outros && b`if (#current) return;`} ${this.chunks.intro} }`; @@ -336,7 +336,7 @@ export default class Block { if (this.chunks.outro.length === 0) { properties.outro = noop; } else { - properties.outro = x`function outro(#local) { + properties.outro = x`function #outro(#local) { ${this.chunks.outro} }`; } @@ -345,7 +345,7 @@ export default class Block { if (this.chunks.destroy.length === 0) { properties.destroy = noop; } else { - properties.destroy = x`function destroy(detaching) { + properties.destroy = x`function #destroy(detaching) { ${this.chunks.destroy} }`; } diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 49ce17236a..cc0c7dfe31 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -247,7 +247,7 @@ export default function dom( function create_fragment(#ctx) { ${block.get_contents()} } - `); + `); } body.push(b` @@ -369,7 +369,7 @@ export default function dom( unknown_props_check = b` const writable_props = [${writable_props.map(prop => x`'${prop.export_name}'`)}]; @_Object.keys($$props).forEach(key => { - if (!writable_props.includes(key) && !key.startsWith('$$')) @_console.warn(\`<${component.tag}> was created with unknown prop '\${key}'\`); + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$') @_console.warn(\`<${component.tag}> was created with unknown prop '\${key}'\`); }); `; } diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index 168d53d997..a34091f5b6 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -304,7 +304,8 @@ export default class ElementWrapper extends Wrapper { } // insert static children with textContent or innerHTML - if (!this.node.namespace && (this.can_use_innerhtml || this.can_use_textcontent()) && this.fragment.nodes.length > 0) { + const can_use_textcontent = this.can_use_textcontent(); + if (!this.node.namespace && (this.can_use_innerhtml || can_use_textcontent) && this.fragment.nodes.length > 0) { if (this.fragment.nodes.length === 1 && this.fragment.nodes[0].node.type === 'Text') { block.chunks.create.push( // @ts-ignore todo: should it be this.fragment.nodes[0].node.data instead? @@ -324,7 +325,8 @@ export default class ElementWrapper extends Wrapper { quasis: [] }; - to_html((this.fragment.nodes as unknown as Array), block, literal, state); + const can_use_raw_text = !this.can_use_innerhtml && can_use_textcontent; + to_html((this.fragment.nodes as unknown as Array), block, literal, state, can_use_raw_text); literal.quasis.push(state.quasi); block.chunks.create.push( @@ -634,10 +636,10 @@ export default class ElementWrapper extends Wrapper { }); block.chunks.init.push(b` - var ${levels} = [${initial_props}]; + let ${levels} = [${initial_props}]; - var ${data} = {}; - for (var #i = 0; #i < ${levels}.length; #i += 1) { + let ${data} = {}; + for (let #i = 0; #i < ${levels}.length; #i += 1) { ${data} = @assign(${data}, ${levels}[#i]); } `); @@ -867,7 +869,7 @@ export default class ElementWrapper extends Wrapper { } } -function to_html(wrappers: Array, block: Block, literal: any, state: any) { +function to_html(wrappers: Array, block: Block, literal: any, state: any, can_use_raw_text?: boolean) { wrappers.forEach(wrapper => { if (wrapper.node.type === 'Text') { if ((wrapper as TextWrapper).use_space()) state.quasi.value.raw += ' '; @@ -876,7 +878,8 @@ function to_html(wrappers: Array, blo const raw = parent && ( parent.name === 'script' || - parent.name === 'style' + parent.name === 'style' || + can_use_raw_text ); state.quasi.value.raw += (raw ? wrapper.node.data : escape_html(wrapper.node.data)) @@ -931,4 +934,4 @@ function to_html(wrappers: Array, blo } } }); -} \ No newline at end of file +} diff --git a/test/js/samples/debug-empty/expected.js b/test/js/samples/debug-empty/expected.js index 3c65e5a950..b545823c57 100644 --- a/test/js/samples/debug-empty/expected.js +++ b/test/js/samples/debug-empty/expected.js @@ -72,7 +72,7 @@ function instance($$self, $$props, $$invalidate) { const writable_props = ["name"]; Object.keys($$props).forEach(key => { - if (!writable_props.includes(key) && !key.startsWith("$$")) console.warn(` was created with unknown prop '${key}'`); + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(` was created with unknown prop '${key}'`); }); $$self.$set = $$props => { diff --git a/test/js/samples/debug-foo-bar-baz-things/expected.js b/test/js/samples/debug-foo-bar-baz-things/expected.js index 4d6a0f61c6..448fc82176 100644 --- a/test/js/samples/debug-foo-bar-baz-things/expected.js +++ b/test/js/samples/debug-foo-bar-baz-things/expected.js @@ -167,7 +167,7 @@ function instance($$self, $$props, $$invalidate) { const writable_props = ["things", "foo", "bar", "baz"]; Object.keys($$props).forEach(key => { - if (!writable_props.includes(key) && !key.startsWith("$$")) console.warn(` was created with unknown prop '${key}'`); + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(` was created with unknown prop '${key}'`); }); $$self.$set = $$props => { diff --git a/test/js/samples/debug-foo/expected.js b/test/js/samples/debug-foo/expected.js index 3f502bc0ca..8abfd1bae1 100644 --- a/test/js/samples/debug-foo/expected.js +++ b/test/js/samples/debug-foo/expected.js @@ -165,7 +165,7 @@ function instance($$self, $$props, $$invalidate) { const writable_props = ["things", "foo"]; Object.keys($$props).forEach(key => { - if (!writable_props.includes(key) && !key.startsWith("$$")) console.warn(` was created with unknown prop '${key}'`); + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(` was created with unknown prop '${key}'`); }); $$self.$set = $$props => { diff --git a/test/js/samples/dev-warning-missing-data-computed/expected.js b/test/js/samples/dev-warning-missing-data-computed/expected.js index f362a42db6..5da2b4aead 100644 --- a/test/js/samples/dev-warning-missing-data-computed/expected.js +++ b/test/js/samples/dev-warning-missing-data-computed/expected.js @@ -69,7 +69,7 @@ function instance($$self, $$props, $$invalidate) { const writable_props = ["foo"]; Object.keys($$props).forEach(key => { - if (!writable_props.includes(key) && !key.startsWith("$$")) console.warn(` was created with unknown prop '${key}'`); + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(` was created with unknown prop '${key}'`); }); $$self.$set = $$props => { diff --git a/test/runtime/samples/deconflict-block-methods/_config.js b/test/runtime/samples/deconflict-block-methods/_config.js new file mode 100644 index 0000000000..2bb1aa8424 --- /dev/null +++ b/test/runtime/samples/deconflict-block-methods/_config.js @@ -0,0 +1,6 @@ +export default { + compileOptions: { + dev: true + }, + html: `
deconflicted
` +}; diff --git a/test/runtime/samples/deconflict-block-methods/main.svelte b/test/runtime/samples/deconflict-block-methods/main.svelte new file mode 100644 index 0000000000..ad75488873 --- /dev/null +++ b/test/runtime/samples/deconflict-block-methods/main.svelte @@ -0,0 +1,5 @@ + + +
{create}
diff --git a/test/runtime/samples/deconflict-spread-i/_config.js b/test/runtime/samples/deconflict-spread-i/_config.js new file mode 100644 index 0000000000..f147a4c1ff --- /dev/null +++ b/test/runtime/samples/deconflict-spread-i/_config.js @@ -0,0 +1,3 @@ +export default { + preserveIdentifiers: true +}; \ No newline at end of file diff --git a/test/runtime/samples/deconflict-spread-i/main.svelte b/test/runtime/samples/deconflict-spread-i/main.svelte new file mode 100644 index 0000000000..a7b201ac4e --- /dev/null +++ b/test/runtime/samples/deconflict-spread-i/main.svelte @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/test/runtime/samples/unchanged-expression-escape/_config.js b/test/runtime/samples/unchanged-expression-escape/_config.js new file mode 100644 index 0000000000..11a54c0fe9 --- /dev/null +++ b/test/runtime/samples/unchanged-expression-escape/_config.js @@ -0,0 +1,7 @@ +export default { + html: ` +

Hello world, what's up? this & that

+

Hello world, what's up? this & that

+

Hello world, what's up? this & that

+ `, +}; diff --git a/test/runtime/samples/unchanged-expression-escape/main.svelte b/test/runtime/samples/unchanged-expression-escape/main.svelte new file mode 100644 index 0000000000..de61ba5906 --- /dev/null +++ b/test/runtime/samples/unchanged-expression-escape/main.svelte @@ -0,0 +1,7 @@ + + +

Hello {name}, what's up? this & that

+

Hello world, what's up? this & that

+

Hello {name}, what's up? this & that

\ No newline at end of file