diff --git a/.gitignore b/.gitignore index 7a14244929..f7fac04eba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .idea .DS_Store .nyc_output +.vscode node_modules *.map /src/compiler/compile/internal_exports.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index b0672d790e..cbab1872dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,32 @@ ## Unreleased +* Fix attaching of JS debugging comments to HTML comments ([#4565](https://github.com/sveltejs/svelte/issues/4565)) + +## 3.20.1 + +* Fix compiler regression with slots ([#4562](https://github.com/sveltejs/svelte/issues/4562)) + +## 3.20.0 + +* Allow destructuring in `{#await}` blocks ([#1851](https://github.com/sveltejs/svelte/issues/1851)) +* Allow `` to be used in a slot ([#2798](https://github.com/sveltejs/svelte/issues/2798)) +* Expose object of unknown props in `$$restProps` ([#2930](https://github.com/sveltejs/svelte/issues/2930)) +* Prevent passing named slots other than from the top level within a component ([#3385](https://github.com/sveltejs/svelte/issues/3385)) +* Allow transitions and animations to work within iframes ([#3624](https://github.com/sveltejs/svelte/issues/3624)) +* Fix initialising slot fallbacks when unnecessary ([#3763](https://github.com/sveltejs/svelte/issues/3763)) +* Disallow binding directly to `const` variables ([#4479](https://github.com/sveltejs/svelte/issues/4479)) +* Fix re-attaching event handlers on keyed `{#each}` blocks ([#4491](https://github.com/sveltejs/svelte/issues/4491)) +* Fix updating keyed `{#each}` blocks with `{:else}` ([#4536](https://github.com/sveltejs/svelte/issues/4536), [#4549](https://github.com/sveltejs/svelte/issues/4549)) +* Fix hydration of top-level content ([#4542](https://github.com/sveltejs/svelte/issues/4542)) + +## 3.19.2 + +* In `dev` mode, display a runtime warning when a component is passed an unexpected slot ([#1020](https://github.com/sveltejs/svelte/issues/1020), [#1447](https://github.com/sveltejs/svelte/issues/1447)) * In `vars` array, correctly indicate whether `module` variables are `mutated` or `reassigned` ([#3215](https://github.com/sveltejs/svelte/issues/3215)) * Fix spread props not updating in certain situations ([#3521](https://github.com/sveltejs/svelte/issues/3521), [#4480](https://github.com/sveltejs/svelte/issues/4480)) * Use the fallback content for slots if they are passed only whitespace ([#4092](https://github.com/sveltejs/svelte/issues/4092)) +* Fix bitmask overflow for `{#if}` blocks ([#4263](https://github.com/sveltejs/svelte/issues/4263)) * In `dev` mode, check for unknown props even if the component has no writable props ([#4323](https://github.com/sveltejs/svelte/issues/4323)) * Exclude global variables from `$capture_state` ([#4463](https://github.com/sveltejs/svelte/issues/4463)) * Fix bitmask overflow for slots ([#4481](https://github.com/sveltejs/svelte/issues/4481)) diff --git a/banner.png b/banner.png deleted file mode 100644 index 0d117c3c09..0000000000 Binary files a/banner.png and /dev/null differ diff --git a/package-lock.json b/package-lock.json index f0f4e17422..7c521bd93d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "3.19.1", + "version": "3.20.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -280,9 +280,9 @@ "dev": true }, "acorn": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", - "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", + "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==", "dev": true }, "acorn-globals": { diff --git a/package.json b/package.json index 7a02f1da10..2053ebb76f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "3.19.1", + "version": "3.20.1", "description": "Cybernetically enhanced web apps", "module": "index.mjs", "main": "index", diff --git a/site/content/docs/02-template-syntax.md b/site/content/docs/02-template-syntax.md index d25b348254..ea36474bed 100644 --- a/site/content/docs/02-template-syntax.md +++ b/site/content/docs/02-template-syntax.md @@ -113,6 +113,15 @@ An element or component can have multiple spread attributes, interspersed with r ``` +--- + +*`$$restProps`* contains only the props which are *not* declared with `export`. It can be used to pass down other unknown attributes to an element in a component. + +```html + +``` + +--- ### Text expressions diff --git a/site/content/docs/03-run-time.md b/site/content/docs/03-run-time.md index c75ec694d9..0bbae24185 100644 --- a/site/content/docs/03-run-time.md +++ b/site/content/docs/03-run-time.md @@ -974,7 +974,7 @@ app.count += 1; Svelte components can also be compiled to custom elements (aka web components) using the `customElement: true` compiler option. You should specify a tag name for the component using the `` [element](docs#svelte_options). ```html - + +
Length: {length}
+
Values: {values.join(',')}
+ +
\ No newline at end of file diff --git a/test/runtime/samples/$$rest-without-props/_config.js b/test/runtime/samples/$$rest-without-props/_config.js new file mode 100644 index 0000000000..017f9df561 --- /dev/null +++ b/test/runtime/samples/$$rest-without-props/_config.js @@ -0,0 +1,54 @@ +export default { + props: { + a: 3, + b: 4, + c: 5, + d: 6 + }, + html: ` +
Length: 3
+
Values: 4,5,1
+
+ + `, + async test({ assert, target, window, }) { + const [btn1, btn2, btn3, btn4] = target.querySelectorAll('button'); + const clickEvent = new window.MouseEvent('click'); + + await btn1.dispatchEvent(clickEvent); + + assert.htmlEqual(target.innerHTML, ` +
Length: 3
+
Values: 4,5,1
+
+ + `); + + await btn2.dispatchEvent(clickEvent); + + assert.htmlEqual(target.innerHTML, ` +
Length: 3
+
Values: 34,5,1
+
+ + `); + + await btn3.dispatchEvent(clickEvent); + + assert.htmlEqual(target.innerHTML, ` +
Length: 3
+
Values: 34,5,31
+
+ + `); + + await btn4.dispatchEvent(clickEvent); + + assert.htmlEqual(target.innerHTML, ` +
Length: 4
+
Values: 34,5,31,2
+
+ + `); + } +}; diff --git a/test/runtime/samples/$$rest-without-props/main.svelte b/test/runtime/samples/$$rest-without-props/main.svelte new file mode 100644 index 0000000000..21b2690584 --- /dev/null +++ b/test/runtime/samples/$$rest-without-props/main.svelte @@ -0,0 +1,25 @@ + + + + + + + \ No newline at end of file diff --git a/test/runtime/samples/$$rest/App.svelte b/test/runtime/samples/$$rest/App.svelte new file mode 100644 index 0000000000..875372f670 --- /dev/null +++ b/test/runtime/samples/$$rest/App.svelte @@ -0,0 +1,13 @@ + +
Length: {length}
+
Values: {values.join(',')}
+ +
+
\ No newline at end of file diff --git a/test/runtime/samples/$$rest/_config.js b/test/runtime/samples/$$rest/_config.js new file mode 100644 index 0000000000..255927f354 --- /dev/null +++ b/test/runtime/samples/$$rest/_config.js @@ -0,0 +1,60 @@ +export default { + props: { + a: 3, + b: 4, + c: 5, + d: 6 + }, + html: ` +
Length: 3
+
Values: 4,5,1
+
+
+ + `, + + async test({ assert, target, window, }) { + const [btn1, btn2, btn3, btn4] = target.querySelectorAll('button'); + const clickEvent = new window.MouseEvent('click'); + + await btn1.dispatchEvent(clickEvent); + + assert.htmlEqual(target.innerHTML, ` +
Length: 3
+
Values: 4,5,1
+
+
+ + `); + + await btn2.dispatchEvent(clickEvent); + + assert.htmlEqual(target.innerHTML, ` +
Length: 3
+
Values: 34,5,1
+
+
+ + `); + + await btn3.dispatchEvent(clickEvent); + + assert.htmlEqual(target.innerHTML, ` +
Length: 3
+
Values: 34,5,31
+
+
+ + `); + + await btn4.dispatchEvent(clickEvent); + + assert.htmlEqual(target.innerHTML, ` +
Length: 4
+
Values: 34,5,31,2
+
+
+ + `); + } +}; diff --git a/test/runtime/samples/$$rest/main.svelte b/test/runtime/samples/$$rest/main.svelte new file mode 100644 index 0000000000..21b2690584 --- /dev/null +++ b/test/runtime/samples/$$rest/main.svelte @@ -0,0 +1,25 @@ + + + + + + + \ No newline at end of file diff --git a/test/runtime/samples/await-then-destruct-array/_config.js b/test/runtime/samples/await-then-destruct-array/_config.js new file mode 100644 index 0000000000..55c48481e0 --- /dev/null +++ b/test/runtime/samples/await-then-destruct-array/_config.js @@ -0,0 +1,61 @@ +export default { + props: { + thePromise: new Promise(resolve => {}) + }, + + html: ` + loading... + `, + + async test({ assert, component, target }) { + await (component.thePromise = Promise.resolve([1, 2])); + + assert.htmlEqual( + target.innerHTML, + ` +

a: 1

+

b: 2

+ ` + ); + + await (component.thePromise = Promise.resolve([4, 5])); + + assert.htmlEqual( + target.innerHTML, + ` +

a: 4

+

b: 5

+ ` + ); + + try { + await (component.thePromise = Promise.reject(['a', [6, 7]])); + } catch (e) { + // do nothing + } + + assert.htmlEqual( + target.innerHTML, + ` +

c: a

+

d: 6

+

e: 7

+ ` + ); + + try { + await (component.thePromise = Promise.reject(['b', [8, 9]])); + } catch (e) { + // do nothing + } + + assert.htmlEqual( + target.innerHTML, + ` +

c: b

+

d: 8

+

e: 9

+ ` + ); + } +}; diff --git a/test/runtime/samples/await-then-destruct-array/main.svelte b/test/runtime/samples/await-then-destruct-array/main.svelte new file mode 100644 index 0000000000..cc0d217f79 --- /dev/null +++ b/test/runtime/samples/await-then-destruct-array/main.svelte @@ -0,0 +1,14 @@ + + +{#await thePromise} + loading... +{:then [ a, b ]} +

a: {a}

+

b: {b}

+{:catch [c, [d, e]]} +

c: {c}

+

d: {d}

+

e: {e}

+{/await} \ No newline at end of file diff --git a/test/runtime/samples/await-then-destruct-default/_config.js b/test/runtime/samples/await-then-destruct-default/_config.js new file mode 100644 index 0000000000..d0e5a49f28 --- /dev/null +++ b/test/runtime/samples/await-then-destruct-default/_config.js @@ -0,0 +1,23 @@ +export default { + async test({ assert, component, target }) { + await Promise.resolve(); + + assert.htmlEqual( + target.innerHTML, + ` +

a: 3

+

b: 2

+

c: 3

+

a: 1

+

b: 2

+

c: 3

+

a: 3

+

b: 2

+

c: 3

+

a: 1

+

b: 2

+

c: 3

+ ` + ); + } +}; diff --git a/test/runtime/samples/await-then-destruct-default/main.svelte b/test/runtime/samples/await-then-destruct-default/main.svelte new file mode 100644 index 0000000000..d559aadab1 --- /dev/null +++ b/test/runtime/samples/await-then-destruct-default/main.svelte @@ -0,0 +1,34 @@ + + +{#await object then { a = 3, b = 4, c }} +

a: {a}

+

b: {b}

+

c: {c}

+{/await} + +{#await array then [a, b, c = 3]} +

a: {a}

+

b: {b}

+

c: {c}

+{/await} + +{#await objectReject then value} + resolved +{:catch { a = 3, b = 4, c }} +

a: {a}

+

b: {b}

+

c: {c}

+{/await} + +{#await arrayReject then value} + resolved +{:catch [a, b, c = 3]} +

a: {a}

+

b: {b}

+

c: {c}

+{/await} \ No newline at end of file diff --git a/test/runtime/samples/await-then-destruct-object/_config.js b/test/runtime/samples/await-then-destruct-object/_config.js new file mode 100644 index 0000000000..371462de97 --- /dev/null +++ b/test/runtime/samples/await-then-destruct-object/_config.js @@ -0,0 +1,63 @@ +export default { + props: { + thePromise: new Promise(resolve => {}) + }, + + html: ` + loading... + `, + + async test({ assert, component, target }) { + await (component.thePromise = Promise.resolve({ error: "error message" })); + + assert.htmlEqual( + target.innerHTML, + ` +

error: error message

+

result: undefined

+ ` + ); + + await (component.thePromise = Promise.resolve({ result: "42" })); + + assert.htmlEqual( + target.innerHTML, + ` +

error: undefined

+

result: 42

+ ` + ); + + try { + await (component.thePromise = Promise.reject({ + error: { message: "oops", code: "123" } + })); + } catch (e) { + // do nothing + } + + assert.htmlEqual( + target.innerHTML, + ` +

message: oops

+

code: 123

+ ` + ); + + try { + await (component.thePromise = Promise.reject({ + error: { message: "timeout", code: "456" } + })); + } catch (e) { + // do nothing + } + + assert.htmlEqual( + target.innerHTML, + ` +

message: timeout

+

code: 456

+ ` + ); + } +}; diff --git a/test/runtime/samples/await-then-destruct-object/main.svelte b/test/runtime/samples/await-then-destruct-object/main.svelte new file mode 100644 index 0000000000..ff574b7be8 --- /dev/null +++ b/test/runtime/samples/await-then-destruct-object/main.svelte @@ -0,0 +1,13 @@ + + +{#await thePromise} + loading... +{:then { result, error }} +

error: {error}

+

result: {result}

+{:catch { error: { message, code } }} +

message: {message}

+

code: {code}

+{/await} \ No newline at end of file diff --git a/test/runtime/samples/await-then-destruct-rest/_config.js b/test/runtime/samples/await-then-destruct-rest/_config.js new file mode 100644 index 0000000000..528568e569 --- /dev/null +++ b/test/runtime/samples/await-then-destruct-rest/_config.js @@ -0,0 +1,21 @@ +export default { + async test({ assert, component, target }) { + await Promise.resolve(); + + assert.htmlEqual( + target.innerHTML, + ` +

a: 1

+

rest: {"b":2,"c":3}

+

a: 1

+

b: 2

+

rest: [3,4,5,6]

+

a: 1

+

rest: {"b":2,"c":3}

+

a: 1

+

b: 2

+

rest: [3,4,5,6]

+ ` + ); + } +}; diff --git a/test/runtime/samples/await-then-destruct-rest/main.svelte b/test/runtime/samples/await-then-destruct-rest/main.svelte new file mode 100644 index 0000000000..a2d57dabf3 --- /dev/null +++ b/test/runtime/samples/await-then-destruct-rest/main.svelte @@ -0,0 +1,32 @@ + + +{#await object then { a, ...rest }} +

a: {a}

+

rest: {JSON.stringify(rest)}

+{/await} + +{#await array then [a, b, ...rest]} +

a: {a}

+

b: {b}

+

rest: {JSON.stringify(rest)}

+{/await} + +{#await objectReject then value} + resolved +{:catch { a, ...rest }} +

a: {a}

+

rest: {JSON.stringify(rest)}

+{/await} + +{#await arrayReject then value} + resolved +{:catch [a, b, ...rest]} +

a: {a}

+

b: {b}

+

rest: {JSON.stringify(rest)}

+{/await} \ No newline at end of file diff --git a/test/runtime/samples/bitmask-overflow-if/_config.js b/test/runtime/samples/bitmask-overflow-if/_config.js new file mode 100644 index 0000000000..74bc70d414 --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-if/_config.js @@ -0,0 +1,24 @@ +export default { + html: ` + 012345678910111213141516171819202122232425262728293031323334353637383940 + expected: true + if: true + + `, + + async test({ assert, component, target, window }) { + const button = target.querySelector("button"); + await button.dispatchEvent(new window.MouseEvent("click")); + + assert.htmlEqual( + target.innerHTML, + ` + 112345678910111213141516171819202122232425262728293031323334353637383940 + expected: false + if: false +
+ + ` + ); + } +}; diff --git a/test/runtime/samples/bitmask-overflow-if/main.svelte b/test/runtime/samples/bitmask-overflow-if/main.svelte new file mode 100644 index 0000000000..2c1c453091 --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-if/main.svelte @@ -0,0 +1,62 @@ + + + +{_0}{_1}{_2}{_3}{_4}{_5}{_6}{_7}{_8}{_9}{_10}{_11}{_12}{_13}{_14}{_15}{_16}{_17}{_18}{_19}{_20}{_21}{_22}{_23}{_24}{_25}{_26}{_27}{_28}{_29}{_30}{_31}{_32}{_33}{_34}{_35}{_36}{_37}{_38}{_39}{_40} + +expected: {_a.indexOf(_0) && _0 === '0' && _1 === '1'} +{#if _a.indexOf(_0) && _0 === '0' && _1 === '1'} +if: true +{:else} +if: false +
+{/if} + + \ No newline at end of file diff --git a/test/runtime/samples/component-slot-fallback-2/Inner.svelte b/test/runtime/samples/component-slot-fallback-2/Inner.svelte new file mode 100644 index 0000000000..d1c247ad35 --- /dev/null +++ b/test/runtime/samples/component-slot-fallback-2/Inner.svelte @@ -0,0 +1,7 @@ + + + +{value} \ No newline at end of file diff --git a/test/runtime/samples/component-slot-fallback-2/Outer.svelte b/test/runtime/samples/component-slot-fallback-2/Outer.svelte new file mode 100644 index 0000000000..1e44ba4db7 --- /dev/null +++ b/test/runtime/samples/component-slot-fallback-2/Outer.svelte @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/test/runtime/samples/component-slot-fallback-2/_config.js b/test/runtime/samples/component-slot-fallback-2/_config.js new file mode 100644 index 0000000000..585e3b4c9e --- /dev/null +++ b/test/runtime/samples/component-slot-fallback-2/_config.js @@ -0,0 +1,39 @@ +export default { + html: ` `, + ssrHtml: ` `, + + async test({ assert, target, component, window }) { + const [input1, input2, inputFallback] = target.querySelectorAll("input"); + + assert.equal(component.getSubscriberCount(), 3); + + input1.value = "a"; + await input1.dispatchEvent(new window.Event("input")); + input1.value = "ab"; + await input1.dispatchEvent(new window.Event("input")); + assert.equal(input1.value, "ab"); + assert.equal(input2.value, "ab"); + assert.equal(inputFallback.value, "ab"); + + component.props = "hello"; + + assert.htmlEqual( + target.innerHTML, + ` + hello + hello + + ` + ); + + component.fallback = "world"; + assert.htmlEqual( + target.innerHTML, + ` + hello + hello + world + ` + ); + } +}; diff --git a/test/runtime/samples/component-slot-fallback-2/main.svelte b/test/runtime/samples/component-slot-fallback-2/main.svelte new file mode 100644 index 0000000000..4583667015 --- /dev/null +++ b/test/runtime/samples/component-slot-fallback-2/main.svelte @@ -0,0 +1,23 @@ + + + + + + + + + + + + diff --git a/test/runtime/samples/component-slot-fallback-2/store.svelte b/test/runtime/samples/component-slot-fallback-2/store.svelte new file mode 100644 index 0000000000..e377aaf314 --- /dev/null +++ b/test/runtime/samples/component-slot-fallback-2/store.svelte @@ -0,0 +1,23 @@ + \ No newline at end of file diff --git a/test/runtime/samples/component-slot-fallback-3/Inner.svelte b/test/runtime/samples/component-slot-fallback-3/Inner.svelte new file mode 100644 index 0000000000..db2af272d2 --- /dev/null +++ b/test/runtime/samples/component-slot-fallback-3/Inner.svelte @@ -0,0 +1,6 @@ + +
Hello
+
world
+
Bye
+
World
+
diff --git a/test/runtime/samples/component-slot-fallback-3/_config.js b/test/runtime/samples/component-slot-fallback-3/_config.js new file mode 100644 index 0000000000..b5591fb5e0 --- /dev/null +++ b/test/runtime/samples/component-slot-fallback-3/_config.js @@ -0,0 +1,6 @@ +export default { + html: ` +
Hello World
+
Hello
world
Bye
World
+ `, +}; diff --git a/test/runtime/samples/component-slot-fallback-3/main.svelte b/test/runtime/samples/component-slot-fallback-3/main.svelte new file mode 100644 index 0000000000..eda7ea60e4 --- /dev/null +++ b/test/runtime/samples/component-slot-fallback-3/main.svelte @@ -0,0 +1,9 @@ + + + +
Hello World
+
+ + diff --git a/test/runtime/samples/component-slot-fallback-4/Inner.svelte b/test/runtime/samples/component-slot-fallback-4/Inner.svelte new file mode 100644 index 0000000000..9eb3ef1401 --- /dev/null +++ b/test/runtime/samples/component-slot-fallback-4/Inner.svelte @@ -0,0 +1,3 @@ + + + foobar \ No newline at end of file diff --git a/test/runtime/samples/component-slot-fallback-4/_config.js b/test/runtime/samples/component-slot-fallback-4/_config.js new file mode 100644 index 0000000000..b7c2b63ed6 --- /dev/null +++ b/test/runtime/samples/component-slot-fallback-4/_config.js @@ -0,0 +1,5 @@ +export default { + html: ` + foobar + `, +}; diff --git a/test/runtime/samples/component-slot-fallback-4/main.svelte b/test/runtime/samples/component-slot-fallback-4/main.svelte new file mode 100644 index 0000000000..206ce21def --- /dev/null +++ b/test/runtime/samples/component-slot-fallback-4/main.svelte @@ -0,0 +1,5 @@ + + + diff --git a/test/runtime/samples/component-slot-nested-error-2/Nested.svelte b/test/runtime/samples/component-slot-nested-error-2/Nested.svelte new file mode 100644 index 0000000000..c6f086d96c --- /dev/null +++ b/test/runtime/samples/component-slot-nested-error-2/Nested.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/runtime/samples/component-slot-nested-error-2/_config.js b/test/runtime/samples/component-slot-nested-error-2/_config.js new file mode 100644 index 0000000000..98a9f1cab0 --- /dev/null +++ b/test/runtime/samples/component-slot-nested-error-2/_config.js @@ -0,0 +1,3 @@ +export default { + error: [`Element with a slot='...' attribute must be a child of a component or a descendant of a custom element`] +}; diff --git a/test/runtime/samples/component-slot-nested-error-2/main.svelte b/test/runtime/samples/component-slot-nested-error-2/main.svelte new file mode 100644 index 0000000000..a7142d6dc1 --- /dev/null +++ b/test/runtime/samples/component-slot-nested-error-2/main.svelte @@ -0,0 +1,11 @@ + + + +
+
+
+
+
+ diff --git a/test/runtime/samples/component-slot-nested-error-3/Nested.svelte b/test/runtime/samples/component-slot-nested-error-3/Nested.svelte new file mode 100644 index 0000000000..c6f086d96c --- /dev/null +++ b/test/runtime/samples/component-slot-nested-error-3/Nested.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/runtime/samples/component-slot-nested-error-3/_config.js b/test/runtime/samples/component-slot-nested-error-3/_config.js new file mode 100644 index 0000000000..98a9f1cab0 --- /dev/null +++ b/test/runtime/samples/component-slot-nested-error-3/_config.js @@ -0,0 +1,3 @@ +export default { + error: [`Element with a slot='...' attribute must be a child of a component or a descendant of a custom element`] +}; diff --git a/test/runtime/samples/component-slot-nested-error-3/main.svelte b/test/runtime/samples/component-slot-nested-error-3/main.svelte new file mode 100644 index 0000000000..a63b1defde --- /dev/null +++ b/test/runtime/samples/component-slot-nested-error-3/main.svelte @@ -0,0 +1,11 @@ + + + +
+
+
+
+
+ diff --git a/test/runtime/samples/component-slot-nested-error/Nested.svelte b/test/runtime/samples/component-slot-nested-error/Nested.svelte new file mode 100644 index 0000000000..c6f086d96c --- /dev/null +++ b/test/runtime/samples/component-slot-nested-error/Nested.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/runtime/samples/component-slot-nested-error/_config.js b/test/runtime/samples/component-slot-nested-error/_config.js new file mode 100644 index 0000000000..98a9f1cab0 --- /dev/null +++ b/test/runtime/samples/component-slot-nested-error/_config.js @@ -0,0 +1,3 @@ +export default { + error: [`Element with a slot='...' attribute must be a child of a component or a descendant of a custom element`] +}; diff --git a/test/runtime/samples/component-slot-nested-error/main.svelte b/test/runtime/samples/component-slot-nested-error/main.svelte new file mode 100644 index 0000000000..531c96f08c --- /dev/null +++ b/test/runtime/samples/component-slot-nested-error/main.svelte @@ -0,0 +1,9 @@ + + + +
+
+
+ diff --git a/test/runtime/samples/component-slot-warning/Nested.svelte b/test/runtime/samples/component-slot-warning/Nested.svelte new file mode 100644 index 0000000000..c6f086d96c --- /dev/null +++ b/test/runtime/samples/component-slot-warning/Nested.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/runtime/samples/component-slot-warning/_config.js b/test/runtime/samples/component-slot-warning/_config.js new file mode 100644 index 0000000000..6ffe624782 --- /dev/null +++ b/test/runtime/samples/component-slot-warning/_config.js @@ -0,0 +1,9 @@ +export default { + compileOptions: { + dev: true + }, + warnings: [ + ' received an unexpected slot "default".', + ' received an unexpected slot "slot1".' + ] +}; diff --git a/test/runtime/samples/component-slot-warning/main.svelte b/test/runtime/samples/component-slot-warning/main.svelte new file mode 100644 index 0000000000..c29ef3e85b --- /dev/null +++ b/test/runtime/samples/component-slot-warning/main.svelte @@ -0,0 +1,7 @@ + + + + + diff --git a/test/runtime/samples/dev-warning-unknown-props-with-$$props/Foo.svelte b/test/runtime/samples/dev-warning-unknown-props-with-$$props/Foo.svelte index 9e5c62339d..375b1a6a0a 100644 --- a/test/runtime/samples/dev-warning-unknown-props-with-$$props/Foo.svelte +++ b/test/runtime/samples/dev-warning-unknown-props-with-$$props/Foo.svelte @@ -4,4 +4,4 @@
{foo}
-
{JSON.stringify($$props)}
+
{JSON.stringify($$restProps)}
diff --git a/test/runtime/samples/dev-warning-unknown-props-with-$$rest/Foo.svelte b/test/runtime/samples/dev-warning-unknown-props-with-$$rest/Foo.svelte new file mode 100644 index 0000000000..9e5c62339d --- /dev/null +++ b/test/runtime/samples/dev-warning-unknown-props-with-$$rest/Foo.svelte @@ -0,0 +1,7 @@ + + +
{foo}
+
{JSON.stringify($$props)}
diff --git a/test/runtime/samples/dev-warning-unknown-props-with-$$rest/_config.js b/test/runtime/samples/dev-warning-unknown-props-with-$$rest/_config.js new file mode 100644 index 0000000000..62ad08624d --- /dev/null +++ b/test/runtime/samples/dev-warning-unknown-props-with-$$rest/_config.js @@ -0,0 +1,7 @@ +export default { + compileOptions: { + dev: true + }, + + warnings: [] +}; diff --git a/test/runtime/samples/dev-warning-unknown-props-with-$$rest/main.svelte b/test/runtime/samples/dev-warning-unknown-props-with-$$rest/main.svelte new file mode 100644 index 0000000000..1566cf3e41 --- /dev/null +++ b/test/runtime/samples/dev-warning-unknown-props-with-$$rest/main.svelte @@ -0,0 +1,5 @@ + + + diff --git a/test/runtime/samples/each-block-keyed-else/_config.js b/test/runtime/samples/each-block-keyed-else/_config.js new file mode 100644 index 0000000000..a5bf722a80 --- /dev/null +++ b/test/runtime/samples/each-block-keyed-else/_config.js @@ -0,0 +1,37 @@ +export default { + props: { + animals: ['alpaca', 'baboon', 'capybara'], + foo: 'something else' + }, + + html: ` + before +

alpaca

+

baboon

+

capybara

+ after + `, + + test({ assert, component, target }) { + component.animals = []; + assert.htmlEqual(target.innerHTML, ` + before +

no animals, but rather something else

+ after + `); + + component.foo = 'something other'; + assert.htmlEqual(target.innerHTML, ` + before +

no animals, but rather something other

+ after + `); + + component.animals = ['wombat']; + assert.htmlEqual(target.innerHTML, ` + before +

wombat

+ after + `); + } +}; diff --git a/test/runtime/samples/each-block-keyed-else/main.svelte b/test/runtime/samples/each-block-keyed-else/main.svelte new file mode 100644 index 0000000000..2a82653ff1 --- /dev/null +++ b/test/runtime/samples/each-block-keyed-else/main.svelte @@ -0,0 +1,12 @@ + + +before +{#each animals as animal (animal)} +

{animal}

+{:else} +

no animals, but rather {foo}

+{/each} +after diff --git a/test/runtime/samples/each-block-unkeyed-else-2/_config.js b/test/runtime/samples/each-block-unkeyed-else-2/_config.js new file mode 100644 index 0000000000..a5bf722a80 --- /dev/null +++ b/test/runtime/samples/each-block-unkeyed-else-2/_config.js @@ -0,0 +1,37 @@ +export default { + props: { + animals: ['alpaca', 'baboon', 'capybara'], + foo: 'something else' + }, + + html: ` + before +

alpaca

+

baboon

+

capybara

+ after + `, + + test({ assert, component, target }) { + component.animals = []; + assert.htmlEqual(target.innerHTML, ` + before +

no animals, but rather something else

+ after + `); + + component.foo = 'something other'; + assert.htmlEqual(target.innerHTML, ` + before +

no animals, but rather something other

+ after + `); + + component.animals = ['wombat']; + assert.htmlEqual(target.innerHTML, ` + before +

wombat

+ after + `); + } +}; diff --git a/test/runtime/samples/each-block-unkeyed-else-2/main.svelte b/test/runtime/samples/each-block-unkeyed-else-2/main.svelte new file mode 100644 index 0000000000..3275cb1f83 --- /dev/null +++ b/test/runtime/samples/each-block-unkeyed-else-2/main.svelte @@ -0,0 +1,12 @@ + + +before +{#each animals as animal} +

{animal}

+{:else} +

no animals, but rather {foo}

+{/each} +after diff --git a/test/runtime/samples/event-handler-each-modifier/_config.js b/test/runtime/samples/event-handler-each-modifier/_config.js new file mode 100644 index 0000000000..702addd3c3 --- /dev/null +++ b/test/runtime/samples/event-handler-each-modifier/_config.js @@ -0,0 +1,42 @@ +export default { + async test({ assert, component, target, window }) { + // set first + await component.lists.update(() => [ + { text: "item1" }, + { text: "item2" }, + { text: "item3" } + ]); + + await component.lists.update(() => [ + { text: "item3" }, + { text: "item2" }, + { text: "item1" } + ]); + + await component.lists.update(() => [ + { text: "item1" }, + { text: "item2" }, + { text: "item3" } + ]); + + assert.equal(component.updated, 4); + + const [item1, item2] = target.childNodes; + const [item1Btn1, item1Btn2] = item1.querySelectorAll('button'); + const [item2Btn1, item2Btn2] = item2.querySelectorAll('button'); + + const clickEvent = new window.MouseEvent('click'); + + await item1Btn1.dispatchEvent(clickEvent); + assert.equal(component.getNormalCount(), 1); + + await item1Btn2.dispatchEvent(clickEvent); + assert.equal(component.getModifierCount(), 1); + + await item2Btn1.dispatchEvent(clickEvent); + assert.equal(component.getNormalCount(), 2); + + await item2Btn2.dispatchEvent(clickEvent); + assert.equal(component.getModifierCount(), 2); + } +}; diff --git a/test/runtime/samples/event-handler-each-modifier/main.svelte b/test/runtime/samples/event-handler-each-modifier/main.svelte new file mode 100644 index 0000000000..ca7447f728 --- /dev/null +++ b/test/runtime/samples/event-handler-each-modifier/main.svelte @@ -0,0 +1,37 @@ + + +{#each $lists as item (item.text)} +
+ {item.text} + + +
+{/each} diff --git a/test/runtime/samples/self-reference-component/Countdown.svelte b/test/runtime/samples/self-reference-component/Countdown.svelte new file mode 100644 index 0000000000..21178f2567 --- /dev/null +++ b/test/runtime/samples/self-reference-component/Countdown.svelte @@ -0,0 +1,7 @@ + + +{#if count > 0} + +{/if} \ No newline at end of file diff --git a/test/runtime/samples/self-reference-component/_config.js b/test/runtime/samples/self-reference-component/_config.js new file mode 100644 index 0000000000..e3e0ad3a4f --- /dev/null +++ b/test/runtime/samples/self-reference-component/_config.js @@ -0,0 +1,3 @@ +export default { + html: '5 4 3 2 1 0', +}; \ No newline at end of file diff --git a/test/runtime/samples/self-reference-component/main.svelte b/test/runtime/samples/self-reference-component/main.svelte new file mode 100644 index 0000000000..fd28ec4e40 --- /dev/null +++ b/test/runtime/samples/self-reference-component/main.svelte @@ -0,0 +1,10 @@ + + +{count} + + + + \ No newline at end of file diff --git a/test/runtime/samples/transition-css-iframe/Foo.svelte b/test/runtime/samples/transition-css-iframe/Foo.svelte new file mode 100644 index 0000000000..c79672f21b --- /dev/null +++ b/test/runtime/samples/transition-css-iframe/Foo.svelte @@ -0,0 +1,16 @@ + + +{#if visible} +
+{/if} \ No newline at end of file diff --git a/test/runtime/samples/transition-css-iframe/Frame.svelte b/test/runtime/samples/transition-css-iframe/Frame.svelte new file mode 100644 index 0000000000..c7ac9cf76f --- /dev/null +++ b/test/runtime/samples/transition-css-iframe/Frame.svelte @@ -0,0 +1,58 @@ + + + + + diff --git a/test/runtime/samples/transition-css-iframe/_config.js b/test/runtime/samples/transition-css-iframe/_config.js new file mode 100644 index 0000000000..507efe44f4 --- /dev/null +++ b/test/runtime/samples/transition-css-iframe/_config.js @@ -0,0 +1,18 @@ +export default { + skip_if_ssr: true, + + async test({ assert, component, target, window, raf }) { + const frame = target.querySelector('iframe'); + await Promise.resolve(); + + component.visible = true; + const div = frame.contentDocument.querySelector('div'); + + raf.tick(25); + + component.visible = false; + + raf.tick(26); + assert.ok(~div.style.animation.indexOf('25ms')); + }, +}; diff --git a/test/runtime/samples/transition-css-iframe/main.svelte b/test/runtime/samples/transition-css-iframe/main.svelte new file mode 100644 index 0000000000..b1686ff15e --- /dev/null +++ b/test/runtime/samples/transition-css-iframe/main.svelte @@ -0,0 +1,8 @@ + + + \ No newline at end of file diff --git a/test/validator/samples/binding-const-field/errors.json b/test/validator/samples/binding-const-field/errors.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/test/validator/samples/binding-const-field/errors.json @@ -0,0 +1 @@ +[] diff --git a/test/validator/samples/binding-const-field/input.svelte b/test/validator/samples/binding-const-field/input.svelte new file mode 100644 index 0000000000..055a16438d --- /dev/null +++ b/test/validator/samples/binding-const-field/input.svelte @@ -0,0 +1,7 @@ + + + diff --git a/test/validator/samples/binding-const/errors.json b/test/validator/samples/binding-const/errors.json new file mode 100644 index 0000000000..6d48af9c4e --- /dev/null +++ b/test/validator/samples/binding-const/errors.json @@ -0,0 +1,15 @@ +[{ + "code": "invalid-binding", + "message": "Cannot bind to a variable which is not writable", + "pos": 61, + "start": { + "line": 5, + "column": 19, + "character": 61 + }, + "end": { + "line": 5, + "column": 24, + "character": 66 + } +}] \ No newline at end of file diff --git a/test/validator/samples/binding-const/input.svelte b/test/validator/samples/binding-const/input.svelte new file mode 100644 index 0000000000..1857a1932c --- /dev/null +++ b/test/validator/samples/binding-const/input.svelte @@ -0,0 +1,5 @@ + + + diff --git a/test/validator/samples/component-slotted-custom-element-2/errors.json b/test/validator/samples/component-slotted-custom-element-2/errors.json new file mode 100644 index 0000000000..06be51d72d --- /dev/null +++ b/test/validator/samples/component-slotted-custom-element-2/errors.json @@ -0,0 +1,9 @@ +[ + { + "code": "invalid-slotted-content", + "message": "Element with a slot='...' attribute must be a child of a component or a descendant of a custom element", + "start": { "line": 10, "column": 9, "character": 138 }, + "end": { "line": 10, "column": 19, "character": 148 }, + "pos": 138 + } +] diff --git a/test/validator/samples/component-slotted-custom-element-2/input.svelte b/test/validator/samples/component-slotted-custom-element-2/input.svelte new file mode 100644 index 0000000000..221659ca4d --- /dev/null +++ b/test/validator/samples/component-slotted-custom-element-2/input.svelte @@ -0,0 +1,14 @@ + + + + + {#if thing} +
+
+
+ {/if} + + \ No newline at end of file diff --git a/test/validator/samples/component-slotted-custom-element/errors.json b/test/validator/samples/component-slotted-custom-element/errors.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/test/validator/samples/component-slotted-custom-element/errors.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/test/validator/samples/component-slotted-custom-element/input.svelte b/test/validator/samples/component-slotted-custom-element/input.svelte new file mode 100644 index 0000000000..e0e27834c1 --- /dev/null +++ b/test/validator/samples/component-slotted-custom-element/input.svelte @@ -0,0 +1,15 @@ + + + + +
+
+
+ {#if thing} +
+ {/if} + + \ No newline at end of file diff --git a/test/validator/samples/component-slotted-each-block/errors.json b/test/validator/samples/component-slotted-each-block/errors.json index 89f394bca4..2944acae17 100644 --- a/test/validator/samples/component-slotted-each-block/errors.json +++ b/test/validator/samples/component-slotted-each-block/errors.json @@ -1,6 +1,6 @@ [{ "code": "invalid-slotted-content", - "message": "Cannot place slotted elements inside an each-block", + "message": "Element with a slot='...' attribute must be a child of a component or a descendant of a custom element", "start": { "line": 7, "column": 7, diff --git a/test/validator/samples/component-slotted-if-block/errors.json b/test/validator/samples/component-slotted-if-block/errors.json index ab35a77fce..3ae07c1b3b 100644 --- a/test/validator/samples/component-slotted-if-block/errors.json +++ b/test/validator/samples/component-slotted-if-block/errors.json @@ -1,6 +1,6 @@ [{ "code": "invalid-slotted-content", - "message": "Cannot place slotted elements inside an if-block", + "message": "Element with a slot='...' attribute must be a child of a component or a descendant of a custom element", "start": { "line": 7, "column": 7, diff --git a/test/validator/samples/slot-attribute-invalid/errors.json b/test/validator/samples/slot-attribute-invalid/errors.json index fc01fa9792..a75fdc065c 100644 --- a/test/validator/samples/slot-attribute-invalid/errors.json +++ b/test/validator/samples/slot-attribute-invalid/errors.json @@ -1,6 +1,6 @@ [{ "code": "invalid-slotted-content", - "message": "Element with a slot='...' attribute must be a descendant of a component or custom element", + "message": "Element with a slot='...' attribute must be a child of a component or a descendant of a custom element", "start": { "line": 1, "column": 5,