diff --git a/.eslintignore b/.eslintignore index bfe7b1fa9544..b5cb03ae6e62 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,6 +4,9 @@ _output test/*/samples/*/output.js node_modules +# automatically generated +internal_exports.ts + # output files animate/*.js esing/*.js diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2488902b249a..14824ecdfae2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,3 +23,9 @@ jobs: - uses: actions/checkout@v1 - uses: actions/setup-node@v1 - run: 'npm i && npm run lint' + Unit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-node@v1 + - run: 'npm i && npm run test:unit' diff --git a/.gitignore b/.gitignore index b0e6896dbeba..7a1424492996 100644 --- a/.gitignore +++ b/.gitignore @@ -33,5 +33,8 @@ _output /site/static/svelte-app.json /site/static/contributors.jpg /site/static/workers +/site/static/organisations /site/scripts/svelte-app +/site/scripts/community /site/src/routes/_contributors.js +/site/src/routes/_components/WhosUsingSvelte.svelte diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 81451039faf5..000000000000 --- a/.prettierrc +++ /dev/null @@ -1,3 +0,0 @@ -useTabs: true -singleQuote: true -trailingComma: es5 diff --git a/CHANGELOG.md b/CHANGELOG.md index c5fccddcb5f7..f1564848b561 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,100 @@ # Svelte changelog +## 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)) + +## 3.19.1 + +* Do not treat modifications to `$$props` as updates to a store called `$props` ([#4368](https://github.com/sveltejs/svelte/issues/4368)) +* Deconflict `value` parameter name used in contextual bindings ([#4445](https://github.com/sveltejs/svelte/issues/4445)) +* Fix dev mode validation of `{#each}` blocks using strings ([#4450](https://github.com/sveltejs/svelte/issues/4450)) + +## 3.19.0 + +* Fix indirect bindings involving elements with spreads ([#3680](https://github.com/sveltejs/svelte/issues/3680)) +* `$capture_state`/`$inject_state` now act on the component's entire state, rather than its props ([#3822](https://github.com/sveltejs/svelte/pull/3822)) +* Warn when using `` and `Foo` is dynamic ([#4331](https://github.com/sveltejs/svelte/issues/4331)) +* Display compilation warnings in `svelte/register` in dev mode ([#4364](https://github.com/sveltejs/svelte/issues/4364)) +* Fix unneeded updating of keyed each blocks ([#4373](https://github.com/sveltejs/svelte/issues/4373)) +* Throw runtime error in dev mode for non-array-like values in `{#each}` blocks ([#4408](https://github.com/sveltejs/svelte/issues/4408)) + +## 3.18.2 + +* Fix binding to module-level variables ([#4086](https://github.com/sveltejs/svelte/issues/4086)) +* Improve parsing error messages when there is a pending unclosed tag ([#4131](https://github.com/sveltejs/svelte/issues/4131)) +* Disallow attribute/prop names from matching two-way-bound names or `{shorthand}` attribute/prop names ([#4325](https://github.com/sveltejs/svelte/issues/4325)) +* Improve performance of `flush()` by not using `.shift()` ([#4356](https://github.com/sveltejs/svelte/pull/4356)) +* Permit reserved keywords as destructuring keys in `{#each}` ([#4372](https://github.com/sveltejs/svelte/issues/4372)) +* Disallow reserved keywords in `{expressions}` ([#4372](https://github.com/sveltejs/svelte/issues/4372)) +* Fix code generation error with precedence of arrow functions ([#4384](https://github.com/sveltejs/svelte/issues/4384)) +* Fix event handlers that are dynamic via reactive declarations or stores ([#4388](https://github.com/sveltejs/svelte/issues/4388)) +* Fix invalidation in expressions like `++foo.bar` ([#4393](https://github.com/sveltejs/svelte/issues/4393)) + +## 3.18.1 + +* Fix code generation error with adjacent inline and block comments ([#4312](https://github.com/sveltejs/svelte/issues/4312)) +* Fix detection of unused CSS selectors that begin with a `:global()` but contain a scoped portion ([#4314](https://github.com/sveltejs/svelte/issues/4314)) + +## 3.18.0 + +* Fix infinite loop when instantiating another component during `onMount` ([#3218](https://github.com/sveltejs/svelte/issues/3218)) +* Make autosubscribing to a nullish store a no-op ([#2181](https://github.com/sveltejs/svelte/issues/2181)) + +## 3.17.3 + +* Fix updating a `` inside an `{#if}` or other block ([#4292](https://github.com/sveltejs/svelte/issues/4292)) +* Fix using RxJS observables in `derived` stores ([#4298](https://github.com/sveltejs/svelte/issues/4298)) +* Add dev mode check to disallow duplicate keys in a keyed `{#each}` ([#4301](https://github.com/sveltejs/svelte/issues/4301)) +* Fix hydration of `` when starting from SSR-generated code with `hydratable: true` ([#4310](https://github.com/sveltejs/svelte/issues/4310)) + +## 3.17.2 + +* Fix removing attributes during hydration ([#1733](https://github.com/sveltejs/svelte/issues/1733)) +* Disallow two-way binding to a variable declared by an `{#await}` block ([#4012](https://github.com/sveltejs/svelte/issues/4012)) +* Allow access to `let:` variables in sibling attributes on slot root ([#4173](https://github.com/sveltejs/svelte/issues/4173)) +* Fix `~=` and class selector matching against values separated by any whitespace characters ([#4242](https://github.com/sveltejs/svelte/issues/4242)) +* Fix code generation for `await`ed expressions that need parentheses ([#4267](https://github.com/sveltejs/svelte/issues/4267)) +* Preserve JavaScript comments from the original component source where possible ([#4268](https://github.com/sveltejs/svelte/issues/4268)) +* Add some more known globals ([#4276](https://github.com/sveltejs/svelte/pull/4276)) +* Correctly apply event modifiers to `<svelte:body>` events ([#4278](https://github.com/sveltejs/svelte/issues/4278)) + +## 3.17.1 + +* Only attach SSR mode markers to a component's `<head>` elements when compiling with `hydratable: true` ([#4258](https://github.com/sveltejs/svelte/issues/4258)) + +## 3.17.0 + +* Remove old `<head>` elements during hydration so they aren't duplicated ([#1607](https://github.com/sveltejs/svelte/issues/1607)) +* Prevent text input cursor jumping in Safari with one-way binding ([#3449](https://github.com/sveltejs/svelte/issues/3449)) +* Expose compiler version in dev events ([#4047](https://github.com/sveltejs/svelte/issues/4047)) +* Don't run actions before their element is in the document ([#4166](https://github.com/sveltejs/svelte/issues/4166)) +* Fix reactive assignments with destructuring and stores where the destructured value should be undefined ([#4170](https://github.com/sveltejs/svelte/issues/4170)) +* Fix hydrating `{:else}` in `{#each}` ([#4202](https://github.com/sveltejs/svelte/issues/4202)) +* Do not automatically declare variables in reactive declarations when assigning to a member expression ([#4212](https://github.com/sveltejs/svelte/issues/4212)) +* Fix stringifying of attributes in SSR mode when there are spread attributes ([#4240](https://github.com/sveltejs/svelte/issues/4240)) +* Only render one `<title>` in SSR mode when multiple components provide one ([#4250](https://github.com/sveltejs/svelte/pull/4250)) + +## 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)) +* Apply directives in the order they're given ([#2446](https://github.com/sveltejs/svelte/issues/2446)) +* Fix destructuring in `let:` directives ([#2751](https://github.com/sveltejs/svelte/issues/2751)) +* Preserve whitespace around `<tspan>`s in `<svg>`s ([#3998](https://github.com/sveltejs/svelte/issues/3998)) + ## 3.16.5 * Better fix for cascading invalidations and fix some regressions ([#4098](https://github.com/sveltejs/svelte/issues/4098), [#4114](https://github.com/sveltejs/svelte/issues/4114), [#4120](https://github.com/sveltejs/svelte/issues/4120)) diff --git a/LICENSE b/LICENSE index b63fe48148fa..a8e26a756d84 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2016-19 [these people](https://github.com/sveltejs/svelte/graphs/contributors) +Copyright (c) 2016-20 [these people](https://github.com/sveltejs/svelte/graphs/contributors) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/README.md b/README.md index 9460efce76b3..fa725804a984 100644 --- a/README.md +++ b/README.md @@ -7,15 +7,6 @@ <img src="https://img.shields.io/npm/v/svelte.svg" alt="npm version"> </a> - <a href="https://packagephobia.now.sh/result?p=svelte"> - <img src="https://packagephobia.now.sh/badge?p=svelte" alt="install size"> - </a> - - <a href="https://github.com/sveltejs/svelte/actions"> - <img src="https://github.com/sveltejs/svelte/workflows/CI/badge.svg?branch=master" - alt="build status"> - </a> - <a href="https://github.com/sveltejs/svelte/blob/master/LICENSE"> <img src="https://img.shields.io/npm/l/svelte.svg" alt="license"> </a> @@ -41,6 +32,8 @@ cd svelte npm install ``` +> Do not use Yarn to install the dependencies, as the specific package versions in `package-lock.json` are used to build and test Svelte. + > Many tests depend on newlines being preserved as `<LF>`. On Windows, you can ensure this by cloning with: > ```bash > git -c core.autocrlf=false clone https://github.com/sveltejs/svelte.git diff --git a/package-lock.json b/package-lock.json index f3eb85835834..014348f37eef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "3.16.5", + "version": "3.19.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -30,16 +30,119 @@ "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 + } + } + }, + "@tootallnate/once": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.0.0.tgz", + "integrity": "sha512-KYyTT/T6ALPkIRd2Ge080X/BsXvy9O0hcWTtMWkPvwAwF99+vn6Dv4GzrFT/Nn1LePr+FFDbRXXlqmsy9lw2zA==", + "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", @@ -500,9 +603,9 @@ "dev": true }, "code-red": { - "version": "0.0.27", - "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.27.tgz", - "integrity": "sha512-MSILIi8kkSGag76TW+PRfBP/dN++Ei+uTeiUfqW4Es5teFNrbsAWtyAbPwxKI1vxEsBx64loAfGxS1kVCo1d2g==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.1.1.tgz", + "integrity": "sha512-2pEIyya4fxI9HxQcrl9dJl20+9He1nLeja50zkf7gK2OTTV9NpD3CgA74gzXnPqWv2zJpa6uXNSaE0haOCpOsw==", "dev": true, "requires": { "acorn": "^7.1.0", @@ -512,16 +615,16 @@ } }, "codecov": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/codecov/-/codecov-3.5.0.tgz", - "integrity": "sha512-/OsWOfIHaQIr7aeZ4pY0UC1PZT6kimoKFOFYFNb6wxo3iw12nRrh+mNGH72rnXxNsq6SGfesVPizm/6Q3XqcFQ==", + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/codecov/-/codecov-3.6.5.tgz", + "integrity": "sha512-v48WuDMUug6JXwmmfsMzhCHRnhUf8O3duqXvltaYJKrO1OekZWpB/eH6iIoaxMl8Qli0+u3OxptdsBOYiD7VAQ==", "dev": true, "requires": { - "argv": "^0.0.2", - "ignore-walk": "^3.0.1", - "js-yaml": "^3.13.1", - "teeny-request": "^3.11.3", - "urlgrey": "^0.4.4" + "argv": "0.0.2", + "ignore-walk": "3.0.3", + "js-yaml": "3.13.1", + "teeny-request": "6.0.1", + "urlgrey": "0.4.4" } }, "color-convert": { @@ -1496,9 +1599,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", @@ -1573,6 +1676,37 @@ "whatwg-encoding": "^1.0.1" } }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "agent-base": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.0.tgz", + "integrity": "sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -1585,9 +1719,9 @@ } }, "https-proxy-agent": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz", - "integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", "dev": true, "requires": { "agent-base": "^4.3.0", @@ -1610,9 +1744,9 @@ "dev": true }, "ignore-walk": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", - "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", + "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", "dev": true, "requires": { "minimatch": "^3.0.4" @@ -3058,85 +3192,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==", + "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": { - "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==", - "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 +3209,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" @@ -3336,6 +3399,15 @@ "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", "dev": true }, + "stream-events": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", + "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", + "dev": true, + "requires": { + "stubs": "^3.0.0" + } + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -3383,6 +3455,12 @@ "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", "dev": true }, + "stubs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", + "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=", + "dev": true + }, "sucrase": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.10.1.tgz", @@ -3423,14 +3501,43 @@ } }, "teeny-request": { - "version": "3.11.3", - "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-3.11.3.tgz", - "integrity": "sha512-CKncqSF7sH6p4rzCgkb/z/Pcos5efl0DmolzvlqRQUNcpRIruOhY9+T1FsIlyEbfWd7MsFpodROOwHYh2BaXzw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-6.0.1.tgz", + "integrity": "sha512-TAK0c9a00ELOqLrZ49cFxvPVogMUFaWY8dUsQc/0CuQPGF+BOxOQzXfE413BAk2kLomwNplvdtMpeaeGWmoc2g==", "dev": true, "requires": { - "https-proxy-agent": "^2.2.1", + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^4.0.0", "node-fetch": "^2.2.0", + "stream-events": "^1.0.5", "uuid": "^3.3.2" + }, + "dependencies": { + "agent-base": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", + "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==", + "dev": true + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "https-proxy-agent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", + "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", + "dev": true, + "requires": { + "agent-base": "5", + "debug": "4" + } + } } }, "test-exclude": { diff --git a/package.json b/package.json index 36eaf2e323de..009e5143a925 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "3.16.5", + "version": "3.19.2", "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", @@ -64,7 +70,7 @@ "acorn": "^7.1.0", "agadoo": "^1.1.0", "c8": "^5.0.1", - "code-red": "0.0.27", + "code-red": "0.1.1", "codecov": "^3.5.0", "css-tree": "1.0.0-alpha22", "eslint": "^6.3.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", diff --git a/register.js b/register.js index 3278c1cbf5cb..25f8aa430974 100644 --- a/register.js +++ b/register.js @@ -36,7 +36,15 @@ function registerExtension(extension) { format: 'cjs' }); - const { js } = compile(fs.readFileSync(filename, 'utf-8'), options); + const { js, warnings } = compile(fs.readFileSync(filename, 'utf-8'), options); + + if (options.dev) { + warnings.forEach(warning => { + console.warn(`\nSvelte Warning in ${warning.filename}:`); + console.warn(warning.message); + console.warn(warning.frame); + }) + } return module._compile(js.code, filename); }; diff --git a/rollup.config.js b/rollup.config.js index c55cbf2426f5..6f3d893a33a4 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -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; @@ -60,6 +60,9 @@ export default [ ], external, plugins: [ + replace({ + __VERSION__: pkg.version + }), ts_plugin, { writeBundle(bundle) { diff --git a/site/Dockerfile b/site/Dockerfile index c2a65122d9e3..0261a6952124 100644 --- a/site/Dockerfile +++ b/site/Dockerfile @@ -1,3 +1,6 @@ +# IMPORTANT: Don't use this Dockerfile in your own Sapper projects without also looking at the .dockerignore file. +# Without an appropriate .dockerignore, this Dockerfile will copy a large number of unneeded files into your image. + FROM mhart/alpine-node:12 # install dependencies diff --git a/site/Makefile b/site/Makefile index 4c432dc6c94d..6fd08fd8ee19 100644 --- a/site/Makefile +++ b/site/Makefile @@ -14,9 +14,9 @@ sapper: docker: @echo "\n~> building docker image" - @gcloud builds submit -t $(IMAGE) + @gcloud builds submit --project $(PROJECT) -t $(IMAGE) deploy: sapper docker @echo "\n~> deploying $(SERVICE) to Cloud Run servers" - @gcloud beta run deploy $(SERVICE) --allow-unauthenticated --platform managed --region us-central1 --image $(IMAGE) --memory=512Mi + @gcloud run deploy $(SERVICE) --project $(PROJECT) --allow-unauthenticated --platform managed --region us-central1 --image $(IMAGE) --memory=512Mi 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 7a107c590b7e..b80223d82077 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 @@ -60,7 +60,7 @@ To treat `*.svelte` files as HTML, add the following lines to your `settings.jso ## 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. +The [Svelte Framework Integration](https://plugins.jetbrains.com/plugin/12375-svelte/) can be used to add support for Svelte to WebStorm, or other Jetbrains IDEs. Consult the [WebStorm plugin installation guide](https://www.jetbrains.com/help/webstorm/managing-plugins.html) on the JetBrains website for more details. ## Sublime Text 3 diff --git a/site/content/blog/2019-04-16-svelte-for-new-developers.md b/site/content/blog/2019-04-16-svelte-for-new-developers.md index fc8e993e8824..796a6c11abbb 100644 --- a/site/content/blog/2019-04-16-svelte-for-new-developers.md +++ b/site/content/blog/2019-04-16-svelte-for-new-developers.md @@ -18,7 +18,7 @@ You'll be using the *command line*, also known as the terminal. On Windows, you The command line is a way to interact with your computer (or another computer! but that's a topic for another time) with more power and control than the GUI (graphical user interface) that most people use day-to-day. -Once on the command line, you can navigate the filesystem using `ls` to list the contents of your current directory, and `cd` to change the current directory. For example, if you had a `Development` directory of your projects inside your home directory, you would type +Once on the command line, you can navigate the filesystem using `ls` (`dir` on Windows) to list the contents of your current directory, and `cd` to change the current directory. For example, if you had a `Development` directory of your projects inside your home directory, you would type ```bash cd Development @@ -34,7 +34,7 @@ cd svelte-projects A full introduction to the command line is out of the scope of this guide, but here are a few more useful commands: * `cd ..` — navigates to the parent of the current directory -* `cat my-file.txt` — on Mac/Linux, lists the contents of `my-file.txt` +* `cat my-file.txt` — on Mac/Linux (`type my-file.txt` on Windows), lists the contents of `my-file.txt` * `open .` (or `start .` on Windows) — opens the current directory in Finder or File Explorer diff --git a/site/content/blog/2019-04-20-write-less-code.md b/site/content/blog/2019-04-20-write-less-code.md index d6c8b771938a..d56c5312e87b 100644 --- a/site/content/blog/2019-04-20-write-less-code.md +++ b/site/content/blog/2019-04-20-write-less-code.md @@ -159,6 +159,6 @@ In Vue, meanwhile, we have a default export with a `data` function that returns ## Death to boilerplate -These are just some of the ways that Svelte helps you build user interfaces with a minimum of fuss. There are plenty of others — for example, [reactive declarations](https://svelte.dev/tutorial/reactive-declarations) essentially do the work of React's `useMemo`, `useCallback` and `useEffect` without the boilerplate (or indeed the garbage collection overhead of creating inline functions and arrays on each state change). +These are just some of the ways that Svelte helps you build user interfaces with a minimum of fuss. There are plenty of others — for example, [reactive declarations](tutorial/reactive-declarations) essentially do the work of React's `useMemo`, `useCallback` and `useEffect` without the boilerplate (or indeed the garbage collection overhead of creating inline functions and arrays on each state change). How? By choosing a different set of constraints. Because [Svelte is a compiler](blog/frameworks-without-the-framework), we're not bound to the peculiarities of JavaScript: we can *design* a component authoring experience, rather than having to fit it around the semantics of the language. Paradoxically, this results in *more* idiomatic code — for example using variables naturally rather than via proxies or hooks — while delivering significantly more performant apps. diff --git a/site/content/docs/00-introduction.md b/site/content/docs/00-introduction.md index 2456b85f9c8f..15fdffbde205 100644 --- a/site/content/docs/00-introduction.md +++ b/site/content/docs/00-introduction.md @@ -2,8 +2,8 @@ title: Before we begin --- -> Temporary note: This document is a work-in-progress. Please forgive any missing or misleading parts, and don't be shy about asking for help in the [Discord chatroom](chat). The [tutorial](tutorial) is more complete; start there. - This page contains detailed API reference documentation. It's intended to be a resource for people who already have some familiarity with Svelte. If that's not you (yet), you may prefer to visit the [interactive tutorial](tutorial) or the [examples](examples) before consulting this reference. + +Don't be shy about asking for help in the [Discord chatroom](chat). \ No newline at end of file diff --git a/site/content/docs/01-component-format.md b/site/content/docs/01-component-format.md index 3d349af51d16..07a59c69f8ce 100644 --- a/site/content/docs/01-component-format.md +++ b/site/content/docs/01-component-format.md @@ -42,13 +42,13 @@ Svelte uses the `export` keyword to mark a variable declaration as a *property* --- -You can specify a default value, which will be used if the component's consumer doesn't specify a prop. +You can specify a default initial value for a prop. It will be used if the component's consumer doesn't specify the prop on the component (or if its initial value is `undefined`) when instantiating the component. Note that whenever a prop is removed by the consumer, its value is set to `undefined` rather than the initial value. -In development mode (see the [compiler options](docs#svelte_compile)), a warning will be printed if no default is provided and the consumer does not specify a value. To squelch this warning, ensure that a default is specified, even if it is `undefined`. +In development mode (see the [compiler options](docs#svelte_compile)), a warning will be printed if no default initial value is provided and the consumer does not specify a value. To squelch this warning, ensure that a default initial value is specified, even if it is `undefined`. ```html <script> - export let bar = 'optional default value'; + export let bar = 'optional default initial value'; export let baz = undefined; </script> ``` @@ -147,24 +147,7 @@ If a statement consists entirely of an assignment to an undeclared variable, Sve --- -A *store* is any object that allows reactive access to a value via a simple *store contract*. - -The [`svelte/store` module](docs#svelte_store) contains minimal store implementations which fulfil this contract. You can use these as the basis for your own stores, or you can implement your stores from scratch. - -A store must contain a `.subscribe` method, which must accept as its argument a subscription function. This subscription function must be immediately and synchronously called with the store's current value upon calling `.subscribe`. All of a store's active subscription functions must later be synchronously called whenever the store's value changes. The `.subscribe` method must also return an unsubscription function. Calling an unsubscription function must stop its subscription, and its corresponding subscription function must not be called again by the store. - -A store may optionally contain a `.set` method, which must accept as its argument a new value for the store, and which synchronously calls all of the store's active subscription functions. Such a store is called a *writable store*. - -```js -const unsubscribe = store.subscribe(value => { - console.log(value); -}); // logs `value` - -// later... -unsubscribe(); -``` - ---- +A *store* is an object that allows reactive access to a value via a simple *store contract*. The [`svelte/store` module](docs#svelte_store) contains minimal store implementations which fulfil this contract. Any time you have a reference to a store, you can access its value inside a component by prefixing it with the `$` character. This causes Svelte to declare the prefixed variable, and set up a store subscription that will be unsubscribed when appropriate. @@ -189,6 +172,20 @@ Local variables (that do not represent store values) must *not* have a `$` prefi </script> ``` +##### Store contract + +```js +store = { subscribe: (subscription: (value: any) => void) => () => void, set?: (value: any) => void } +``` + +You can create your own stores without relying on [`svelte/store`](docs#svelte_store), by implementing the *store contract*: + +1. A store must contain a `.subscribe` method, which must accept as its argument a subscription function. This subscription function must be immediately and synchronously called with the store's current value upon calling `.subscribe`. All of a store's active subscription functions must later be synchronously called whenever the store's value changes. +2. The `.subscribe` method must return an unsubscribe function. Calling an unsubscribe function must stop its subscription, and its corresponding subscription function must not be called again by the store. +3. A store may *optionally* contain a `.set` method, which must accept as its argument a new value for the store, and which synchronously calls all of the store's active subscription functions. Such a store is called a *writable store*. + +For interoperability with RxJS Observables, the `.subscribe` method is also allowed to return an object with an `.unsubscribe` method, rather than return the unsubscription function directly. Note however that unless `.subscribe` synchronously calls the subscription (which is not required by the Observable spec), Svelte will see the value of the store as `undefined` until it does. + ### <script context="module"> @@ -200,7 +197,7 @@ You can `export` bindings from this block, and they will become exports of the c You cannot `export default`, since the default export is the component itself. -> Variables defined in `module` scripts are not reactive — reassigning them will not trigger a rerender even though the variable itself will update. For values shared between multiple components, consider using a [store](https://svelte.dev/docs#svelte_store). +> Variables defined in `module` scripts are not reactive — reassigning them will not trigger a rerender even though the variable itself will update. For values shared between multiple components, consider using a [store](docs#svelte_store). ```html <script context="module"> @@ -256,3 +253,15 @@ To apply styles to a selector globally, use the `:global(...)` modifier. } </style> ``` + +--- + +If you want to make @keyframes that are accessible globally, you need to prepend your keyframe names with `-global-`. + +The `-global-` part will be removed when compiled, and the keyframe then be referenced using just `my-animation-name` elsewhere in your code. + +```html +<style> + @keyframes -global-my-animation-name {...} +</style> +``` diff --git a/site/content/docs/02-template-syntax.md b/site/content/docs/02-template-syntax.md index 89506753d65e..d25b348254db 100644 --- a/site/content/docs/02-template-syntax.md +++ b/site/content/docs/02-template-syntax.md @@ -58,6 +58,17 @@ Or they can *be* JavaScript expressions. --- +Boolean attributes are included on the element if their value is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) and excluded if it's [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy). + +All other attributes are included unless their value is [nullish](https://developer.mozilla.org/en-US/docs/Glossary/Nullish) (`null` or `undefined`). + +```html +<input required={false} placeholder="This input field is not required"> +<div title={null}>This div has no title attribute</div> +``` + +--- + An expression might include characters that would cause syntax highlighting to fail in regular HTML, so quoting the value is permitted. The quotes do not affect how the value is parsed: ```html @@ -205,6 +216,8 @@ Iterating over lists of values can be done with an each block. </ul> ``` +You can use each blocks to iterate over any array or array-like value — that is, any object with a `length` property. + --- An each block can also specify an *index*, equivalent to the second argument in an `array.map(...)` callback: @@ -793,7 +806,7 @@ transition = (node: HTMLElement, params: any) => { A transition is triggered by an element entering or leaving the DOM as a result of a state change. -Elements inside an *outroing* block are kept in the DOM until all current transitions have completed. +When a block is transitioning out, elements inside the block are kept in the DOM until all current transitions have completed. The `transition:` directive indicates a *bidirectional* transition, which means it can be smoothly reversed while the transition is in progress. @@ -1016,7 +1029,7 @@ DOMRect { ​top: number, width: number, x: number, - y:number + y: number } ``` @@ -1202,14 +1215,16 @@ The content is exposed in the child component using the `<slot>` element, which ```html <!-- App.svelte --> +<Widget></Widget> + <Widget> - <p>this is some child content</p> + <p>this is some child content that will overwrite the default slot content</p> </Widget> <!-- Widget.svelte --> <div> <slot> - this will be rendered if someone does <Widget/> + this fallback content will be rendered when no content is provided, like in the first example </slot> </div> ``` @@ -1245,15 +1260,15 @@ The usual shorthand rules apply — `let:item` is equivalent to `let:item={item} ```html <!-- App.svelte --> -<FancyList {items} let:item={item}> - <div>{item.text}</div> +<FancyList {items} let:prop={thing}> + <div>{thing.text}</div> </FancyList> <!-- FancyList.svelte --> <ul> {#each items as item} <li class="fancy"> - <slot item={item}></slot> + <slot prop={item}></slot> </li> {/each} </ul> @@ -1266,7 +1281,7 @@ Named slots can also expose values. The `let:` directive goes on the element wit ```html <!-- App.svelte --> <FancyList {items}> - <div slot="item" let:item={item}>{item.text}</div> + <div slot="item" let:item>{item.text}</div> <p slot="footer">Copyright (c) 2019 Svelte Industries</p> </FancyList> @@ -1274,7 +1289,7 @@ Named slots can also expose values. The `let:` directive goes on the element wit <ul> {#each items as item} <li class="fancy"> - <slot name="item" item={item}></slot> + <slot name="item" {item}></slot> </li> {/each} </ul> diff --git a/site/content/docs/03-run-time.md b/site/content/docs/03-run-time.md index 14093b526478..c75ec694d932 100644 --- a/site/content/docs/03-run-time.md +++ b/site/content/docs/03-run-time.md @@ -214,7 +214,11 @@ Events dispatched from child components can be listened to in their parent. Any ### `svelte/store` -The `svelte/store` module exports functions for creating [stores](docs#4_Prefix_stores_with_$_to_access_their_values). +The `svelte/store` module exports functions for creating [readable](docs#readable), [writable](docs#writable) and [derived](docs#derived) stores. + +Keep in mind that you don't *have* to use these functions to enjoy the [reactive `$store` syntax](docs#4_Prefix_stores_with_$_to_access_their_values) in your components. Any object that correctly implements `.subscribe`, unsubscribe, and (optionally) `.set` is a valid store, and will work both with the special syntax, and with Svelte's built-in [`derived` stores](docs#derived). + +This makes it possible to wrap almost any other reactive state handling library for use in Svelte. Read more about the [store contract](docs#Store_contract) to see what a correct implementation looks like. #### `writable` @@ -489,7 +493,7 @@ A `spring` store gradually changes to its target value based on its `stiffness` --- -As with [`tweened`](#tweened) stores, `set` and `update` return a Promise that resolves if the spring settles. The `store.stiffness` and `store.damping` properties can be changed while the spring is in motion, and will take immediate effect. +As with [`tweened`](docs#tweened) stores, `set` and `update` return a Promise that resolves if the spring settles. The `store.stiffness` and `store.damping` properties can be changed while the spring is in motion, and will take immediate effect. Both `set` and `update` can take a second argument — an object with `hard` or `soft` properties. `{ hard: true }` sets the target value immediately; `{ soft: n }` preserves existing momentum for `n` seconds before settling. `{ soft: true }` is equivalent to `{ soft: 0.5 }`. @@ -883,7 +887,7 @@ Existing children of `target` are left where they are. --- -The `hydrate` option instructs Svelte to upgrade existing DOM (usually from server-side rendering) rather than creating new elements. It will only work if the component was compiled with the [`hydratable: true` option](docs#svelte_compile). +The `hydrate` option instructs Svelte to upgrade existing DOM (usually from server-side rendering) rather than creating new elements. It will only work if the component was compiled with the [`hydratable: true` option](docs#svelte_compile). Hydration of `<head>` elements only works properly if the server-side rendering code was also compiled with `hydratable: true`, which adds a marker to each element in the `<head>` so that the component knows which elements it's responsible for removing during hydration. Whereas children of `target` are normally left alone, `hydrate: true` will cause any children to be removed. For that reason, the `anchor` option cannot be used alongside `hydrate: true`. diff --git a/site/content/docs/04-compile-time.md b/site/content/docs/04-compile-time.md index e9126ccf1316..f9bfa772fec1 100644 --- a/site/content/docs/04-compile-time.md +++ b/site/content/docs/04-compile-time.md @@ -68,7 +68,7 @@ The following options can be passed to the compiler. None are required: | `generate` | `"dom"` | If `"dom"`, Svelte emits a JavaScript class for mounting to the DOM. If `"ssr"`, Svelte emits an object with a `render` method suitable for server-side rendering. If `false`, no JavaScript or CSS is returned; just metadata. | `dev` | `false` | If `true`, causes extra code to be added to components that will perform runtime checks and provide debugging information during development. | `immutable` | `false` | If `true`, tells the compiler that you promise not to mutate any objects. This allows it to be less conservative about checking whether values have changed. -| `hydratable` | `false` | If `true`, enables the `hydrate: true` runtime option, which allows a component to upgrade existing DOM rather than creating new DOM from scratch. +| `hydratable` | `false` | If `true` when generating DOM code, enables the `hydrate: true` runtime option, which allows a component to upgrade existing DOM rather than creating new DOM from scratch. When generating SSR code, this adds markers to `<head>` elements so that hydration knows which to replace. | `legacy` | `false` | If `true`, generates code that will work in IE9 and IE10, which don't support things like `element.dataset`. | `accessors` | `false` | If `true`, getters and setters will be created for the component's props. If `false`, they will only be created for readonly exported values (i.e. those declared with `const`, `class` and `function`). If compiling with `customElement: true` this option defaults to `true`. | `customElement` | `false` | If `true`, tells the compiler to generate a custom element constructor instead of a regular Svelte component. @@ -76,7 +76,7 @@ The following options can be passed to the compiler. None are required: | `css` | `true` | If `true`, styles will be included in the JavaScript class and injected at runtime. It's recommended that you set this to `false` and use the CSS that is statically generated, as it will result in smaller JavaScript bundles and better performance. | `loopGuardTimeout` | 0 | A `number` that tells Svelte to break the loop if it blocks the thread for more than `loopGuardTimeout` ms. This is useful to prevent infinite loops. **Only available when `dev: true`** | `preserveComments` | `false` | If `true`, your HTML comments will be preserved during server-side rendering. By default, they are stripped out. -| `preserveWhitespace` | `false` | If `true`, whitespace inside and between elements is kept as you typed it, rather than optimised by Svelte. +| `preserveWhitespace` | `false` | If `true`, whitespace inside and between elements is kept as you typed it, rather than removed or collapsed to a single space where possible. | `outputFilename` | `null` | A `string` used for your JavaScript sourcemap. | `cssOutputFilename` | `null` | A `string` used for your CSS sourcemap. | `sveltePath` | `"svelte"` | The location of the `svelte` package. Any imports from `svelte` or `svelte/[module]` will be modified accordingly. @@ -113,7 +113,8 @@ const { * `module` is `true` if the value is declared in a `context="module"` script * `mutated` is `true` if the value's properties are assigned to inside the component * `reassigned` is `true` if the value is reassigned inside the component - * `referenced` is `true` if the value is used outside the declaration + * `referenced` is `true` if the value is used in the template + * `referenced_from_script` is `true` if the value is used in the `<script>` outside the declaration * `writable` is `true` if the value was declared with `let` or `var` (but not `const`, `class` or `function`) * `stats` is an object used by the Svelte developer team for diagnosing the compiler. Avoid relying on it to stay the same! @@ -144,6 +145,7 @@ compiled: { mutated: boolean, reassigned: boolean, referenced: boolean, + referenced_from_script: boolean, writable: boolean }>, stats: { @@ -185,7 +187,7 @@ const ast = svelte.parse(source, { filename: 'App.svelte' }); result: { code: string, dependencies: Array<string> -} = svelte.preprocess( +} = await svelte.preprocess( source: string, preprocessors: Array<{ markup?: (input: { content: string, filename: string }) => Promise<{ @@ -222,7 +224,7 @@ The `markup` function receives the entire component source text, along with the ```js const svelte = require('svelte/compiler'); -const { code } = svelte.preprocess(source, { +const { code } = await svelte.preprocess(source, { markup: ({ content, filename }) => { return { code: content.replace(/foo/g, 'bar') @@ -244,7 +246,7 @@ const svelte = require('svelte/compiler'); const sass = require('node-sass'); const { dirname } = require('path'); -const { code, dependencies } = svelte.preprocess(source, { +const { code, dependencies } = await svelte.preprocess(source, { style: async ({ content, attributes, filename }) => { // only process <style lang="sass"> if (attributes.lang !== 'sass') return; @@ -277,7 +279,7 @@ Multiple preprocessors can be used together. The output of the first becomes the ```js const svelte = require('svelte/compiler'); -const { code } = svelte.preprocess(source, [ +const { code } = await svelte.preprocess(source, [ { markup: () => { console.log('this runs first'); diff --git a/site/content/examples/04-events/05-dom-event-forwarding/App.svelte b/site/content/examples/04-events/05-dom-event-forwarding/App.svelte index 1429cae207d8..e75c78106ac3 100644 --- a/site/content/examples/04-events/05-dom-event-forwarding/App.svelte +++ b/site/content/examples/04-events/05-dom-event-forwarding/App.svelte @@ -1,9 +1,9 @@ <script> - import FancyButton from './FancyButton.svelte'; + import CustomButton from './CustomButton.svelte'; function handleClick() { alert('clicked'); } </script> -<FancyButton on:click={handleClick}/> \ No newline at end of file +<CustomButton on:click={handleClick}/> \ No newline at end of file diff --git a/site/content/examples/04-events/05-dom-event-forwarding/CustomButton.svelte b/site/content/examples/04-events/05-dom-event-forwarding/CustomButton.svelte new file mode 100644 index 000000000000..f521c1f4713a --- /dev/null +++ b/site/content/examples/04-events/05-dom-event-forwarding/CustomButton.svelte @@ -0,0 +1,22 @@ +<style> + button { + height: 4rem; + width: 8rem; + background-color: #aaa; + border-color: #f1c40f; + color: #f1c40f; + font-size: 1.25rem; + background-image: linear-gradient(45deg, #f1c40f 50%, transparent 50%); + background-position: 100%; + background-size: 400%; + transition: background 300ms ease-in-out; + } + button:hover { + background-position: 0; + color: #aaa; + } +</style> + +<button on:click> + Click me +</button> \ No newline at end of file diff --git a/site/content/examples/04-events/05-dom-event-forwarding/FancyButton.svelte b/site/content/examples/04-events/05-dom-event-forwarding/FancyButton.svelte deleted file mode 100644 index 68dcc68636a9..000000000000 --- a/site/content/examples/04-events/05-dom-event-forwarding/FancyButton.svelte +++ /dev/null @@ -1,15 +0,0 @@ -<style> - button { - font-family: 'Comic Sans MS', cursive; - font-size: 2em; - padding: 0.5em 1em; - color: royalblue; - background: gold; - border-radius: 1em; - box-shadow: 2px 2px 4px rgba(0,0,0,0.5); - } -</style> - -<button on:click> - Click me -</button> \ No newline at end of file diff --git a/site/content/tutorial/05-events/06-dom-event-forwarding/app-a/App.svelte b/site/content/tutorial/05-events/06-dom-event-forwarding/app-a/App.svelte index 1429cae207d8..e75c78106ac3 100644 --- a/site/content/tutorial/05-events/06-dom-event-forwarding/app-a/App.svelte +++ b/site/content/tutorial/05-events/06-dom-event-forwarding/app-a/App.svelte @@ -1,9 +1,9 @@ <script> - import FancyButton from './FancyButton.svelte'; + import CustomButton from './CustomButton.svelte'; function handleClick() { alert('clicked'); } </script> -<FancyButton on:click={handleClick}/> \ No newline at end of file +<CustomButton on:click={handleClick}/> \ No newline at end of file diff --git a/site/content/tutorial/05-events/06-dom-event-forwarding/app-a/CustomButton.svelte b/site/content/tutorial/05-events/06-dom-event-forwarding/app-a/CustomButton.svelte new file mode 100644 index 000000000000..0955930b5d59 --- /dev/null +++ b/site/content/tutorial/05-events/06-dom-event-forwarding/app-a/CustomButton.svelte @@ -0,0 +1,22 @@ +<style> + button { + height: 4rem; + width: 8rem; + background-color: #aaa; + border-color: #f1c40f; + color: #f1c40f; + font-size: 1.25rem; + background-image: linear-gradient(45deg, #f1c40f 50%, transparent 50%); + background-position: 100%; + background-size: 400%; + transition: background 300ms ease-in-out; + } + button:hover { + background-position: 0; + color: #aaa; + } +</style> + +<button> + Click me +</button> \ No newline at end of file diff --git a/site/content/tutorial/05-events/06-dom-event-forwarding/app-a/FancyButton.svelte b/site/content/tutorial/05-events/06-dom-event-forwarding/app-a/FancyButton.svelte deleted file mode 100644 index b75f19a1f25c..000000000000 --- a/site/content/tutorial/05-events/06-dom-event-forwarding/app-a/FancyButton.svelte +++ /dev/null @@ -1,15 +0,0 @@ -<style> - button { - font-family: 'Comic Sans MS', cursive; - font-size: 2em; - padding: 0.5em 1em; - color: royalblue; - background: gold; - border-radius: 1em; - box-shadow: 2px 2px 4px rgba(0,0,0,0.5); - } -</style> - -<button> - Click me -</button> \ No newline at end of file diff --git a/site/content/tutorial/05-events/06-dom-event-forwarding/app-b/App.svelte b/site/content/tutorial/05-events/06-dom-event-forwarding/app-b/App.svelte index 1429cae207d8..e75c78106ac3 100644 --- a/site/content/tutorial/05-events/06-dom-event-forwarding/app-b/App.svelte +++ b/site/content/tutorial/05-events/06-dom-event-forwarding/app-b/App.svelte @@ -1,9 +1,9 @@ <script> - import FancyButton from './FancyButton.svelte'; + import CustomButton from './CustomButton.svelte'; function handleClick() { alert('clicked'); } </script> -<FancyButton on:click={handleClick}/> \ No newline at end of file +<CustomButton on:click={handleClick}/> \ No newline at end of file diff --git a/site/content/tutorial/05-events/06-dom-event-forwarding/app-b/CustomButton.svelte b/site/content/tutorial/05-events/06-dom-event-forwarding/app-b/CustomButton.svelte new file mode 100644 index 000000000000..f521c1f4713a --- /dev/null +++ b/site/content/tutorial/05-events/06-dom-event-forwarding/app-b/CustomButton.svelte @@ -0,0 +1,22 @@ +<style> + button { + height: 4rem; + width: 8rem; + background-color: #aaa; + border-color: #f1c40f; + color: #f1c40f; + font-size: 1.25rem; + background-image: linear-gradient(45deg, #f1c40f 50%, transparent 50%); + background-position: 100%; + background-size: 400%; + transition: background 300ms ease-in-out; + } + button:hover { + background-position: 0; + color: #aaa; + } +</style> + +<button on:click> + Click me +</button> \ No newline at end of file diff --git a/site/content/tutorial/05-events/06-dom-event-forwarding/app-b/FancyButton.svelte b/site/content/tutorial/05-events/06-dom-event-forwarding/app-b/FancyButton.svelte deleted file mode 100644 index 68dcc68636a9..000000000000 --- a/site/content/tutorial/05-events/06-dom-event-forwarding/app-b/FancyButton.svelte +++ /dev/null @@ -1,15 +0,0 @@ -<style> - button { - font-family: 'Comic Sans MS', cursive; - font-size: 2em; - padding: 0.5em 1em; - color: royalblue; - background: gold; - border-radius: 1em; - box-shadow: 2px 2px 4px rgba(0,0,0,0.5); - } -</style> - -<button on:click> - Click me -</button> \ No newline at end of file diff --git a/site/content/tutorial/05-events/06-dom-event-forwarding/text.md b/site/content/tutorial/05-events/06-dom-event-forwarding/text.md index 0959e1d98b17..be9ae77f8912 100644 --- a/site/content/tutorial/05-events/06-dom-event-forwarding/text.md +++ b/site/content/tutorial/05-events/06-dom-event-forwarding/text.md @@ -4,7 +4,7 @@ title: DOM event forwarding Event forwarding works for DOM events too. -We want to get notified of clicks on our `<FancyButton>` — to do that, we just need to forward `click` events on the `<button>` element in `FancyButton.svelte`: +We want to get notified of clicks on our `<CustomButton>` — to do that, we just need to forward `click` events on the `<button>` element in `CustomButton.svelte`: ```html <button on:click> diff --git a/site/content/tutorial/12-actions/01-actions/text.md b/site/content/tutorial/12-actions/01-actions/text.md index 38de8f9a6592..3706b31e7c62 100644 --- a/site/content/tutorial/12-actions/01-actions/text.md +++ b/site/content/tutorial/12-actions/01-actions/text.md @@ -23,7 +23,9 @@ import { pannable } from './pannable.js'; on:panstart={handlePanStart} on:panmove={handlePanMove} on:panend={handlePanEnd} - style="transform: translate({$coords.x}px,{$coords.y}px)" + style="transform: + translate({$coords.x}px,{$coords.y}px) + rotate({$coords.x * 0.2}deg)" ></div> ``` diff --git a/site/package.json b/site/package.json index d841808a2aaf..a94d26421781 100644 --- a/site/package.json +++ b/site/package.json @@ -7,7 +7,7 @@ "copy-workers": "rm -rf static/workers && cp -r node_modules/@sveltejs/svelte-repl/workers static", "migrate": "node-pg-migrate -r dotenv/config", "sapper": "npm run copy-workers && sapper build --legacy", - "update": "node scripts/update_template.js && node scripts/get-contributors.js", + "update": "node scripts/update_template.js && node scripts/get-contributors.js && node scripts/update_whos_using.js", "start": "node __sapper__/build", "test": "mocha -r esm test/**", "deploy": "make deploy" diff --git a/site/scripts/update_whos_using.js b/site/scripts/update_whos_using.js new file mode 100644 index 000000000000..131a1623597a --- /dev/null +++ b/site/scripts/update_whos_using.js @@ -0,0 +1,12 @@ +const sh = require('shelljs'); + +sh.cd(__dirname + '/../'); + +// fetch community repo +sh.rm('-rf','scripts/community'); +sh.exec('npx degit sveltejs/community scripts/community'); + +// copy over relevant files +sh.cp('scripts/community/whos-using-svelte/WhosUsingSvelte.svelte', 'src/routes/_components/WhosUsingSvelte.svelte'); +sh.rm('-rf', 'static/organisations'); +sh.cp('-r', 'scripts/community/whos-using-svelte/organisations', 'static'); diff --git a/site/src/routes/_components/Contributors.svelte b/site/src/routes/_components/Contributors.svelte new file mode 100644 index 000000000000..74eb3fa50f1a --- /dev/null +++ b/site/src/routes/_components/Contributors.svelte @@ -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} diff --git a/site/src/routes/_components/WhosUsingSvelte.svelte b/site/src/routes/_components/WhosUsingSvelte.svelte deleted file mode 100644 index f27f1684e60a..000000000000 --- a/site/src/routes/_components/WhosUsingSvelte.svelte +++ /dev/null @@ -1,94 +0,0 @@ -<!-- - Instructions for adding new logos: - - * Fork this repo, and clone your fork - * Create a branch called e.g. `add-myorganisation-logo` - * Add the logo to the `static/organisations` directory (preferably SVG) - * Add a new <a> tag in this component, in alphabetical order - * Create a pull request. Thanks! ---> - -<style> - .logos { - margin: 1em 0 0 0; - display: flex; - flex-wrap: wrap; - } - - a { - height: 40px; - margin: 0 0.5em 0.5em 0; - display: flex; - align-items: center; - border: 2px solid var(--second); - padding: 5px 10px; - border-radius: 20px; - color: var(--text); - } - - .add-yourself { - color: var(--prime); - } - - picture, - img { - height: 100%; - } - - @media (min-width: 540px) { - a { - height: 60px; - padding: 10px 20px; - border-radius: 30px; - } - } -</style> - -<div class="logos"> - <a target="_blank" rel="noopener" href="https://absoluteweb.com"><img src="organisations/absoluteweb.svg" alt="Absolute Web logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://bekchy.com"><img src="organisations/bekchy.png" alt="Bekchy logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://beyonk.com"><img src="organisations/beyonk.svg" alt="Beyonk logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://buydotstar.com"><img src="organisations/buydotstar.svg" alt="buy.* logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://cashfree.com/"><img src="organisations/cashfree.svg" alt="Cashfree logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://chess.com" style="background-color: rgb(49,46,43);"><img src="organisations/chess.svg" alt="Chess.com logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://comigosaude.com.br"><img src="organisations/comigo.svg" alt="Comigo logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://datawrapper.de"><img src="organisations/datawrapper.svg" alt="Datawrapper logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://db.nomics.world" style="background-color: rgb(15,39,47);"><picture><source type="image/webp" srcset="organisations/dbnomics.webp"><img src="organisations/dbnomics.jpg" alt="DBNomics logo" loading="lazy"></picture></a> - <a target="_blank" rel="noopener" href="https://deck.nl"><img src="organisations/deck.svg" alt="Deck logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://dextra.com.br/pt/"><img src="organisations/dextra.png" alt="Dextra logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://www.entriwise.com/"><img src="organisations/entriwise.png" alt="Entriwise logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://www.entur.org/about-entur/" style="background-color: rgb(25, 25, 84);"><img src="organisations/entur.svg" alt="Entur logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://from-now-on.com"><img src="organisations/from-now-on.png" alt="From-Now-On logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://fusioncharts.com"><img src="organisations/fusioncharts.svg" alt="FusionCharts logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://godaddy.com"><img src="organisations/godaddy.svg" alt="GoDaddy logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://www.grainger.com"><img src="organisations/grainger.svg" alt="Grainger logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="http://healthtree.org/"><img src="organisations/healthtree.png" alt="HealthTree logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://itslearning.com"><img src="organisations/itslearning.svg" alt="itslearning logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://jacoux.com"><img src="organisations/jacoux.png" alt="Jacoux logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://jingmnt.co.za"><img src="organisations/jingmnt.png" alt="Jingmnt logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://www.mentorcv.com"><img src="organisations/mentorcv.png" alt="Mentor CV logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://www.metrovias.com.ar/"><img src="organisations/metrovias.svg" alt="Metrovias logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="http://mustlab.ru"><img src="organisations/mustlab.png" alt="Mustlab logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://www.nesta.org.uk"><img src="organisations/nesta.svg" alt="Nesta logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://www.nonkositelecoms.com"><img src="organisations/nonkosi.svg" alt="Nonkosi Telecoms logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://www.nzz.ch"><img src="organisations/nzz.svg" alt="Neue Zürcher Zeitung logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://nytimes.com"><img src="organisations/nyt.svg" alt="The New York Times logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://oberonspace.xyz"><img src="organisations/oberonspace.svg" alt="OberonSPACE logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://ofof.nl"><img src="organisations/ofof.png" alt="Ofof logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://openstate.eu"><img src="organisations/open-state-foundation.svg" alt="Open State Foundation logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://panascais.net"><img src="organisations/panascais.svg" alt="Panascais logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://pankod.com"><img src="organisations/pankod.svg" alt="Pankod logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://paperform.co"><img src="organisations/paperform.svg" alt="Paperform logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://razorpay.com"><img src="organisations/razorpay.svg" alt="Razorpay logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://sp.nl"><img src="organisations/socialist-party.svg" alt="Socialist Party logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://sqltribe.com"><img src="organisations/sqltribe.svg" alt="SQL Tribe logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://www.stone.co"><img src="organisations/stone.svg" alt="Stone Payments logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://www.strixengine.com"><img src="organisations/strixcloud.svg" alt="Strix Cloud logo" loading="lazy"><span>Strix Cloud</span></a> - <a target="_blank" rel="noopener" href="https://sucuri.net" style="background-color: rgb(93, 93, 93);"><img src="organisations/sucuri.png" alt="Sucuri logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://tsh.io"><img src="organisations/tsh.svg" alt="The Software House logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://thunderdome.dev"><img src="organisations/thunderdome.svg" alt="Thunderdome logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://m.tokopedia.com"><img src="organisations/tokopedia.svg" alt="Tokopedia logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://webdesq.net"><img src="organisations/webdesq.svg" alt="Webdesq logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://zevvle.com/"><img src="organisations/zevvle.svg" alt="Zevvle logo" loading="lazy"></a> - <a target="_blank" rel="noopener" href="https://github.com/sveltejs/svelte/blob/master/site/src/routes/_components/WhosUsingSvelte.svelte" class="add-yourself"><span>+ your company?</span></a> -</div> diff --git a/site/src/routes/blog/index.svelte b/site/src/routes/blog/index.svelte index 6f96731af065..92fc5ce96d73 100644 --- a/site/src/routes/blog/index.svelte +++ b/site/src/routes/blog/index.svelte @@ -11,7 +11,7 @@ <svelte:head> <title>Blog • Svelte - + diff --git a/site/src/routes/examples/_TableOfContents.svelte b/site/src/routes/examples/_TableOfContents.svelte index f89a9741ae67..d5a8b7240f84 100644 --- a/site/src/routes/examples/_TableOfContents.svelte +++ b/site/src/routes/examples/_TableOfContents.svelte @@ -29,34 +29,48 @@ font-weight: 700; } + div { + display: flex; + flex-direction: row; + padding: 0.2rem 3rem; + margin: 0 -3rem; + } + + div.active { + background: rgba(0, 0, 0, 0.15) calc(100% - 3rem) 47% no-repeat + url(/icons/arrow-right.svg); + background-size: 1em 1em; + color: white; + } + + div.active.loading { + background: rgba(0, 0, 0, 0.1) calc(100% - 3rem) 47% no-repeat + url(/icons/loading.svg); + background-size: 1em 1em; + color: white; + } + a { display: flex; + flex: 1 1 auto; position: relative; color: var(--sidebar-text); border-bottom: none; - padding: 0.2rem 3rem; - margin: 0 -3rem; font-size: 1.6rem; align-items: center; justify-content: start; + padding: 0; } a:hover { color: white; } - a.active { - background: rgba(0, 0, 0, 0.15) calc(100% - 3rem) 50% no-repeat - url(/icons/arrow-right.svg); - background-size: 1em 1em; - color: white; - } - - a.active.loading { - background: rgba(0, 0, 0, 0.1) calc(100% - 3rem) 50% no-repeat - url(/icons/loading.svg); - background-size: 1em 1em; - color: white; + .repl-link { + flex: 0 1 auto; + font-size: 1.2rem; + font-weight: 700; + margin-right: 2.5rem; } .thumbnail { @@ -72,27 +86,31 @@ diff --git a/site/src/routes/index.svelte b/site/src/routes/index.svelte index edf1e4d36c7f..73fbffbc6a59 100644 --- a/site/src/routes/index.svelte +++ b/site/src/routes/index.svelte @@ -1,9 +1,9 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/test/custom-elements/samples/extended-builtin/test.js b/test/custom-elements/samples/extended-builtin/test.js index d676fd137b53..3886ae11498f 100644 --- a/test/custom-elements/samples/extended-builtin/test.js +++ b/test/custom-elements/samples/extended-builtin/test.js @@ -11,5 +11,5 @@ export default function (target) { const el = target.querySelector('custom-element'); const button = el.shadowRoot.querySelector('button'); - assert.ok(button instanceof customElements.get('fancy-button')); + assert.ok(button instanceof customElements.get('custom-button')); } \ No newline at end of file diff --git a/test/helpers.js b/test/helpers.js index 2a03e0f436f4..a764d43f9646 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -45,6 +45,12 @@ export function tryToReadFile(file) { } } +export function cleanRequireCache() { + Object.keys(require.cache) + .filter(x => x.endsWith('.svelte')) + .forEach(file => delete require.cache[file]); +} + const virtualConsole = new jsdom.VirtualConsole(); virtualConsole.sendTo(console); @@ -68,6 +74,7 @@ window.scrollTo = function(pageXOffset, pageYOffset) { export function env() { window.document.title = ''; + window.document.head.innerHTML = ''; window.document.body.innerHTML = '
'; return window; diff --git a/test/hydration/index.js b/test/hydration/index.js index a0bfd6de4b98..f57a0cdc1aca 100644 --- a/test/hydration/index.js +++ b/test/hydration/index.js @@ -67,8 +67,16 @@ describe('hydration', () => { } const target = window.document.body; + const head = window.document.head; + target.innerHTML = fs.readFileSync(`${cwd}/_before.html`, 'utf-8'); + let before_head; + try { + before_head = fs.readFileSync(`${cwd}/_before_head.html`, 'utf-8'); + head.innerHTML = before_head; + } catch (err) {} + const snapshot = config.snapshot ? config.snapshot(target) : {}; const component = new SvelteComponent({ @@ -88,6 +96,19 @@ describe('hydration', () => { } } + if (before_head) { + try { + assert.htmlEqual(head.innerHTML, fs.readFileSync(`${cwd}/_after_head.html`, 'utf-8')); + } catch (error) { + if (shouldUpdateExpected()) { + fs.writeFileSync(`${cwd}/_after_head.html`, head.innerHTML); + console.log(`Updated ${cwd}/_after_head.html.`); + } else { + throw error; + } + } + } + if (config.test) { config.test(assert, target, snapshot, component, window); } else { diff --git a/test/hydration/samples/each-else/_after.html b/test/hydration/samples/each-else/_after.html new file mode 100644 index 000000000000..7920500ec3fe --- /dev/null +++ b/test/hydration/samples/each-else/_after.html @@ -0,0 +1,4 @@ +

Hello, world

+

+ weird +

\ No newline at end of file diff --git a/test/hydration/samples/each-else/_before.html b/test/hydration/samples/each-else/_before.html new file mode 100644 index 000000000000..7920500ec3fe --- /dev/null +++ b/test/hydration/samples/each-else/_before.html @@ -0,0 +1,4 @@ +

Hello, world

+

+ weird +

\ No newline at end of file diff --git a/test/hydration/samples/each-else/main.svelte b/test/hydration/samples/each-else/main.svelte new file mode 100644 index 000000000000..64d3a37c5878 --- /dev/null +++ b/test/hydration/samples/each-else/main.svelte @@ -0,0 +1,15 @@ + + +

Hello, {name}

+{#each array as elem} +

+ item +

+{:else} +

+ weird +

+{/each} diff --git a/test/hydration/samples/element-attribute-removed/_before.html b/test/hydration/samples/element-attribute-removed/_before.html index c6a8a8c95d59..80c0591a4d55 100644 --- a/test/hydration/samples/element-attribute-removed/_before.html +++ b/test/hydration/samples/element-attribute-removed/_before.html @@ -1 +1 @@ -
\ No newline at end of file +
\ No newline at end of file diff --git a/test/hydration/samples/head-meta-hydrate-duplicate/_after.html b/test/hydration/samples/head-meta-hydrate-duplicate/_after.html new file mode 100644 index 000000000000..3e5b375f0a59 --- /dev/null +++ b/test/hydration/samples/head-meta-hydrate-duplicate/_after.html @@ -0,0 +1 @@ +
Just a dummy page.
\ No newline at end of file diff --git a/test/hydration/samples/head-meta-hydrate-duplicate/_after_head.html b/test/hydration/samples/head-meta-hydrate-duplicate/_after_head.html new file mode 100644 index 000000000000..10cf2c8b9a06 --- /dev/null +++ b/test/hydration/samples/head-meta-hydrate-duplicate/_after_head.html @@ -0,0 +1,4 @@ +Some Title + + + \ No newline at end of file diff --git a/test/hydration/samples/head-meta-hydrate-duplicate/_before.html b/test/hydration/samples/head-meta-hydrate-duplicate/_before.html new file mode 100644 index 000000000000..3e5b375f0a59 --- /dev/null +++ b/test/hydration/samples/head-meta-hydrate-duplicate/_before.html @@ -0,0 +1 @@ +
Just a dummy page.
\ No newline at end of file diff --git a/test/hydration/samples/head-meta-hydrate-duplicate/_before_head.html b/test/hydration/samples/head-meta-hydrate-duplicate/_before_head.html new file mode 100644 index 000000000000..107753cdd0e5 --- /dev/null +++ b/test/hydration/samples/head-meta-hydrate-duplicate/_before_head.html @@ -0,0 +1,4 @@ +Some Title + + + \ No newline at end of file diff --git a/test/hydration/samples/head-meta-hydrate-duplicate/_config.js b/test/hydration/samples/head-meta-hydrate-duplicate/_config.js new file mode 100644 index 000000000000..482efd564d62 --- /dev/null +++ b/test/hydration/samples/head-meta-hydrate-duplicate/_config.js @@ -0,0 +1,5 @@ +export default { + test(assert, target, snapshot, component, window) { + assert.equal(window.document.querySelectorAll('meta').length, 2); + } +}; diff --git a/test/hydration/samples/head-meta-hydrate-duplicate/main.svelte b/test/hydration/samples/head-meta-hydrate-duplicate/main.svelte new file mode 100644 index 000000000000..1a8b125dd2cf --- /dev/null +++ b/test/hydration/samples/head-meta-hydrate-duplicate/main.svelte @@ -0,0 +1,8 @@ + + Some Title + + + + + +
Just a dummy page.
\ No newline at end of file diff --git a/test/js/samples/action-custom-event-handler/expected.js b/test/js/samples/action-custom-event-handler/expected.js index 6c3a2a5b0b30..ead6d90e0639 100644 --- a/test/js/samples/action-custom-event-handler/expected.js +++ b/test/js/samples/action-custom-event-handler/expected.js @@ -1,6 +1,7 @@ /* generated by Svelte vX.Y.Z */ import { SvelteComponent, + action_destroyer, detach, element, init, @@ -13,6 +14,7 @@ import { function create_fragment(ctx) { let button; let foo_action; + let dispose; return { c() { @@ -21,16 +23,16 @@ function create_fragment(ctx) { }, m(target, anchor) { insert(target, button, anchor); - foo_action = foo.call(null, button, /*foo_function*/ ctx[1]) || ({}); + dispose = action_destroyer(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(); } }; } @@ -41,7 +43,7 @@ function handleFoo(bar) { function foo(node, callback) { -} +} // code goes here function instance($$self, $$props, $$invalidate) { let { bar } = $$props; diff --git a/test/js/samples/action/expected.js b/test/js/samples/action/expected.js index 78fc4855c624..22d9cd939c2c 100644 --- a/test/js/samples/action/expected.js +++ b/test/js/samples/action/expected.js @@ -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,6 +14,7 @@ import { function create_fragment(ctx) { let a; let link_action; + let dispose; return { c() { @@ -23,14 +24,14 @@ function create_fragment(ctx) { }, m(target, anchor) { insert(target, a, anchor); - link_action = link.call(null, a) || ({}); + dispose = action_destroyer(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(); } }; } diff --git a/test/js/samples/bind-online/expected.js b/test/js/samples/bind-online/expected.js index 8285646481a2..e129e66d7163 100644 --- a/test/js/samples/bind-online/expected.js +++ b/test/js/samples/bind-online/expected.js @@ -14,13 +14,13 @@ function create_fragment(ctx) { add_render_callback(/*onlinestatuschanged*/ ctx[1]); return { - c() { + c: noop, + m(target, anchor) { dispose = [ listen(window, "online", /*onlinestatuschanged*/ ctx[1]), listen(window, "offline", /*onlinestatuschanged*/ ctx[1]) ]; }, - m: noop, p: noop, i: noop, o: noop, diff --git a/test/js/samples/bind-open/expected.js b/test/js/samples/bind-open/expected.js index d4f148cac9d0..7d66145f0ae7 100644 --- a/test/js/samples/bind-open/expected.js +++ b/test/js/samples/bind-open/expected.js @@ -20,12 +20,11 @@ function create_fragment(ctx) { details.innerHTML = `summarycontent `; - - dispose = listen(details, "toggle", /*details_toggle_handler*/ ctx[1]); }, m(target, anchor) { insert(target, details, anchor); details.open = /*open*/ ctx[0]; + dispose = listen(details, "toggle", /*details_toggle_handler*/ ctx[1]); }, p(ctx, [dirty]) { if (dirty & /*open*/ 1) { diff --git a/test/js/samples/bindings-readonly-order/expected.js b/test/js/samples/bindings-readonly-order/expected.js index cf3068666215..db0e7cb007ae 100644 --- a/test/js/samples/bindings-readonly-order/expected.js +++ b/test/js/samples/bindings-readonly-order/expected.js @@ -26,16 +26,16 @@ function create_fragment(ctx) { input1 = element("input"); attr(input0, "type", "file"); attr(input1, "type", "file"); - - dispose = [ - listen(input0, "change", /*input0_change_handler*/ ctx[1]), - listen(input1, "change", /*input1_change_handler*/ ctx[2]) - ]; }, m(target, anchor) { insert(target, input0, anchor); insert(target, t, anchor); insert(target, input1, anchor); + + dispose = [ + listen(input0, "change", /*input0_change_handler*/ ctx[1]), + listen(input1, "change", /*input1_change_handler*/ ctx[2]) + ]; }, p: noop, i: noop, diff --git a/test/js/samples/capture-inject-dev-only/expected.js b/test/js/samples/capture-inject-dev-only/expected.js index 6c639d9207f6..a314b0cff33b 100644 --- a/test/js/samples/capture-inject-dev-only/expected.js +++ b/test/js/samples/capture-inject-dev-only/expected.js @@ -28,7 +28,6 @@ function create_fragment(ctx) { t0 = text(/*foo*/ ctx[0]); t1 = space(); input = element("input"); - dispose = listen(input, "input", /*input_input_handler*/ ctx[1]); }, m(target, anchor) { insert(target, p, anchor); @@ -36,6 +35,7 @@ function create_fragment(ctx) { insert(target, t1, anchor); insert(target, input, anchor); set_input_value(input, /*foo*/ ctx[0]); + dispose = listen(input, "input", /*input_input_handler*/ ctx[1]); }, p(ctx, [dirty]) { if (dirty & /*foo*/ 1) set_data(t0, /*foo*/ ctx[0]); diff --git a/test/js/samples/capture-inject-state/_config.js b/test/js/samples/capture-inject-state/_config.js new file mode 100644 index 000000000000..414b026a97d6 --- /dev/null +++ b/test/js/samples/capture-inject-state/_config.js @@ -0,0 +1,5 @@ +export default { + options: { + dev: true + } +}; diff --git a/test/js/samples/capture-inject-state/expected.js b/test/js/samples/capture-inject-state/expected.js new file mode 100644 index 000000000000..cd719ac5d25f --- /dev/null +++ b/test/js/samples/capture-inject-state/expected.js @@ -0,0 +1,201 @@ +/* generated by Svelte vX.Y.Z */ +import { + SvelteComponentDev, + add_location, + append_dev, + detach_dev, + dispatch_dev, + element, + init, + insert_dev, + noop, + safe_not_equal, + set_data_dev, + space, + subscribe, + text, + validate_slots, + validate_store +} from "svelte/internal"; + +const file = undefined; + +function create_fragment(ctx) { + let p; + let t0; + let t1; + let t2; + let t3; + let t4; + let t5; + let t6; + let t7; + let t8; + let t9; + let t10; + + const block = { + c: function create() { + p = element("p"); + t0 = text(/*prop*/ ctx[0]); + t1 = space(); + t2 = text(/*realName*/ ctx[1]); + t3 = space(); + t4 = text(/*local*/ ctx[3]); + t5 = space(); + t6 = text(priv); + t7 = space(); + t8 = text(/*$prop*/ ctx[2]); + t9 = space(); + t10 = text(/*shadowedByModule*/ ctx[4]); + add_location(p, file, 22, 0, 430); + }, + l: function claim(nodes) { + throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); + }, + m: function mount(target, anchor) { + insert_dev(target, p, anchor); + append_dev(p, t0); + append_dev(p, t1); + append_dev(p, t2); + append_dev(p, t3); + append_dev(p, t4); + append_dev(p, t5); + append_dev(p, t6); + append_dev(p, t7); + append_dev(p, t8); + append_dev(p, t9); + append_dev(p, t10); + }, + p: function update(ctx, [dirty]) { + if (dirty & /*prop*/ 1) set_data_dev(t0, /*prop*/ ctx[0]); + if (dirty & /*realName*/ 2) set_data_dev(t2, /*realName*/ ctx[1]); + if (dirty & /*$prop*/ 4) set_data_dev(t8, /*$prop*/ ctx[2]); + }, + i: noop, + o: noop, + d: function destroy(detaching) { + if (detaching) detach_dev(p); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_fragment.name, + type: "component", + source: "", + ctx + }); + + return block; +} + +let moduleLiveBinding; +const moduleContantProps = 4; +let moduleLet; +const moduleConst = 2; +let shadowedByModule; +const priv = "priv"; + +function instance($$self, $$props, $$invalidate) { + let $prop, + $$unsubscribe_prop = noop, + $$subscribe_prop = () => ($$unsubscribe_prop(), $$unsubscribe_prop = subscribe(prop, $$value => $$invalidate(2, $prop = $$value)), prop); + + $$self.$$.on_destroy.push(() => $$unsubscribe_prop()); + let { prop } = $$props; + validate_store(prop, "prop"); + $$subscribe_prop(); + let { alias: realName } = $$props; + let local; + let shadowedByModule; + const writable_props = ["prop", "alias"]; + + Object.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(` was created with unknown prop '${key}'`); + }); + + let { $$slots = {}, $$scope } = $$props; + validate_slots("Component", $$slots, []); + + $$self.$set = $$props => { + if ("prop" in $$props) $$subscribe_prop($$invalidate(0, prop = $$props.prop)); + if ("alias" in $$props) $$invalidate(1, realName = $$props.alias); + }; + + $$self.$capture_state = () => ({ + moduleLiveBinding, + moduleContantProps, + moduleLet, + moduleConst, + shadowedByModule, + prop, + realName, + local, + priv, + shadowedByModule, + computed, + $prop + }); + + $$self.$inject_state = $$props => { + if ("prop" in $$props) $$subscribe_prop($$invalidate(0, prop = $$props.prop)); + if ("realName" in $$props) $$invalidate(1, realName = $$props.realName); + if ("local" in $$props) $$invalidate(3, local = $$props.local); + if ("shadowedByModule" in $$props) $$invalidate(4, shadowedByModule = $$props.shadowedByModule); + if ("computed" in $$props) computed = $$props.computed; + }; + + let computed; + + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + + $: computed = local * 2; + return [prop, realName, $prop, local, shadowedByModule]; +} + +class Component extends SvelteComponentDev { + constructor(options) { + super(options); + init(this, options, instance, create_fragment, safe_not_equal, { prop: 0, alias: 1 }); + + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "Component", + options, + id: create_fragment.name + }); + + const { ctx } = this.$$; + const props = options.props || {}; + + if (/*prop*/ ctx[0] === undefined && !("prop" in props)) { + console.warn(" was created without expected prop 'prop'"); + } + + if (/*realName*/ ctx[1] === undefined && !("alias" in props)) { + console.warn(" was created without expected prop 'alias'"); + } + } + + get prop() { + throw new Error(": Props cannot be read directly from the component instance unless compiling with 'accessors: true' or ''"); + } + + set prop(value) { + throw new Error(": Props cannot be set directly on the component instance unless compiling with 'accessors: true' or ''"); + } + + get alias() { + throw new Error(": Props cannot be read directly from the component instance unless compiling with 'accessors: true' or ''"); + } + + set alias(value) { + throw new Error(": Props cannot be set directly on the component instance unless compiling with 'accessors: true' or ''"); + } +} + +export default Component; +export { moduleLiveBinding, moduleContantProps }; \ No newline at end of file diff --git a/test/js/samples/capture-inject-state/input.svelte b/test/js/samples/capture-inject-state/input.svelte new file mode 100644 index 000000000000..a1051bc1470c --- /dev/null +++ b/test/js/samples/capture-inject-state/input.svelte @@ -0,0 +1,23 @@ + + + +

{prop} {realName} {local} {priv} {$prop} {shadowedByModule}

diff --git a/test/js/samples/component-static-var/expected.js b/test/js/samples/component-static-var/expected.js index e01402b6d445..a65d9186a78e 100644 --- a/test/js/samples/component-static-var/expected.js +++ b/test/js/samples/component-static-var/expected.js @@ -35,7 +35,6 @@ function create_fragment(ctx) { create_component(bar.$$.fragment); t1 = space(); input = element("input"); - dispose = listen(input, "input", /*input_input_handler*/ ctx[1]); }, m(target, anchor) { mount_component(foo, target, anchor); @@ -45,6 +44,7 @@ function create_fragment(ctx) { insert(target, input, anchor); set_input_value(input, /*z*/ ctx[0]); current = true; + dispose = listen(input, "input", /*input_input_handler*/ ctx[1]); }, p(ctx, [dirty]) { const bar_changes = {}; diff --git a/test/js/samples/component-store-reassign-invalidate/expected.js b/test/js/samples/component-store-reassign-invalidate/expected.js index 02a74cf22eb3..771b20dec4ea 100644 --- a/test/js/samples/component-store-reassign-invalidate/expected.js +++ b/test/js/samples/component-store-reassign-invalidate/expected.js @@ -31,13 +31,13 @@ function create_fragment(ctx) { t1 = space(); button = element("button"); button.textContent = "reset"; - dispose = listen(button, "click", /*click_handler*/ ctx[2]); }, m(target, anchor) { insert(target, h1, anchor); append(h1, t0); insert(target, t1, anchor); insert(target, button, anchor); + dispose = listen(button, "click", /*click_handler*/ ctx[2]); }, p(ctx, [dirty]) { if (dirty & /*$foo*/ 2) set_data(t0, /*$foo*/ ctx[1]); diff --git a/test/js/samples/debug-empty/expected.js b/test/js/samples/debug-empty/expected.js index 5821faadf1e8..dd142adb26b2 100644 --- a/test/js/samples/debug-empty/expected.js +++ b/test/js/samples/debug-empty/expected.js @@ -12,7 +12,8 @@ import { safe_not_equal, set_data_dev, space, - text + text, + validate_slots } from "svelte/internal"; const file = undefined; @@ -75,18 +76,23 @@ function instance($$self, $$props, $$invalidate) { if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(` was created with unknown prop '${key}'`); }); + let { $$slots = {}, $$scope } = $$props; + validate_slots("Component", $$slots, []); + $$self.$set = $$props => { if ("name" in $$props) $$invalidate(0, name = $$props.name); }; - $$self.$capture_state = () => { - return { name }; - }; + $$self.$capture_state = () => ({ name }); $$self.$inject_state = $$props => { if ("name" in $$props) $$invalidate(0, name = $$props.name); }; + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + return [name]; } @@ -103,7 +109,7 @@ class Component extends SvelteComponentDev { }); const { ctx } = this.$$; - const props = options.props || ({}); + const props = options.props || {}; if (/*name*/ ctx[0] === undefined && !("name" in props)) { console.warn(" was created without expected prop 'name'"); 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 a1d6dba3b355..977702b99f5c 100644 --- a/test/js/samples/debug-foo-bar-baz-things/expected.js +++ b/test/js/samples/debug-foo-bar-baz-things/expected.js @@ -13,7 +13,9 @@ import { safe_not_equal, set_data_dev, space, - text + text, + validate_each_argument, + validate_slots } from "svelte/internal"; const file = undefined; @@ -88,6 +90,7 @@ function create_fragment(ctx) { let t1; let t2; let each_value = /*things*/ ctx[0]; + validate_each_argument(each_value); let each_blocks = []; for (let i = 0; i < each_value.length; i += 1) { @@ -122,6 +125,7 @@ function create_fragment(ctx) { p: function update(ctx, [dirty]) { if (dirty & /*things*/ 1) { each_value = /*things*/ ctx[0]; + validate_each_argument(each_value); let i; for (i = 0; i < each_value.length; i += 1) { @@ -176,6 +180,9 @@ function instance($$self, $$props, $$invalidate) { if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(` was created with unknown prop '${key}'`); }); + let { $$slots = {}, $$scope } = $$props; + validate_slots("Component", $$slots, []); + $$self.$set = $$props => { if ("things" in $$props) $$invalidate(0, things = $$props.things); if ("foo" in $$props) $$invalidate(1, foo = $$props.foo); @@ -183,9 +190,7 @@ function instance($$self, $$props, $$invalidate) { if ("baz" in $$props) $$invalidate(3, baz = $$props.baz); }; - $$self.$capture_state = () => { - return { things, foo, bar, baz }; - }; + $$self.$capture_state = () => ({ things, foo, bar, baz }); $$self.$inject_state = $$props => { if ("things" in $$props) $$invalidate(0, things = $$props.things); @@ -194,6 +199,10 @@ function instance($$self, $$props, $$invalidate) { if ("baz" in $$props) $$invalidate(3, baz = $$props.baz); }; + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + return [things, foo, bar, baz]; } @@ -210,7 +219,7 @@ class Component extends SvelteComponentDev { }); const { ctx } = this.$$; - const props = options.props || ({}); + const props = options.props || {}; if (/*things*/ ctx[0] === undefined && !("things" in props)) { console.warn(" was created without expected prop 'things'"); diff --git a/test/js/samples/debug-foo/expected.js b/test/js/samples/debug-foo/expected.js index af79667cc237..fe62ff77bfb1 100644 --- a/test/js/samples/debug-foo/expected.js +++ b/test/js/samples/debug-foo/expected.js @@ -13,7 +13,9 @@ import { safe_not_equal, set_data_dev, space, - text + text, + validate_each_argument, + validate_slots } from "svelte/internal"; const file = undefined; @@ -82,6 +84,7 @@ function create_fragment(ctx) { let t1; let t2; let each_value = /*things*/ ctx[0]; + validate_each_argument(each_value); let each_blocks = []; for (let i = 0; i < each_value.length; i += 1) { @@ -116,6 +119,7 @@ function create_fragment(ctx) { p: function update(ctx, [dirty]) { if (dirty & /*things*/ 1) { each_value = /*things*/ ctx[0]; + validate_each_argument(each_value); let i; for (i = 0; i < each_value.length; i += 1) { @@ -168,20 +172,25 @@ function instance($$self, $$props, $$invalidate) { if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(` was created with unknown prop '${key}'`); }); + let { $$slots = {}, $$scope } = $$props; + validate_slots("Component", $$slots, []); + $$self.$set = $$props => { if ("things" in $$props) $$invalidate(0, things = $$props.things); if ("foo" in $$props) $$invalidate(1, foo = $$props.foo); }; - $$self.$capture_state = () => { - return { things, foo }; - }; + $$self.$capture_state = () => ({ things, foo }); $$self.$inject_state = $$props => { if ("things" in $$props) $$invalidate(0, things = $$props.things); if ("foo" in $$props) $$invalidate(1, foo = $$props.foo); }; + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + return [things, foo]; } @@ -198,7 +207,7 @@ class Component extends SvelteComponentDev { }); const { ctx } = this.$$; - const props = options.props || ({}); + const props = options.props || {}; if (/*things*/ ctx[0] === undefined && !("things" in props)) { console.warn(" was created without expected prop 'things'"); diff --git a/test/js/samples/debug-hoisted/expected.js b/test/js/samples/debug-hoisted/expected.js index eeb946549965..0e634297f08f 100644 --- a/test/js/samples/debug-hoisted/expected.js +++ b/test/js/samples/debug-hoisted/expected.js @@ -4,7 +4,8 @@ import { dispatch_dev, init, noop, - safe_not_equal + safe_not_equal, + validate_slots } from "svelte/internal"; const file = undefined; @@ -47,19 +48,28 @@ function create_fragment(ctx) { return block; } -function instance($$self) { +function instance($$self, $$props, $$invalidate) { let obj = { x: 5 }; let kobzol = 5; + const writable_props = []; - $$self.$capture_state = () => { - return {}; - }; + Object.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(` was created with unknown prop '${key}'`); + }); + + let { $$slots = {}, $$scope } = $$props; + validate_slots("Component", $$slots, []); + $$self.$capture_state = () => ({ obj, kobzol }); $$self.$inject_state = $$props => { if ("obj" in $$props) $$invalidate(0, obj = $$props.obj); if ("kobzol" in $$props) $$invalidate(1, kobzol = $$props.kobzol); }; + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + return [obj, kobzol]; } diff --git a/test/js/samples/debug-no-dependencies/expected.js b/test/js/samples/debug-no-dependencies/expected.js index 054dda795328..76068e8cf464 100644 --- a/test/js/samples/debug-no-dependencies/expected.js +++ b/test/js/samples/debug-no-dependencies/expected.js @@ -10,7 +10,9 @@ import { noop, safe_not_equal, space, - text + text, + validate_each_argument, + validate_slots } from "svelte/internal"; const file = undefined; @@ -64,6 +66,7 @@ function create_each_block(ctx) { function create_fragment(ctx) { let each_1_anchor; let each_value = things; + validate_each_argument(each_value); let each_blocks = []; for (let i = 0; i < each_value.length; i += 1) { @@ -91,6 +94,7 @@ function create_fragment(ctx) { p: function update(ctx, [dirty]) { if (dirty & /*things*/ 0) { each_value = things; + validate_each_argument(each_value); let i; for (i = 0; i < each_value.length; i += 1) { @@ -131,10 +135,22 @@ function create_fragment(ctx) { return block; } +function instance($$self, $$props) { + const writable_props = []; + + Object.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(` was created with unknown prop '${key}'`); + }); + + let { $$slots = {}, $$scope } = $$props; + validate_slots("Component", $$slots, []); + return []; +} + class Component extends SvelteComponentDev { constructor(options) { super(options); - init(this, options, null, create_fragment, safe_not_equal, {}); + init(this, options, instance, create_fragment, safe_not_equal, {}); dispatch_dev("SvelteRegisterComponent", { component: this, 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 beb794a50c7a..0a50e2cd970a 100644 --- a/test/js/samples/dev-warning-missing-data-computed/expected.js +++ b/test/js/samples/dev-warning-missing-data-computed/expected.js @@ -12,7 +12,8 @@ import { safe_not_equal, set_data_dev, space, - text + text, + validate_slots } from "svelte/internal"; const file = undefined; @@ -72,19 +73,24 @@ function instance($$self, $$props, $$invalidate) { if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(` was created with unknown prop '${key}'`); }); + let { $$slots = {}, $$scope } = $$props; + validate_slots("Component", $$slots, []); + $$self.$set = $$props => { if ("foo" in $$props) $$invalidate(0, foo = $$props.foo); }; - $$self.$capture_state = () => { - return { foo, bar }; - }; + $$self.$capture_state = () => ({ foo, bar }); $$self.$inject_state = $$props => { if ("foo" in $$props) $$invalidate(0, foo = $$props.foo); if ("bar" in $$props) $$invalidate(1, bar = $$props.bar); }; + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + $$self.$$.update = () => { if ($$self.$$.dirty & /*foo*/ 1) { $: $$invalidate(1, bar = foo * 2); @@ -107,7 +113,7 @@ class Component extends SvelteComponentDev { }); const { ctx } = this.$$; - const props = options.props || ({}); + const props = options.props || {}; if (/*foo*/ ctx[0] === undefined && !("foo" in props)) { console.warn(" was created without expected prop 'foo'"); diff --git a/test/js/samples/dont-invalidate-this/expected.js b/test/js/samples/dont-invalidate-this/expected.js index 98f638dfcfe9..f5f6d078125d 100644 --- a/test/js/samples/dont-invalidate-this/expected.js +++ b/test/js/samples/dont-invalidate-this/expected.js @@ -17,10 +17,10 @@ function create_fragment(ctx) { return { c() { input = element("input"); - dispose = listen(input, "input", make_uppercase); }, m(target, anchor) { insert(target, input, anchor); + dispose = listen(input, "input", make_uppercase); }, p: noop, i: noop, diff --git a/test/js/samples/each-block-keyed-animated/expected.js b/test/js/samples/each-block-keyed-animated/expected.js index 3b697d68607e..7fb81c27a226 100644 --- a/test/js/samples/each-block-keyed-animated/expected.js +++ b/test/js/samples/each-block-keyed-animated/expected.js @@ -92,10 +92,12 @@ function create_fragment(ctx) { insert(target, each_1_anchor, anchor); }, p(ctx, [dirty]) { - const each_value = /*things*/ ctx[0]; - for (let i = 0; i < each_blocks.length; i += 1) each_blocks[i].r(); - each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx, each_value, each_1_lookup, each_1_anchor.parentNode, fix_and_destroy_block, create_each_block, each_1_anchor, get_each_context); - for (let i = 0; i < each_blocks.length; i += 1) each_blocks[i].a(); + if (dirty & /*things*/ 1) { + const each_value = /*things*/ ctx[0]; + for (let i = 0; i < each_blocks.length; i += 1) each_blocks[i].r(); + each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx, each_value, each_1_lookup, each_1_anchor.parentNode, fix_and_destroy_block, create_each_block, each_1_anchor, get_each_context); + for (let i = 0; i < each_blocks.length; i += 1) each_blocks[i].a(); + } }, i: noop, o: noop, diff --git a/test/js/samples/each-block-keyed/expected.js b/test/js/samples/each-block-keyed/expected.js index 1cd9a31ecee3..ad8c074e99f8 100644 --- a/test/js/samples/each-block-keyed/expected.js +++ b/test/js/samples/each-block-keyed/expected.js @@ -77,8 +77,10 @@ function create_fragment(ctx) { insert(target, each_1_anchor, anchor); }, p(ctx, [dirty]) { - const each_value = /*things*/ ctx[0]; - each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx, each_value, each_1_lookup, each_1_anchor.parentNode, destroy_block, create_each_block, each_1_anchor, get_each_context); + if (dirty & /*things*/ 1) { + const each_value = /*things*/ ctx[0]; + each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx, each_value, each_1_lookup, each_1_anchor.parentNode, destroy_block, create_each_block, each_1_anchor, get_each_context); + } }, i: noop, o: noop, diff --git a/test/js/samples/event-handler-dynamic/expected.js b/test/js/samples/event-handler-dynamic/expected.js index 34c33151bf2b..16b4a3f6262e 100644 --- a/test/js/samples/event-handler-dynamic/expected.js +++ b/test/js/samples/event-handler-dynamic/expected.js @@ -6,6 +6,7 @@ import { element, init, insert, + is_function, listen, noop, run_all, @@ -41,14 +42,6 @@ function create_fragment(ctx) { t5 = space(); button2 = element("button"); button2.textContent = "click"; - - dispose = [ - listen(button0, "click", /*updateHandler1*/ ctx[2]), - listen(button1, "click", /*updateHandler2*/ ctx[3]), - listen(button2, "click", function () { - /*clickHandler*/ ctx[0].apply(this, arguments); - }) - ]; }, m(target, anchor) { insert(target, p0, anchor); @@ -60,6 +53,14 @@ function create_fragment(ctx) { append(p1, t4); insert(target, t5, anchor); insert(target, button2, anchor); + + dispose = [ + listen(button0, "click", /*updateHandler1*/ ctx[2]), + listen(button1, "click", /*updateHandler2*/ ctx[3]), + listen(button2, "click", function () { + if (is_function(/*clickHandler*/ ctx[0])) /*clickHandler*/ ctx[0].apply(this, arguments); + }) + ]; }, p(new_ctx, [dirty]) { ctx = new_ctx; diff --git a/test/js/samples/event-handler-no-passive/expected.js b/test/js/samples/event-handler-no-passive/expected.js index 6f04e678083e..c519fac668f5 100644 --- a/test/js/samples/event-handler-no-passive/expected.js +++ b/test/js/samples/event-handler-no-passive/expected.js @@ -20,10 +20,10 @@ function create_fragment(ctx) { a = element("a"); a.textContent = "this should not navigate to example.com"; attr(a, "href", "https://example.com"); - dispose = listen(a, "touchstart", touchstart_handler); }, m(target, anchor) { insert(target, a, anchor); + dispose = listen(a, "touchstart", touchstart_handler); }, p: noop, i: noop, diff --git a/test/js/samples/event-modifiers/expected.js b/test/js/samples/event-modifiers/expected.js index 3f324bb76d3b..c12c3523a0a1 100644 --- a/test/js/samples/event-modifiers/expected.js +++ b/test/js/samples/event-modifiers/expected.js @@ -35,13 +35,6 @@ function create_fragment(ctx) { t3 = space(); button2 = element("button"); button2.textContent = "or me!"; - - dispose = [ - listen(button0, "click", stop_propagation(prevent_default(handleClick))), - listen(button1, "click", handleClick, { once: true, capture: true }), - listen(button2, "click", handleClick, true), - listen(div, "touchstart", handleTouchstart, { passive: true }) - ]; }, m(target, anchor) { insert(target, div, anchor); @@ -50,6 +43,13 @@ function create_fragment(ctx) { append(div, button1); append(div, t3); append(div, button2); + + dispose = [ + listen(button0, "click", stop_propagation(prevent_default(handleClick))), + listen(button1, "click", handleClick, { once: true, capture: true }), + listen(button2, "click", handleClick, true), + listen(div, "touchstart", handleTouchstart, { passive: true }) + ]; }, p: noop, i: noop, @@ -63,11 +63,11 @@ function create_fragment(ctx) { function handleTouchstart() { -} +} // ... function handleClick() { -} +} // ... class Component extends SvelteComponent { constructor(options) { diff --git a/test/js/samples/input-files/expected.js b/test/js/samples/input-files/expected.js index c3e46f0c798a..2a2254fbd754 100644 --- a/test/js/samples/input-files/expected.js +++ b/test/js/samples/input-files/expected.js @@ -20,10 +20,10 @@ function create_fragment(ctx) { input = element("input"); attr(input, "type", "file"); input.multiple = true; - dispose = listen(input, "change", /*input_change_handler*/ ctx[1]); }, m(target, anchor) { insert(target, input, anchor); + dispose = listen(input, "change", /*input_change_handler*/ ctx[1]); }, p: noop, i: noop, diff --git a/test/js/samples/input-no-initial-value/expected.js b/test/js/samples/input-no-initial-value/expected.js index 8ff2b2798b74..d588f0bf735a 100644 --- a/test/js/samples/input-no-initial-value/expected.js +++ b/test/js/samples/input-no-initial-value/expected.js @@ -31,11 +31,6 @@ function create_fragment(ctx) { button.textContent = "Store"; attr(input, "type", "text"); input.required = true; - - dispose = [ - listen(input, "input", /*input_input_handler*/ ctx[2]), - listen(form, "submit", /*handleSubmit*/ ctx[1]) - ]; }, m(target, anchor) { insert(target, form, anchor); @@ -43,6 +38,11 @@ function create_fragment(ctx) { set_input_value(input, /*test*/ ctx[0]); append(form, t0); append(form, button); + + dispose = [ + listen(input, "input", /*input_input_handler*/ ctx[2]), + listen(form, "submit", /*handleSubmit*/ ctx[1]) + ]; }, p(ctx, [dirty]) { if (dirty & /*test*/ 1 && input.value !== /*test*/ ctx[0]) { diff --git a/test/js/samples/input-range/expected.js b/test/js/samples/input-range/expected.js index 5a074d9754b3..12dfd3e90efe 100644 --- a/test/js/samples/input-range/expected.js +++ b/test/js/samples/input-range/expected.js @@ -22,16 +22,16 @@ function create_fragment(ctx) { c() { input = element("input"); attr(input, "type", "range"); + }, + m(target, anchor) { + insert(target, input, anchor); + set_input_value(input, /*value*/ ctx[0]); dispose = [ listen(input, "change", /*input_change_input_handler*/ ctx[1]), listen(input, "input", /*input_change_input_handler*/ ctx[1]) ]; }, - m(target, anchor) { - insert(target, input, anchor); - set_input_value(input, /*value*/ ctx[0]); - }, p(ctx, [dirty]) { if (dirty & /*value*/ 1) { set_input_value(input, /*value*/ ctx[0]); diff --git a/test/js/samples/input-value/expected.js b/test/js/samples/input-value/expected.js new file mode 100644 index 000000000000..21c7bfc83b9e --- /dev/null +++ b/test/js/samples/input-value/expected.js @@ -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]; + }, + m(target, anchor) { + insert(target, input, anchor); + insert(target, t0, anchor); + insert(target, h1, anchor); + append(h1, t1); + append(h1, t2); + dispose = listen(input, "input", /*onInput*/ ctx[1]); + }, + 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; \ No newline at end of file diff --git a/test/js/samples/input-value/input.svelte b/test/js/samples/input-value/input.svelte new file mode 100644 index 000000000000..476458a195c4 --- /dev/null +++ b/test/js/samples/input-value/input.svelte @@ -0,0 +1,11 @@ + + + + +

{name}!

\ No newline at end of file diff --git a/test/js/samples/input-without-blowback-guard/expected.js b/test/js/samples/input-without-blowback-guard/expected.js index 344976ade602..fefe867e146b 100644 --- a/test/js/samples/input-without-blowback-guard/expected.js +++ b/test/js/samples/input-without-blowback-guard/expected.js @@ -19,11 +19,11 @@ function create_fragment(ctx) { c() { input = element("input"); attr(input, "type", "checkbox"); - dispose = listen(input, "change", /*input_change_handler*/ ctx[1]); }, m(target, anchor) { insert(target, input, anchor); input.checked = /*foo*/ ctx[0]; + dispose = listen(input, "change", /*input_change_handler*/ ctx[1]); }, p(ctx, [dirty]) { if (dirty & /*foo*/ 1) { diff --git a/test/js/samples/instrumentation-script-if-no-block/expected.js b/test/js/samples/instrumentation-script-if-no-block/expected.js index 4127a6d7d693..7634481a2d6a 100644 --- a/test/js/samples/instrumentation-script-if-no-block/expected.js +++ b/test/js/samples/instrumentation-script-if-no-block/expected.js @@ -30,7 +30,6 @@ function create_fragment(ctx) { p = element("p"); t2 = text("x: "); t3 = text(/*x*/ ctx[0]); - dispose = listen(button, "click", /*foo*/ ctx[1]); }, m(target, anchor) { insert(target, button, anchor); @@ -38,6 +37,7 @@ function create_fragment(ctx) { insert(target, p, anchor); append(p, t2); append(p, t3); + dispose = listen(button, "click", /*foo*/ ctx[1]); }, p(ctx, [dirty]) { if (dirty & /*x*/ 1) set_data(t3, /*x*/ ctx[0]); diff --git a/test/js/samples/instrumentation-script-x-equals-x/expected.js b/test/js/samples/instrumentation-script-x-equals-x/expected.js index 0d4493baf3c0..c154608cd52c 100644 --- a/test/js/samples/instrumentation-script-x-equals-x/expected.js +++ b/test/js/samples/instrumentation-script-x-equals-x/expected.js @@ -31,7 +31,6 @@ function create_fragment(ctx) { p = element("p"); t2 = text("number of things: "); t3 = text(t3_value); - dispose = listen(button, "click", /*foo*/ ctx[1]); }, m(target, anchor) { insert(target, button, anchor); @@ -39,6 +38,7 @@ function create_fragment(ctx) { insert(target, p, anchor); append(p, t2); append(p, t3); + dispose = listen(button, "click", /*foo*/ ctx[1]); }, p(ctx, [dirty]) { if (dirty & /*things*/ 1 && t3_value !== (t3_value = /*things*/ ctx[0].length + "")) set_data(t3, t3_value); diff --git a/test/js/samples/instrumentation-template-if-no-block/expected.js b/test/js/samples/instrumentation-template-if-no-block/expected.js index 0bd627eb87b3..77780baa99d1 100644 --- a/test/js/samples/instrumentation-template-if-no-block/expected.js +++ b/test/js/samples/instrumentation-template-if-no-block/expected.js @@ -30,7 +30,6 @@ function create_fragment(ctx) { p = element("p"); t2 = text("x: "); t3 = text(/*x*/ ctx[0]); - dispose = listen(button, "click", /*click_handler*/ ctx[1]); }, m(target, anchor) { insert(target, button, anchor); @@ -38,6 +37,7 @@ function create_fragment(ctx) { insert(target, p, anchor); append(p, t2); append(p, t3); + dispose = listen(button, "click", /*click_handler*/ ctx[1]); }, p(ctx, [dirty]) { if (dirty & /*x*/ 1) set_data(t3, /*x*/ ctx[0]); diff --git a/test/js/samples/instrumentation-template-x-equals-x/expected.js b/test/js/samples/instrumentation-template-x-equals-x/expected.js index e049a6d39be8..4fe45616c75b 100644 --- a/test/js/samples/instrumentation-template-x-equals-x/expected.js +++ b/test/js/samples/instrumentation-template-x-equals-x/expected.js @@ -31,7 +31,6 @@ function create_fragment(ctx) { p = element("p"); t2 = text("number of things: "); t3 = text(t3_value); - dispose = listen(button, "click", /*click_handler*/ ctx[1]); }, m(target, anchor) { insert(target, button, anchor); @@ -39,6 +38,7 @@ function create_fragment(ctx) { insert(target, p, anchor); append(p, t2); append(p, t3); + dispose = listen(button, "click", /*click_handler*/ ctx[1]); }, p(ctx, [dirty]) { if (dirty & /*things*/ 1 && t3_value !== (t3_value = /*things*/ ctx[0].length + "")) set_data(t3, t3_value); diff --git a/test/js/samples/loop-protect/expected.js b/test/js/samples/loop-protect/expected.js index 554ccf23b15f..c52d9df437e5 100644 --- a/test/js/samples/loop-protect/expected.js +++ b/test/js/samples/loop-protect/expected.js @@ -6,13 +6,16 @@ import { detach_dev, dispatch_dev, element, + globals, init, insert_dev, loop_guard, noop, - safe_not_equal + safe_not_equal, + validate_slots } from "svelte/internal"; +const { console: console_1 } = globals; const file = undefined; function create_fragment(ctx) { @@ -102,20 +105,31 @@ function instance($$self, $$props, $$invalidate) { } while (true); } + const writable_props = []; + + Object.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console_1.warn(` was created with unknown prop '${key}'`); + }); + + let { $$slots = {}, $$scope } = $$props; + validate_slots("Component", $$slots, []); + function div_binding($$value) { binding_callbacks[$$value ? "unshift" : "push"](() => { $$invalidate(0, node = $$value); }); } - $$self.$capture_state = () => { - return {}; - }; + $$self.$capture_state = () => ({ node, foo }); $$self.$inject_state = $$props => { if ("node" in $$props) $$invalidate(0, node = $$props.node); }; + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + $: { const guard_4 = loop_guard(100); diff --git a/test/js/samples/media-bindings/expected.js b/test/js/samples/media-bindings/expected.js index bfb1b8911d39..52fef3679246 100644 --- a/test/js/samples/media-bindings/expected.js +++ b/test/js/samples/media-bindings/expected.js @@ -29,32 +29,18 @@ function create_fragment(ctx) { audio_updating = true; } - /*audio_timeupdate_handler*/ ctx[10].call(audio); + /*audio_timeupdate_handler*/ ctx[12].call(audio); } return { c() { audio = element("audio"); + if (/*buffered*/ ctx[0] === void 0) add_render_callback(() => /*audio_progress_handler*/ ctx[10].call(audio)); + if (/*buffered*/ ctx[0] === void 0 || /*seekable*/ ctx[1] === void 0) add_render_callback(() => /*audio_loadedmetadata_handler*/ ctx[11].call(audio)); if (/*played*/ ctx[2] === void 0 || /*currentTime*/ ctx[3] === void 0 || /*ended*/ ctx[9] === void 0) add_render_callback(audio_timeupdate_handler); - if (/*duration*/ ctx[4] === void 0) add_render_callback(() => /*audio_durationchange_handler*/ ctx[11].call(audio)); - if (/*buffered*/ ctx[0] === void 0) add_render_callback(() => /*audio_progress_handler*/ ctx[13].call(audio)); - if (/*buffered*/ ctx[0] === void 0 || /*seekable*/ ctx[1] === void 0) add_render_callback(() => /*audio_loadedmetadata_handler*/ ctx[14].call(audio)); + if (/*duration*/ ctx[4] === void 0) add_render_callback(() => /*audio_durationchange_handler*/ ctx[13].call(audio)); if (/*seeking*/ ctx[8] === void 0) add_render_callback(() => /*audio_seeking_seeked_handler*/ ctx[17].call(audio)); if (/*ended*/ ctx[9] === void 0) add_render_callback(() => /*audio_ended_handler*/ ctx[18].call(audio)); - - dispose = [ - listen(audio, "timeupdate", audio_timeupdate_handler), - listen(audio, "durationchange", /*audio_durationchange_handler*/ ctx[11]), - listen(audio, "play", /*audio_play_pause_handler*/ ctx[12]), - listen(audio, "pause", /*audio_play_pause_handler*/ ctx[12]), - listen(audio, "progress", /*audio_progress_handler*/ ctx[13]), - listen(audio, "loadedmetadata", /*audio_loadedmetadata_handler*/ ctx[14]), - listen(audio, "volumechange", /*audio_volumechange_handler*/ ctx[15]), - listen(audio, "ratechange", /*audio_ratechange_handler*/ ctx[16]), - listen(audio, "seeking", /*audio_seeking_seeked_handler*/ ctx[17]), - listen(audio, "seeked", /*audio_seeking_seeked_handler*/ ctx[17]), - listen(audio, "ended", /*audio_ended_handler*/ ctx[18]) - ]; }, m(target, anchor) { insert(target, audio, anchor); @@ -66,12 +52,28 @@ function create_fragment(ctx) { if (!isNaN(/*playbackRate*/ ctx[7])) { audio.playbackRate = /*playbackRate*/ ctx[7]; } + + dispose = [ + listen(audio, "progress", /*audio_progress_handler*/ ctx[10]), + listen(audio, "loadedmetadata", /*audio_loadedmetadata_handler*/ ctx[11]), + listen(audio, "timeupdate", audio_timeupdate_handler), + listen(audio, "durationchange", /*audio_durationchange_handler*/ ctx[13]), + listen(audio, "play", /*audio_play_pause_handler*/ ctx[14]), + listen(audio, "pause", /*audio_play_pause_handler*/ ctx[14]), + listen(audio, "volumechange", /*audio_volumechange_handler*/ ctx[15]), + listen(audio, "ratechange", /*audio_ratechange_handler*/ ctx[16]), + listen(audio, "seeking", /*audio_seeking_seeked_handler*/ ctx[17]), + listen(audio, "seeked", /*audio_seeking_seeked_handler*/ ctx[17]), + listen(audio, "ended", /*audio_ended_handler*/ ctx[18]) + ]; }, p(ctx, [dirty]) { if (!audio_updating && dirty & /*currentTime*/ 8 && !isNaN(/*currentTime*/ ctx[3])) { audio.currentTime = /*currentTime*/ ctx[3]; } + audio_updating = false; + if (dirty & /*paused*/ 32 && audio_is_paused !== (audio_is_paused = /*paused*/ ctx[5])) { audio[audio_is_paused ? "pause" : "play"](); } @@ -83,8 +85,6 @@ function create_fragment(ctx) { if (dirty & /*playbackRate*/ 128 && !isNaN(/*playbackRate*/ ctx[7])) { audio.playbackRate = /*playbackRate*/ ctx[7]; } - - audio_updating = false; }, i: noop, o: noop, @@ -107,6 +107,18 @@ function instance($$self, $$props, $$invalidate) { let { seeking } = $$props; let { ended } = $$props; + function audio_progress_handler() { + buffered = time_ranges_to_array(this.buffered); + $$invalidate(0, buffered); + } + + function audio_loadedmetadata_handler() { + buffered = time_ranges_to_array(this.buffered); + seekable = time_ranges_to_array(this.seekable); + $$invalidate(0, buffered); + $$invalidate(1, seekable); + } + function audio_timeupdate_handler() { played = time_ranges_to_array(this.played); currentTime = this.currentTime; @@ -126,18 +138,6 @@ function instance($$self, $$props, $$invalidate) { $$invalidate(5, paused); } - function audio_progress_handler() { - buffered = time_ranges_to_array(this.buffered); - $$invalidate(0, buffered); - } - - function audio_loadedmetadata_handler() { - buffered = time_ranges_to_array(this.buffered); - seekable = time_ranges_to_array(this.seekable); - $$invalidate(0, buffered); - $$invalidate(1, seekable); - } - function audio_volumechange_handler() { volume = this.volume; $$invalidate(6, volume); @@ -182,11 +182,11 @@ function instance($$self, $$props, $$invalidate) { playbackRate, seeking, ended, + audio_progress_handler, + audio_loadedmetadata_handler, audio_timeupdate_handler, audio_durationchange_handler, audio_play_pause_handler, - audio_progress_handler, - audio_loadedmetadata_handler, audio_volumechange_handler, audio_ratechange_handler, audio_seeking_seeked_handler, diff --git a/test/js/samples/ssr-no-oncreate-etc/expected.js b/test/js/samples/ssr-no-oncreate-etc/expected.js index 276587eeca14..803f06a8829d 100644 --- a/test/js/samples/ssr-no-oncreate-etc/expected.js +++ b/test/js/samples/ssr-no-oncreate-etc/expected.js @@ -13,7 +13,7 @@ function foo() { function swipe(node, callback) { -} +} // TODO implement const Component = create_ssr_component(($$result, $$props, $$bindings, $$slots) => { onMount(() => { diff --git a/test/js/samples/video-bindings/expected.js b/test/js/samples/video-bindings/expected.js index e3d48f9922cd..c8cd1d84ce0d 100644 --- a/test/js/samples/video-bindings/expected.js +++ b/test/js/samples/video-bindings/expected.js @@ -17,8 +17,8 @@ import { function create_fragment(ctx) { let video; let video_updating = false; - let video_resize_listener; let video_animationframe; + let video_resize_listener; let dispose; function video_timeupdate_handler() { @@ -29,24 +29,24 @@ function create_fragment(ctx) { video_updating = true; } - /*video_timeupdate_handler*/ ctx[5].call(video); + /*video_timeupdate_handler*/ ctx[4].call(video); } return { c() { video = element("video"); - add_render_callback(() => /*video_elementresize_handler*/ ctx[4].call(video)); - if (/*videoHeight*/ ctx[1] === void 0 || /*videoWidth*/ ctx[2] === void 0) add_render_callback(() => /*video_resize_handler*/ ctx[6].call(video)); + if (/*videoHeight*/ ctx[1] === void 0 || /*videoWidth*/ ctx[2] === void 0) add_render_callback(() => /*video_resize_handler*/ ctx[5].call(video)); + add_render_callback(() => /*video_elementresize_handler*/ ctx[6].call(video)); + }, + m(target, anchor) { + insert(target, video, anchor); + video_resize_listener = add_resize_listener(video, /*video_elementresize_handler*/ ctx[6].bind(video)); dispose = [ listen(video, "timeupdate", video_timeupdate_handler), - listen(video, "resize", /*video_resize_handler*/ ctx[6]) + listen(video, "resize", /*video_resize_handler*/ ctx[5]) ]; }, - m(target, anchor) { - insert(target, video, anchor); - video_resize_listener = add_resize_listener(video, /*video_elementresize_handler*/ ctx[4].bind(video)); - }, p(ctx, [dirty]) { if (!video_updating && dirty & /*currentTime*/ 1 && !isNaN(/*currentTime*/ ctx[0])) { video.currentTime = /*currentTime*/ ctx[0]; @@ -70,11 +70,6 @@ function instance($$self, $$props, $$invalidate) { let { videoWidth } = $$props; let { offsetWidth } = $$props; - function video_elementresize_handler() { - offsetWidth = this.offsetWidth; - $$invalidate(3, offsetWidth); - } - function video_timeupdate_handler() { currentTime = this.currentTime; $$invalidate(0, currentTime); @@ -87,6 +82,11 @@ function instance($$self, $$props, $$invalidate) { $$invalidate(2, videoWidth); } + function video_elementresize_handler() { + offsetWidth = this.offsetWidth; + $$invalidate(3, offsetWidth); + } + $$self.$set = $$props => { if ("currentTime" in $$props) $$invalidate(0, currentTime = $$props.currentTime); if ("videoHeight" in $$props) $$invalidate(1, videoHeight = $$props.videoHeight); @@ -99,9 +99,9 @@ function instance($$self, $$props, $$invalidate) { videoHeight, videoWidth, offsetWidth, - video_elementresize_handler, video_timeupdate_handler, - video_resize_handler + video_resize_handler, + video_elementresize_handler ]; } diff --git a/test/js/samples/window-binding-online/expected.js b/test/js/samples/window-binding-online/expected.js index 8285646481a2..e129e66d7163 100644 --- a/test/js/samples/window-binding-online/expected.js +++ b/test/js/samples/window-binding-online/expected.js @@ -14,13 +14,13 @@ function create_fragment(ctx) { add_render_callback(/*onlinestatuschanged*/ ctx[1]); return { - c() { + c: noop, + m(target, anchor) { dispose = [ listen(window, "online", /*onlinestatuschanged*/ ctx[1]), listen(window, "offline", /*onlinestatuschanged*/ ctx[1]) ]; }, - m: noop, p: noop, i: noop, o: noop, diff --git a/test/js/samples/window-binding-scroll/expected.js b/test/js/samples/window-binding-scroll/expected.js index f79212e25e66..70c39eedd20c 100644 --- a/test/js/samples/window-binding-scroll/expected.js +++ b/test/js/samples/window-binding-scroll/expected.js @@ -33,6 +33,11 @@ function create_fragment(ctx) { p = element("p"); t0 = text("scrolled to "); t1 = text(/*y*/ ctx[0]); + }, + m(target, anchor) { + insert(target, p, anchor); + append(p, t0); + append(p, t1); dispose = listen(window, "scroll", () => { scrolling = true; @@ -41,11 +46,6 @@ function create_fragment(ctx) { /*onwindowscroll*/ ctx[1](); }); }, - m(target, anchor) { - insert(target, p, anchor); - append(p, t0); - append(p, t1); - }, p(ctx, [dirty]) { if (dirty & /*y*/ 1 && !scrolling) { scrolling = true; diff --git a/test/parser/samples/action-with-identifier/output.json b/test/parser/samples/action-with-identifier/output.json index 435aee4444a0..9ae0011c524a 100644 --- a/test/parser/samples/action-with-identifier/output.json +++ b/test/parser/samples/action-with-identifier/output.json @@ -20,6 +20,16 @@ "type": "Identifier", "start": 20, "end": 27, + "loc": { + "start": { + "line": 1, + "column": 20 + }, + "end": { + "line": 1, + "column": 27 + } + }, "name": "message" } } diff --git a/test/parser/samples/attribute-dynamic-boolean/output.json b/test/parser/samples/attribute-dynamic-boolean/output.json index 478144152a10..ab6b3927ce41 100644 --- a/test/parser/samples/attribute-dynamic-boolean/output.json +++ b/test/parser/samples/attribute-dynamic-boolean/output.json @@ -24,6 +24,16 @@ "type": "Identifier", "start": 20, "end": 28, + "loc": { + "start": { + "line": 1, + "column": 20 + }, + "end": { + "line": 1, + "column": 28 + } + }, "name": "readonly" } } diff --git a/test/parser/samples/attribute-dynamic-reserved/input.svelte b/test/parser/samples/attribute-dynamic-reserved/input.svelte deleted file mode 100644 index d973a9dea043..000000000000 --- a/test/parser/samples/attribute-dynamic-reserved/input.svelte +++ /dev/null @@ -1 +0,0 @@ -
\ No newline at end of file diff --git a/test/parser/samples/attribute-dynamic-reserved/output.json b/test/parser/samples/attribute-dynamic-reserved/output.json deleted file mode 100644 index 22be3c908776..000000000000 --- a/test/parser/samples/attribute-dynamic-reserved/output.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "html": { - "start": 0, - "end": 25, - "type": "Fragment", - "children": [ - { - "start": 0, - "end": 25, - "type": "Element", - "name": "div", - "attributes": [ - { - "start": 5, - "end": 18, - "type": "Attribute", - "name": "class", - "value": [ - { - "start": 11, - "end": 18, - "type": "MustacheTag", - "expression": { - "type": "Identifier", - "start": 12, - "end": 17, - "name": "class" - } - } - ] - } - ], - "children": [] - } - ] - } -} \ No newline at end of file diff --git a/test/parser/samples/attribute-dynamic/output.json b/test/parser/samples/attribute-dynamic/output.json index a48f37687672..28b9da1deaa1 100644 --- a/test/parser/samples/attribute-dynamic/output.json +++ b/test/parser/samples/attribute-dynamic/output.json @@ -31,6 +31,16 @@ "type": "Identifier", "start": 20, "end": 25, + "loc": { + "start": { + "line": 1, + "column": 20 + }, + "end": { + "line": 1, + "column": 25 + } + }, "name": "color" } }, @@ -53,6 +63,16 @@ "type": "Identifier", "start": 30, "end": 35, + "loc": { + "start": { + "line": 1, + "column": 30 + }, + "end": { + "line": 1, + "column": 35 + } + }, "name": "color" } } diff --git a/test/parser/samples/attribute-unique-binding-error/error.json b/test/parser/samples/attribute-unique-binding-error/error.json new file mode 100644 index 000000000000..dd145721499e --- /dev/null +++ b/test/parser/samples/attribute-unique-binding-error/error.json @@ -0,0 +1,10 @@ +{ + "code": "duplicate-attribute", + "message": "Attributes need to be unique", + "start": { + "line": 1, + "column": 17, + "character": 17 + }, + "pos": 17 +} diff --git a/test/parser/samples/attribute-unique-binding-error/input.svelte b/test/parser/samples/attribute-unique-binding-error/input.svelte new file mode 100644 index 000000000000..78f854bad629 --- /dev/null +++ b/test/parser/samples/attribute-unique-binding-error/input.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/parser/samples/attribute-unique-shorthand-error/error.json b/test/parser/samples/attribute-unique-shorthand-error/error.json new file mode 100644 index 000000000000..dd145721499e --- /dev/null +++ b/test/parser/samples/attribute-unique-shorthand-error/error.json @@ -0,0 +1,10 @@ +{ + "code": "duplicate-attribute", + "message": "Attributes need to be unique", + "start": { + "line": 1, + "column": 17, + "character": 17 + }, + "pos": 17 +} diff --git a/test/parser/samples/attribute-unique-shorthand-error/input.svelte b/test/parser/samples/attribute-unique-shorthand-error/input.svelte new file mode 100644 index 000000000000..d486eab55852 --- /dev/null +++ b/test/parser/samples/attribute-unique-shorthand-error/input.svelte @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/test/parser/samples/attribute-with-whitespace/output.json b/test/parser/samples/attribute-with-whitespace/output.json index 11d5aa5e069a..edf05ca32e0f 100644 --- a/test/parser/samples/attribute-with-whitespace/output.json +++ b/test/parser/samples/attribute-with-whitespace/output.json @@ -20,6 +20,16 @@ "type": "Identifier", "start": 19, "end": 22, + "loc": { + "start": { + "line": 1, + "column": 19 + }, + "end": { + "line": 1, + "column": 22 + } + }, "name": "foo" } } diff --git a/test/parser/samples/binding/output.json b/test/parser/samples/binding/output.json index 558215f41aa5..c980b7f3ebc1 100644 --- a/test/parser/samples/binding/output.json +++ b/test/parser/samples/binding/output.json @@ -27,6 +27,16 @@ "type": "Identifier", "start": 50, "end": 54, + "loc": { + "start": { + "line": 5, + "column": 19 + }, + "end": { + "line": 5, + "column": 23 + } + }, "name": "name" } } diff --git a/test/parser/samples/each-block-destructured/output.json b/test/parser/samples/each-block-destructured/output.json index bafde1324db4..425c609a2ccd 100644 --- a/test/parser/samples/each-block-destructured/output.json +++ b/test/parser/samples/each-block-destructured/output.json @@ -40,6 +40,16 @@ "type": "Identifier", "start": 46, "end": 49, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 8 + } + }, "name": "key" } }, @@ -58,6 +68,16 @@ "type": "Identifier", "start": 53, "end": 58, + "loc": { + "start": { + "line": 2, + "column": 12 + }, + "end": { + "line": 2, + "column": 17 + } + }, "name": "value" } } diff --git a/test/parser/samples/each-block-else/output.json b/test/parser/samples/each-block-else/output.json index 19b5af19b4fa..2720ce52929d 100644 --- a/test/parser/samples/each-block-else/output.json +++ b/test/parser/samples/each-block-else/output.json @@ -40,6 +40,16 @@ "type": "Identifier", "start": 31, "end": 37, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 11 + } + }, "name": "animal" } } diff --git a/test/parser/samples/each-block-indexed/output.json b/test/parser/samples/each-block-indexed/output.json index 68a12ea31c16..50f2000a36c5 100644 --- a/test/parser/samples/each-block-indexed/output.json +++ b/test/parser/samples/each-block-indexed/output.json @@ -40,6 +40,16 @@ "type": "Identifier", "start": 34, "end": 35, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 6 + } + }, "name": "i" } }, @@ -58,6 +68,16 @@ "type": "Identifier", "start": 39, "end": 45, + "loc": { + "start": { + "line": 2, + "column": 10 + }, + "end": { + "line": 2, + "column": 16 + } + }, "name": "animal" } } diff --git a/test/parser/samples/each-block-keyed/output.json b/test/parser/samples/each-block-keyed/output.json index 61b5442c0d93..7dc86814538a 100644 --- a/test/parser/samples/each-block-keyed/output.json +++ b/test/parser/samples/each-block-keyed/output.json @@ -40,6 +40,16 @@ "type": "Identifier", "start": 37, "end": 41, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 9 + } + }, "name": "todo" } } diff --git a/test/parser/samples/each-block/output.json b/test/parser/samples/each-block/output.json index 38bc7e1d042f..6594fb50a6ec 100644 --- a/test/parser/samples/each-block/output.json +++ b/test/parser/samples/each-block/output.json @@ -40,6 +40,16 @@ "type": "Identifier", "start": 31, "end": 37, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 11 + } + }, "name": "animal" } } diff --git a/test/parser/samples/element-with-mustache/output.json b/test/parser/samples/element-with-mustache/output.json index f7c2e9936bad..049e373100f9 100644 --- a/test/parser/samples/element-with-mustache/output.json +++ b/test/parser/samples/element-with-mustache/output.json @@ -26,6 +26,16 @@ "type": "Identifier", "start": 11, "end": 15, + "loc": { + "start": { + "line": 1, + "column": 11 + }, + "end": { + "line": 1, + "column": 15 + } + }, "name": "name" } }, diff --git a/test/parser/samples/error-catch-before-closing/error.json b/test/parser/samples/error-catch-before-closing/error.json new file mode 100644 index 000000000000..30fbf5fbd523 --- /dev/null +++ b/test/parser/samples/error-catch-before-closing/error.json @@ -0,0 +1,6 @@ +{ + "code": "invalid-catch-placement", + "message": "Expected to close {#each} block before seeing {:catch} block", + "start": { "line": 3, "column": 7, "character": 41 }, + "pos": 41 +} diff --git a/test/parser/samples/error-catch-before-closing/input.svelte b/test/parser/samples/error-catch-before-closing/input.svelte new file mode 100644 index 000000000000..bd771701e2b6 --- /dev/null +++ b/test/parser/samples/error-catch-before-closing/input.svelte @@ -0,0 +1,4 @@ +{#await true} + {#each foo as bar} +{:catch f} +{/await} \ No newline at end of file diff --git a/test/parser/samples/error-else-before-closing-2/error.json b/test/parser/samples/error-else-before-closing-2/error.json new file mode 100644 index 000000000000..d35be1abf5e7 --- /dev/null +++ b/test/parser/samples/error-else-before-closing-2/error.json @@ -0,0 +1,6 @@ +{ + "code": "invalid-else-placement", + "message": "Expected to close {#await} block before seeing {:else} block", + "start": { "line": 3, "column": 6, "character": 29 }, + "pos": 29 +} diff --git a/test/parser/samples/error-else-before-closing-2/input.svelte b/test/parser/samples/error-else-before-closing-2/input.svelte new file mode 100644 index 000000000000..f865a9a53306 --- /dev/null +++ b/test/parser/samples/error-else-before-closing-2/input.svelte @@ -0,0 +1,4 @@ +{#if true} + {#await p} +{:else} +{/if} \ No newline at end of file diff --git a/test/parser/samples/error-else-before-closing-3/error.json b/test/parser/samples/error-else-before-closing-3/error.json new file mode 100644 index 000000000000..e5ec210c759d --- /dev/null +++ b/test/parser/samples/error-else-before-closing-3/error.json @@ -0,0 +1,6 @@ +{ + "code": "invalid-else-placement", + "message": "Cannot have an {:else} block outside an {#if ...} or {#each ...} block", + "start": { "line": 2, "column": 6, "character": 11 }, + "pos": 11 +} diff --git a/test/parser/samples/error-else-before-closing-3/input.svelte b/test/parser/samples/error-else-before-closing-3/input.svelte new file mode 100644 index 000000000000..fb434f26a3c1 --- /dev/null +++ b/test/parser/samples/error-else-before-closing-3/input.svelte @@ -0,0 +1,2 @@ +
  • +{:else} \ No newline at end of file diff --git a/test/parser/samples/error-else-before-closing/error.json b/test/parser/samples/error-else-before-closing/error.json new file mode 100644 index 000000000000..5b6e490c0f9a --- /dev/null +++ b/test/parser/samples/error-else-before-closing/error.json @@ -0,0 +1,6 @@ +{ + "code": "invalid-else-placement", + "message": "Expected to close
  • tag before seeing {:else} block", + "start": { "line": 3, "column": 6, "character": 23 }, + "pos": 23 +} diff --git a/test/parser/samples/error-else-before-closing/input.svelte b/test/parser/samples/error-else-before-closing/input.svelte new file mode 100644 index 000000000000..a22863192da2 --- /dev/null +++ b/test/parser/samples/error-else-before-closing/input.svelte @@ -0,0 +1,4 @@ +{#if true} +
  • +{:else} +{/if} \ No newline at end of file diff --git a/test/parser/samples/error-else-if-before-closing-2/error.json b/test/parser/samples/error-else-if-before-closing-2/error.json new file mode 100644 index 000000000000..e55f4f11e567 --- /dev/null +++ b/test/parser/samples/error-else-if-before-closing-2/error.json @@ -0,0 +1,6 @@ +{ + "code": "invalid-elseif-placement", + "message": "Expected to close

    tag before seeing {:else if ...} block", + "start": { "line": 3, "column": 9, "character": 25 }, + "pos": 25 +} diff --git a/test/parser/samples/error-else-if-before-closing-2/input.svelte b/test/parser/samples/error-else-if-before-closing-2/input.svelte new file mode 100644 index 000000000000..5ae36df4eb08 --- /dev/null +++ b/test/parser/samples/error-else-if-before-closing-2/input.svelte @@ -0,0 +1,4 @@ +{#if true} +

    +{:else if false} +{/if} \ No newline at end of file diff --git a/test/parser/samples/error-else-if-before-closing/error.json b/test/parser/samples/error-else-if-before-closing/error.json new file mode 100644 index 000000000000..21d16c72a4d6 --- /dev/null +++ b/test/parser/samples/error-else-if-before-closing/error.json @@ -0,0 +1,6 @@ +{ + "code": "invalid-elseif-placement", + "message": "Expected to close {#await} block before seeing {:else if ...} block", + "start": { "line": 3, "column": 9, "character": 34 }, + "pos": 34 +} diff --git a/test/parser/samples/error-else-if-before-closing/input.svelte b/test/parser/samples/error-else-if-before-closing/input.svelte new file mode 100644 index 000000000000..486a921a9a49 --- /dev/null +++ b/test/parser/samples/error-else-if-before-closing/input.svelte @@ -0,0 +1,4 @@ +{#if true} + {#await foo} +{:else if false} +{/if} \ No newline at end of file diff --git a/test/parser/samples/error-else-if-without-if/error.json b/test/parser/samples/error-else-if-without-if/error.json new file mode 100644 index 000000000000..dd69df677236 --- /dev/null +++ b/test/parser/samples/error-else-if-without-if/error.json @@ -0,0 +1,6 @@ +{ + "code": "invalid-elseif-placement", + "message": "Cannot have an {:else if ...} block outside an {#if ...} block", + "start": { "line": 3, "column": 10, "character": 35 }, + "pos": 35 +} diff --git a/test/parser/samples/error-else-if-without-if/input.svelte b/test/parser/samples/error-else-if-without-if/input.svelte new file mode 100644 index 000000000000..06baf335111b --- /dev/null +++ b/test/parser/samples/error-else-if-without-if/input.svelte @@ -0,0 +1,4 @@ +{#await foo} +{:then bar} + {:else if} +{/await} \ No newline at end of file diff --git a/test/parser/samples/error-then-before-closing/error.json b/test/parser/samples/error-then-before-closing/error.json new file mode 100644 index 000000000000..07310c93fae9 --- /dev/null +++ b/test/parser/samples/error-then-before-closing/error.json @@ -0,0 +1,6 @@ +{ + "code": "invalid-then-placement", + "message": "Expected to close

  • tag before seeing {:then} block", + "start": { "line": 3, "column": 6, "character": 26 }, + "pos": 26 +} diff --git a/test/parser/samples/error-then-before-closing/input.svelte b/test/parser/samples/error-then-before-closing/input.svelte new file mode 100644 index 000000000000..bb0b993bdfe7 --- /dev/null +++ b/test/parser/samples/error-then-before-closing/input.svelte @@ -0,0 +1,4 @@ +{#await true} +
  • +{:then f} +{/await} \ No newline at end of file diff --git a/test/parser/samples/event-handler/output.json b/test/parser/samples/event-handler/output.json index 44bb83de7dfa..95db9998f470 100644 --- a/test/parser/samples/event-handler/output.json +++ b/test/parser/samples/event-handler/output.json @@ -128,6 +128,16 @@ "type": "Identifier", "start": 68, "end": 75, + "loc": { + "start": { + "line": 3, + "column": 5 + }, + "end": { + "line": 3, + "column": 12 + } + }, "name": "visible" }, "children": [ diff --git a/test/parser/samples/if-block-else/output.json b/test/parser/samples/if-block-else/output.json index 8b22cfa26b3a..1f2cff3ff9e6 100644 --- a/test/parser/samples/if-block-else/output.json +++ b/test/parser/samples/if-block-else/output.json @@ -12,6 +12,16 @@ "type": "Identifier", "start": 5, "end": 8, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 8 + } + }, "name": "foo" }, "children": [ diff --git a/test/parser/samples/if-block/output.json b/test/parser/samples/if-block/output.json index 1714bb7141c3..ef895a366abf 100644 --- a/test/parser/samples/if-block/output.json +++ b/test/parser/samples/if-block/output.json @@ -12,6 +12,16 @@ "type": "Identifier", "start": 5, "end": 8, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 8 + } + }, "name": "foo" }, "children": [ diff --git a/test/parser/samples/implicitly-closed-li-block/output.json b/test/parser/samples/implicitly-closed-li-block/output.json index 4a75a34223db..767f64053cd1 100644 --- a/test/parser/samples/implicitly-closed-li-block/output.json +++ b/test/parser/samples/implicitly-closed-li-block/output.json @@ -40,6 +40,16 @@ "type": "Literal", "start": 18, "end": 22, + "loc": { + "start": { + "line": 3, + "column": 6 + }, + "end": { + "line": 3, + "column": 10 + } + }, "value": true, "raw": "true" }, diff --git a/test/parser/samples/no-error-if-before-closing/input.svelte b/test/parser/samples/no-error-if-before-closing/input.svelte new file mode 100644 index 000000000000..4059e0d4d108 --- /dev/null +++ b/test/parser/samples/no-error-if-before-closing/input.svelte @@ -0,0 +1,19 @@ +{#if true} + +{:else} +{/if} + +{#if true} +
    +{:else} +{/if} + +{#await true} + +{:then f} +{/await} + +{#await true} +
    +{:then f} +{/await} \ No newline at end of file diff --git a/test/parser/samples/no-error-if-before-closing/output.json b/test/parser/samples/no-error-if-before-closing/output.json new file mode 100644 index 000000000000..251cefc0ca81 --- /dev/null +++ b/test/parser/samples/no-error-if-before-closing/output.json @@ -0,0 +1,258 @@ +{ + "html": { + "start": 0, + "end": 148, + "type": "Fragment", + "children": [ + { + "start": 0, + "end": 33, + "type": "IfBlock", + "expression": { + "type": "Literal", + "start": 5, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "value": true, + "raw": "true" + }, + "children": [ + { + "start": 12, + "end": 19, + "type": "Element", + "name": "input", + "attributes": [], + "children": [] + } + ], + "else": { + "start": 27, + "end": 28, + "type": "ElseBlock", + "children": [] + } + }, + { + "start": 33, + "end": 35, + "type": "Text", + "raw": "\n\n", + "data": "\n\n" + }, + { + "start": 35, + "end": 65, + "type": "IfBlock", + "expression": { + "type": "Literal", + "start": 40, + "end": 44, + "loc": { + "start": { + "line": 6, + "column": 5 + }, + "end": { + "line": 6, + "column": 9 + } + }, + "value": true, + "raw": "true" + }, + "children": [ + { + "start": 47, + "end": 51, + "type": "Element", + "name": "br", + "attributes": [], + "children": [] + } + ], + "else": { + "start": 59, + "end": 60, + "type": "ElseBlock", + "children": [] + } + }, + { + "start": 65, + "end": 67, + "type": "Text", + "raw": "\n\n", + "data": "\n\n" + }, + { + "start": 67, + "end": 108, + "type": "AwaitBlock", + "expression": { + "type": "Literal", + "start": 75, + "end": 79, + "loc": { + "start": { + "line": 11, + "column": 8 + }, + "end": { + "line": 11, + "column": 12 + } + }, + "value": true, + "raw": "true" + }, + "value": "f", + "error": null, + "pending": { + "start": 80, + "end": 90, + "type": "PendingBlock", + "children": [ + { + "start": 80, + "end": 82, + "type": "Text", + "raw": "\n\t", + "data": "\n\t" + }, + { + "start": 82, + "end": 89, + "type": "Element", + "name": "input", + "attributes": [], + "children": [] + }, + { + "start": 89, + "end": 90, + "type": "Text", + "raw": "\n", + "data": "\n" + } + ], + "skip": false + }, + "then": { + "start": 90, + "end": 100, + "type": "ThenBlock", + "children": [ + { + "start": 99, + "end": 100, + "type": "Text", + "raw": "\n", + "data": "\n" + } + ], + "skip": false + }, + "catch": { + "start": null, + "end": null, + "type": "CatchBlock", + "children": [], + "skip": true + } + }, + { + "start": 108, + "end": 110, + "type": "Text", + "raw": "\n\n", + "data": "\n\n" + }, + { + "start": 110, + "end": 148, + "type": "AwaitBlock", + "expression": { + "type": "Literal", + "start": 118, + "end": 122, + "loc": { + "start": { + "line": 16, + "column": 8 + }, + "end": { + "line": 16, + "column": 12 + } + }, + "value": true, + "raw": "true" + }, + "value": "f", + "error": null, + "pending": { + "start": 123, + "end": 130, + "type": "PendingBlock", + "children": [ + { + "start": 123, + "end": 125, + "type": "Text", + "raw": "\n\t", + "data": "\n\t" + }, + { + "start": 125, + "end": 129, + "type": "Element", + "name": "br", + "attributes": [], + "children": [] + }, + { + "start": 129, + "end": 130, + "type": "Text", + "raw": "\n", + "data": "\n" + } + ], + "skip": false + }, + "then": { + "start": 130, + "end": 140, + "type": "ThenBlock", + "children": [ + { + "start": 139, + "end": 140, + "type": "Text", + "raw": "\n", + "data": "\n" + } + ], + "skip": false + }, + "catch": { + "start": null, + "end": null, + "type": "CatchBlock", + "children": [], + "skip": true + } + } + ] + } +} \ No newline at end of file diff --git a/test/parser/samples/refs/output.json b/test/parser/samples/refs/output.json index 72a3d7689c4a..fb94ffd70156 100644 --- a/test/parser/samples/refs/output.json +++ b/test/parser/samples/refs/output.json @@ -27,6 +27,16 @@ "type": "Identifier", "start": 49, "end": 52, + "loc": { + "start": { + "line": 5, + "column": 19 + }, + "end": { + "line": 5, + "column": 22 + } + }, "name": "foo" } } diff --git a/test/parser/samples/script-comment-only/output.json b/test/parser/samples/script-comment-only/output.json index 3441d8a7bb12..e090b30ae6a6 100644 --- a/test/parser/samples/script-comment-only/output.json +++ b/test/parser/samples/script-comment-only/output.json @@ -41,7 +41,15 @@ } }, "body": [], - "sourceType": "module" + "sourceType": "module", + "trailingComments": [ + { + "type": "Line", + "value": " TODO write some code", + "start": 10, + "end": 33 + } + ] } } } \ No newline at end of file diff --git a/test/parser/samples/script-comment-trailing-multiline/output.json b/test/parser/samples/script-comment-trailing-multiline/output.json index 3c02b1fbde2d..184a29978d7d 100644 --- a/test/parser/samples/script-comment-trailing-multiline/output.json +++ b/test/parser/samples/script-comment-trailing-multiline/output.json @@ -33,6 +33,16 @@ "type": "Identifier", "start": 90, "end": 94, + "loc": { + "start": { + "line": 9, + "column": 11 + }, + "end": { + "line": 9, + "column": 15 + } + }, "name": "name" } }, @@ -134,7 +144,15 @@ "kind": "let" } ], - "sourceType": "module" + "sourceType": "module", + "trailingComments": [ + { + "type": "Block", + "value": "\n\ttrailing multiline comment\n", + "start": 32, + "end": 67 + } + ] } } } \ No newline at end of file diff --git a/test/parser/samples/script-comment-trailing/output.json b/test/parser/samples/script-comment-trailing/output.json index beca0010426a..2aca23f667a8 100644 --- a/test/parser/samples/script-comment-trailing/output.json +++ b/test/parser/samples/script-comment-trailing/output.json @@ -33,6 +33,16 @@ "type": "Identifier", "start": 79, "end": 83, + "loc": { + "start": { + "line": 7, + "column": 11 + }, + "end": { + "line": 7, + "column": 15 + } + }, "name": "name" } }, @@ -134,7 +144,15 @@ "kind": "let" } ], - "sourceType": "module" + "sourceType": "module", + "trailingComments": [ + { + "type": "Line", + "value": " trailing line comment", + "start": 32, + "end": 56 + } + ] } } } \ No newline at end of file diff --git a/test/parser/samples/script/output.json b/test/parser/samples/script/output.json index 00b7073a1940..4d0aa9cf3613 100644 --- a/test/parser/samples/script/output.json +++ b/test/parser/samples/script/output.json @@ -33,6 +33,16 @@ "type": "Identifier", "start": 52, "end": 56, + "loc": { + "start": { + "line": 5, + "column": 11 + }, + "end": { + "line": 5, + "column": 15 + } + }, "name": "name" } }, diff --git a/test/parser/samples/space-between-mustaches/output.json b/test/parser/samples/space-between-mustaches/output.json index 9a367bd2c1f3..b89f4d6c8327 100644 --- a/test/parser/samples/space-between-mustaches/output.json +++ b/test/parser/samples/space-between-mustaches/output.json @@ -26,6 +26,16 @@ "type": "Identifier", "start": 5, "end": 6, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 6 + } + }, "name": "a" } }, @@ -44,6 +54,16 @@ "type": "Identifier", "start": 9, "end": 10, + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 1, + "column": 10 + } + }, "name": "b" } }, @@ -62,6 +82,16 @@ "type": "Identifier", "start": 15, "end": 16, + "loc": { + "start": { + "line": 1, + "column": 15 + }, + "end": { + "line": 1, + "column": 16 + } + }, "name": "c" } }, diff --git a/test/parser/samples/spread/output.json b/test/parser/samples/spread/output.json index 73a0dc97778b..3a5c471905d3 100644 --- a/test/parser/samples/spread/output.json +++ b/test/parser/samples/spread/output.json @@ -18,6 +18,16 @@ "type": "Identifier", "start": 9, "end": 14, + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 1, + "column": 14 + } + }, "name": "props" } } diff --git a/test/parser/samples/textarea-children/output.json b/test/parser/samples/textarea-children/output.json index 90f31f3caff9..919fa33fde1e 100644 --- a/test/parser/samples/textarea-children/output.json +++ b/test/parser/samples/textarea-children/output.json @@ -29,6 +29,16 @@ "type": "Identifier", "start": 41, "end": 44, + "loc": { + "start": { + "line": 2, + "column": 30 + }, + "end": { + "line": 2, + "column": 33 + } + }, "name": "foo" } }, diff --git a/test/parser/samples/whitespace-normal/output.json b/test/parser/samples/whitespace-normal/output.json index acbae7ae17b6..61eca1329f0e 100644 --- a/test/parser/samples/whitespace-normal/output.json +++ b/test/parser/samples/whitespace-normal/output.json @@ -33,6 +33,16 @@ "type": "Identifier", "start": 19, "end": 23, + "loc": { + "start": { + "line": 1, + "column": 19 + }, + "end": { + "line": 1, + "column": 23 + } + }, "name": "name" } }, diff --git a/test/parser/samples/yield/input.svelte b/test/parser/samples/yield/input.svelte deleted file mode 100644 index f5e8aad05330..000000000000 --- a/test/parser/samples/yield/input.svelte +++ /dev/null @@ -1 +0,0 @@ -{yield} \ No newline at end of file diff --git a/test/parser/samples/yield/output.json b/test/parser/samples/yield/output.json deleted file mode 100644 index b2e4b9430ff6..000000000000 --- a/test/parser/samples/yield/output.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "html": { - "start": 0, - "end": 7, - "type": "Fragment", - "children": [ - { - "start": 0, - "end": 7, - "type": "MustacheTag", - "expression": { - "type": "Identifier", - "start": 1, - "end": 6, - "name": "yield" - } - } - ] - } -} \ No newline at end of file diff --git a/test/runtime/index.js b/test/runtime/index.js index 408fda40f457..f070eb818551 100644 --- a/test/runtime/index.js +++ b/test/runtime/index.js @@ -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"; @@ -10,6 +10,7 @@ import { showOutput, loadConfig, loadSvelte, + cleanRequireCache, env, setupHtmlEqual, mkdirp @@ -79,11 +80,7 @@ describe("runtime", () => { compileOptions.immutable = config.immutable; compileOptions.accessors = 'accessors' in config ? config.accessors : true; - Object.keys(require.cache) - .filter(x => x.endsWith('.svelte')) - .forEach(file => { - delete require.cache[file]; - }); + cleanRequireCache(); let mod; let SvelteComponent; diff --git a/test/runtime/samples/action-receives-element-mounted/_config.js b/test/runtime/samples/action-receives-element-mounted/_config.js new file mode 100644 index 000000000000..0806d0fa909f --- /dev/null +++ b/test/runtime/samples/action-receives-element-mounted/_config.js @@ -0,0 +1,8 @@ +const result = {}; + +export default { + props: { result }, + async test({ assert, component, target, window }) { + assert.notEqual(result.parentElement, null); + } +}; diff --git a/test/runtime/samples/action-receives-element-mounted/main.svelte b/test/runtime/samples/action-receives-element-mounted/main.svelte new file mode 100644 index 000000000000..a53ce81de0ac --- /dev/null +++ b/test/runtime/samples/action-receives-element-mounted/main.svelte @@ -0,0 +1,8 @@ + + +

    Hello!

    \ No newline at end of file diff --git a/test/runtime/samples/apply-directives-in-order-2/_config.js b/test/runtime/samples/apply-directives-in-order-2/_config.js new file mode 100644 index 000000000000..a74ce41cb66f --- /dev/null +++ b/test/runtime/samples/apply-directives-in-order-2/_config.js @@ -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', + ]); + }, +}; diff --git a/test/runtime/samples/apply-directives-in-order-2/main.svelte b/test/runtime/samples/apply-directives-in-order-2/main.svelte new file mode 100644 index 000000000000..e91c4b6a1497 --- /dev/null +++ b/test/runtime/samples/apply-directives-in-order-2/main.svelte @@ -0,0 +1,34 @@ + + + + + + + + diff --git a/test/runtime/samples/apply-directives-in-order/_config.js b/test/runtime/samples/apply-directives-in-order/_config.js new file mode 100644 index 000000000000..e5e8980ed115 --- /dev/null +++ b/test/runtime/samples/apply-directives-in-order/_config.js @@ -0,0 +1,37 @@ +export default { + props: { + value: '' + }, + + html: ` + +

    + `, + + ssrHtml: ` + +

    + `, + + async test({ assert, component, target, window }) { + const input = target.querySelector('input'); + + const event = new window.Event('input'); + input.value = 'h'; + await input.dispatchEvent(event); + + assert.equal(input.value, 'H'); + assert.htmlEqual(target.innerHTML, ` + +

    H

    + `); + + input.value = 'he'; + await input.dispatchEvent(event); + assert.equal(input.value, 'HE'); + assert.htmlEqual(target.innerHTML, ` + +

    HE

    + `); + }, +}; diff --git a/test/runtime/samples/apply-directives-in-order/main.svelte b/test/runtime/samples/apply-directives-in-order/main.svelte new file mode 100644 index 000000000000..be652c7b7956 --- /dev/null +++ b/test/runtime/samples/apply-directives-in-order/main.svelte @@ -0,0 +1,10 @@ + + + +

    {value}

    diff --git a/test/runtime/samples/binding-indirect-spread/_config.js b/test/runtime/samples/binding-indirect-spread/_config.js new file mode 100644 index 000000000000..1f24fcdbcb12 --- /dev/null +++ b/test/runtime/samples/binding-indirect-spread/_config.js @@ -0,0 +1,44 @@ +export default { + skip_if_ssr: true, + async test({ assert, component, target, window }) { + const event = new window.MouseEvent('click'); + + const [radio1, radio2, radio3] = target.querySelectorAll('input[type=radio]'); + + assert.ok(!radio1.checked); + assert.ok(radio2.checked); + assert.ok(!radio3.checked); + + component.radio = 'radio1'; + + assert.ok(radio1.checked); + assert.ok(!radio2.checked); + assert.ok(!radio3.checked); + + await radio3.dispatchEvent(event); + + assert.equal(component.radio, 'radio3'); + assert.ok(!radio1.checked); + assert.ok(!radio2.checked); + assert.ok(radio3.checked); + + const [check1, check2, check3] = target.querySelectorAll('input[type=checkbox]'); + + assert.ok(!check1.checked); + assert.ok(check2.checked); + assert.ok(!check3.checked); + + component.check = ['check1', 'check2']; + + assert.ok(check1.checked); + assert.ok(check2.checked); + assert.ok(!check3.checked); + + await check3.dispatchEvent(event); + + assert.deepEqual(component.check, ['check1', 'check2', 'check3']); + assert.ok(check1.checked); + assert.ok(check2.checked); + assert.ok(check3.checked); + } +}; diff --git a/test/runtime/samples/binding-indirect-spread/main.svelte b/test/runtime/samples/binding-indirect-spread/main.svelte new file mode 100644 index 000000000000..43129b08b7d6 --- /dev/null +++ b/test/runtime/samples/binding-indirect-spread/main.svelte @@ -0,0 +1,12 @@ + + + + + + + + + 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 000000000000..74bc70d4144f --- /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 000000000000..2c1c4530914f --- /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/bitmask-overflow-slot-3/Echo.svelte b/test/runtime/samples/bitmask-overflow-slot-3/Echo.svelte new file mode 100644 index 000000000000..d3ecf142c924 --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-slot-3/Echo.svelte @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/test/runtime/samples/bitmask-overflow-slot-3/_config.js b/test/runtime/samples/bitmask-overflow-slot-3/_config.js new file mode 100644 index 000000000000..93e548e5f7ef --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-slot-3/_config.js @@ -0,0 +1,30 @@ +export default { + + html: ` +

    _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

    +

    0

    + + `, + + async test({ assert, component, target, window }) { + // change from inside + const button = target.querySelector('button'); + await button.dispatchEvent(new window.MouseEvent('click')); + + assert.htmlEqual(target.innerHTML, ` +

    _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

    +

    1

    + + `); + + // change from outside + component._0 = 'a'; + component._40 = 'b'; + + assert.htmlEqual(target.innerHTML, ` +

    a_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_39b

    +

    1

    + + `); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/bitmask-overflow-slot-3/main.svelte b/test/runtime/samples/bitmask-overflow-slot-3/main.svelte new file mode 100644 index 000000000000..ae798e4aeeb5 --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-slot-3/main.svelte @@ -0,0 +1,11 @@ + + + +

    {_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}

    +

    {dummy}

    +
    + diff --git a/test/runtime/samples/bitmask-overflow-slot-4/Echo.svelte b/test/runtime/samples/bitmask-overflow-slot-4/Echo.svelte new file mode 100644 index 000000000000..2e1beda492d9 --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-slot-4/Echo.svelte @@ -0,0 +1,11 @@ + + +

    {_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}

    + + \ No newline at end of file diff --git a/test/runtime/samples/bitmask-overflow-slot-4/_config.js b/test/runtime/samples/bitmask-overflow-slot-4/_config.js new file mode 100644 index 000000000000..cdaa5de77fa6 --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-slot-4/_config.js @@ -0,0 +1,41 @@ +export default { + html: ` +

    _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

    +

    0

    +

    0

    + + `, + + async test({ assert, component, target, window }) { + // change from inside + const button = target.querySelector('button'); + await button.dispatchEvent(new window.MouseEvent('click')); + + assert.htmlEqual(target.innerHTML, ` +

    _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

    +

    0

    +

    1

    + + `); + + // change from outside + component._0 = 'a'; + + assert.htmlEqual(target.innerHTML, ` +

    _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

    +

    a

    +

    1

    + + `); + + // change from outside through props + component._40 = 'b'; + + assert.htmlEqual(target.innerHTML, ` +

    _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_39b

    +

    a

    +

    1

    + + `); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/bitmask-overflow-slot-4/main.svelte b/test/runtime/samples/bitmask-overflow-slot-4/main.svelte new file mode 100644 index 000000000000..7e02487a305d --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-slot-4/main.svelte @@ -0,0 +1,12 @@ + + + +

    {_0}

    +

    {dummy}

    +
    + diff --git a/test/runtime/samples/bitmask-overflow-slot-5/Echo.svelte b/test/runtime/samples/bitmask-overflow-slot-5/Echo.svelte new file mode 100644 index 000000000000..dddb3f76428f --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-slot-5/Echo.svelte @@ -0,0 +1,13 @@ + + +

    {_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}

    +

    {b}

    + + \ No newline at end of file diff --git a/test/runtime/samples/bitmask-overflow-slot-5/_config.js b/test/runtime/samples/bitmask-overflow-slot-5/_config.js new file mode 100644 index 000000000000..7dedb8f7ebde --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-slot-5/_config.js @@ -0,0 +1,49 @@ +export default { + html: ` +

    _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

    +

    b

    +

    -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

    +

    0

    +

    0

    + + `, + + async test({ assert, component, target, window }) { + // change from inside + const button = target.querySelector('button'); + await button.dispatchEvent(new window.MouseEvent('click')); + + assert.htmlEqual(target.innerHTML, ` +

    _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

    +

    b

    +

    -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

    +

    0

    +

    1

    + + `); + + // change from outside + component.a = 'AA'; + + assert.htmlEqual(target.innerHTML, ` +

    _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

    +

    b

    +

    -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

    +

    AA

    +

    1

    + + `); + + // change from outside through props + component.b = 'BB'; + + assert.htmlEqual(target.innerHTML, ` +

    _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

    +

    BB

    +

    -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

    +

    AA

    +

    1

    + + `); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/bitmask-overflow-slot-5/main.svelte b/test/runtime/samples/bitmask-overflow-slot-5/main.svelte new file mode 100644 index 000000000000..b17d6f7baef8 --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-slot-5/main.svelte @@ -0,0 +1,13 @@ + + + +

    {_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}

    +

    {a}

    +

    {dummy}

    +
    + diff --git a/test/runtime/samples/component-binding-blowback-c/main.svelte b/test/runtime/samples/component-binding-blowback-c/main.svelte index 4876af13a8a9..75552bf358d0 100644 --- a/test/runtime/samples/component-binding-blowback-c/main.svelte +++ b/test/runtime/samples/component-binding-blowback-c/main.svelte @@ -4,7 +4,7 @@ export let count; export let idToValue = Object.create(null); - function ids() { + function ids(count) { return new Array(count) .fill(null) .map((_, i) => ({ id: 'id-' + i})) @@ -15,7 +15,7 @@
      - {#each ids() as object (object.id)} + {#each ids(count) as object (object.id)} {object.id}: value is {idToValue[object.id]} diff --git a/test/runtime/samples/component-slot-fallback-empty/Nested.svelte b/test/runtime/samples/component-slot-fallback-empty/Nested.svelte new file mode 100644 index 000000000000..9e6683feb77a --- /dev/null +++ b/test/runtime/samples/component-slot-fallback-empty/Nested.svelte @@ -0,0 +1,4 @@ +
      +

      default fallback content

      + bar fallback +
      \ No newline at end of file diff --git a/test/runtime/samples/component-slot-fallback-empty/_config.js b/test/runtime/samples/component-slot-fallback-empty/_config.js new file mode 100644 index 000000000000..2e153d24db01 --- /dev/null +++ b/test/runtime/samples/component-slot-fallback-empty/_config.js @@ -0,0 +1,13 @@ +export default { + html: ` +
      +

      default fallback content

      + +
      + +
      +

      default fallback content

      + bar fallback +
      + ` +}; diff --git a/test/runtime/samples/component-slot-fallback-empty/main.svelte b/test/runtime/samples/component-slot-fallback-empty/main.svelte new file mode 100644 index 000000000000..7ae5f4c5d778 --- /dev/null +++ b/test/runtime/samples/component-slot-fallback-empty/main.svelte @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/test/runtime/samples/component-slot-let-destructured-2/Nested.svelte b/test/runtime/samples/component-slot-let-destructured-2/Nested.svelte new file mode 100644 index 000000000000..5dfe32bc7ff6 --- /dev/null +++ b/test/runtime/samples/component-slot-let-destructured-2/Nested.svelte @@ -0,0 +1,5 @@ + + + diff --git a/test/runtime/samples/component-slot-let-destructured-2/_config.js b/test/runtime/samples/component-slot-let-destructured-2/_config.js new file mode 100644 index 000000000000..38b04b7b5e06 --- /dev/null +++ b/test/runtime/samples/component-slot-let-destructured-2/_config.js @@ -0,0 +1,68 @@ +export default { + html: ` +
      + hello world 0 hello + +
      +
      + hello world 0 hello + +
      +
      + hello world 0 hello + +
      + `, + async test({ assert, component, target, window }) { + const [button1, button2, button3] = target.querySelectorAll('button'); + const event = new window.MouseEvent('click'); + + await button1.dispatchEvent(event); + assert.htmlEqual(target.innerHTML, ` +
      + hello world 1 hello + +
      +
      + hello world 0 hello + +
      +
      + hello world 0 hello + +
      + `); + + await button2.dispatchEvent(event); + assert.htmlEqual(target.innerHTML, ` +
      + hello world 1 hello + +
      +
      + hello world 1 hello + +
      +
      + hello world 0 hello + +
      + `); + + await button3.dispatchEvent(event); + assert.htmlEqual(target.innerHTML, ` +
      + hello world 1 hello + +
      +
      + hello world 1 hello + +
      +
      + hello world 1 hello + +
      + `); + } +}; diff --git a/test/runtime/samples/component-slot-let-destructured-2/main.svelte b/test/runtime/samples/component-slot-let-destructured-2/main.svelte new file mode 100644 index 000000000000..215a1390d90a --- /dev/null +++ b/test/runtime/samples/component-slot-let-destructured-2/main.svelte @@ -0,0 +1,28 @@ + + +
      + + {pair[0]} {pair[1]} {c} {foo} + + + +
      + +
      + + {a} {b} {d} {foo} + + + +
      + +
      + + {a} {b} {e} {foo} + + + +
      \ No newline at end of file diff --git a/test/runtime/samples/component-slot-let-g/A.svelte b/test/runtime/samples/component-slot-let-g/A.svelte new file mode 100644 index 000000000000..4f4ac95014bb --- /dev/null +++ b/test/runtime/samples/component-slot-let-g/A.svelte @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/test/runtime/samples/component-slot-let-g/_config.js b/test/runtime/samples/component-slot-let-g/_config.js new file mode 100644 index 000000000000..aaa9895ea8a0 --- /dev/null +++ b/test/runtime/samples/component-slot-let-g/_config.js @@ -0,0 +1,22 @@ +export default { + html: ` + 1 + 0 + `, + async test({ assert, target, component, window }) { + component.x = 2; + + assert.htmlEqual(target.innerHTML, ` + 2 + 0 + `); + + const span = target.querySelector('span'); + await span.dispatchEvent(new window.MouseEvent('click')); + + assert.htmlEqual(target.innerHTML, ` + 2 + 2 + `); + } +}; diff --git a/test/runtime/samples/component-slot-let-g/main.svelte b/test/runtime/samples/component-slot-let-g/main.svelte new file mode 100644 index 000000000000..e7d4890e6bf0 --- /dev/null +++ b/test/runtime/samples/component-slot-let-g/main.svelte @@ -0,0 +1,17 @@ + + + + y = reflected} + slot="foo" + let:reflected + class={reflected} + > + {reflected} + + +{ y } \ No newline at end of file diff --git a/test/runtime/samples/component-slot-nested-if/Display.svelte b/test/runtime/samples/component-slot-nested-if/Display.svelte new file mode 100644 index 000000000000..d9034e4be29a --- /dev/null +++ b/test/runtime/samples/component-slot-nested-if/Display.svelte @@ -0,0 +1,2 @@ +Display: + \ No newline at end of file diff --git a/test/runtime/samples/component-slot-nested-if/Input.svelte b/test/runtime/samples/component-slot-nested-if/Input.svelte new file mode 100644 index 000000000000..fd8f22db004c --- /dev/null +++ b/test/runtime/samples/component-slot-nested-if/Input.svelte @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/test/runtime/samples/component-slot-nested-if/_config.js b/test/runtime/samples/component-slot-nested-if/_config.js new file mode 100644 index 000000000000..89dfd006cc76 --- /dev/null +++ b/test/runtime/samples/component-slot-nested-if/_config.js @@ -0,0 +1,30 @@ +export default { + html: ` + + `, + async test({ assert, target, snapshot, component, window }) { + const input = target.querySelector('input'); + + input.value = 'a'; + await input.dispatchEvent(new window.Event('input')); + + assert.htmlEqual( + target.innerHTML, + ` + + Display: a + ` + ); + + input.value = 'abc'; + await input.dispatchEvent(new window.Event('input')); + + assert.htmlEqual( + target.innerHTML, + ` + + Display: abc + ` + ); + }, +}; diff --git a/test/runtime/samples/component-slot-nested-if/main.svelte b/test/runtime/samples/component-slot-nested-if/main.svelte new file mode 100644 index 000000000000..727927b15714 --- /dev/null +++ b/test/runtime/samples/component-slot-nested-if/main.svelte @@ -0,0 +1,10 @@ + + + + {#if foo} + {foo} + {/if} + 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 000000000000..c6f086d96c19 --- /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 000000000000..6ffe624782e0 --- /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 000000000000..c29ef3e85be2 --- /dev/null +++ b/test/runtime/samples/component-slot-warning/main.svelte @@ -0,0 +1,7 @@ + + + + + diff --git a/test/runtime/samples/deconflict-contextual-bind/Widget.svelte b/test/runtime/samples/deconflict-contextual-bind/Widget.svelte new file mode 100644 index 000000000000..3aaa59b74757 --- /dev/null +++ b/test/runtime/samples/deconflict-contextual-bind/Widget.svelte @@ -0,0 +1,3 @@ + diff --git a/test/runtime/samples/deconflict-contextual-bind/_config.js b/test/runtime/samples/deconflict-contextual-bind/_config.js new file mode 100644 index 000000000000..7602cde02323 --- /dev/null +++ b/test/runtime/samples/deconflict-contextual-bind/_config.js @@ -0,0 +1,3 @@ +export default { + preserveIdentifiers: true +}; diff --git a/test/runtime/samples/deconflict-contextual-bind/main.svelte b/test/runtime/samples/deconflict-contextual-bind/main.svelte new file mode 100644 index 000000000000..fe91deca17f1 --- /dev/null +++ b/test/runtime/samples/deconflict-contextual-bind/main.svelte @@ -0,0 +1,8 @@ + + +{#each values as value} + +{/each} diff --git a/test/runtime/samples/dev-warning-each-block-no-sets-maps/_config.js b/test/runtime/samples/dev-warning-each-block-no-sets-maps/_config.js new file mode 100644 index 000000000000..83481d9ebebf --- /dev/null +++ b/test/runtime/samples/dev-warning-each-block-no-sets-maps/_config.js @@ -0,0 +1,6 @@ +export default { + compileOptions: { + dev: true + }, + error: `{#each} only iterates over array-like objects. You can use a spread to convert this iterable into an array.` +}; diff --git a/test/runtime/samples/dev-warning-each-block-no-sets-maps/main.svelte b/test/runtime/samples/dev-warning-each-block-no-sets-maps/main.svelte new file mode 100644 index 000000000000..e1aae26d129a --- /dev/null +++ b/test/runtime/samples/dev-warning-each-block-no-sets-maps/main.svelte @@ -0,0 +1,7 @@ + + +{#each foo as item} +
      {item}
      +{/each} \ No newline at end of file diff --git a/test/runtime/samples/dev-warning-each-block-require-arraylike/_config.js b/test/runtime/samples/dev-warning-each-block-require-arraylike/_config.js new file mode 100644 index 000000000000..62e5fc209b54 --- /dev/null +++ b/test/runtime/samples/dev-warning-each-block-require-arraylike/_config.js @@ -0,0 +1,6 @@ +export default { + compileOptions: { + dev: true + }, + error: `{#each} only iterates over array-like objects.` +}; diff --git a/test/runtime/samples/dev-warning-each-block-require-arraylike/main.svelte b/test/runtime/samples/dev-warning-each-block-require-arraylike/main.svelte new file mode 100644 index 000000000000..f85df8d84bd7 --- /dev/null +++ b/test/runtime/samples/dev-warning-each-block-require-arraylike/main.svelte @@ -0,0 +1,3 @@ +{#each {} as item} +
      {item}
      +{/each} \ No newline at end of file diff --git a/test/runtime/samples/dev-warning-unknown-props-2/Foo.svelte b/test/runtime/samples/dev-warning-unknown-props-2/Foo.svelte new file mode 100644 index 000000000000..bc56c4d89448 --- /dev/null +++ b/test/runtime/samples/dev-warning-unknown-props-2/Foo.svelte @@ -0,0 +1 @@ +Foo diff --git a/test/runtime/samples/dev-warning-unknown-props-2/_config.js b/test/runtime/samples/dev-warning-unknown-props-2/_config.js new file mode 100644 index 000000000000..9bff4a2a741b --- /dev/null +++ b/test/runtime/samples/dev-warning-unknown-props-2/_config.js @@ -0,0 +1,9 @@ +export default { + compileOptions: { + dev: true + }, + + warnings: [ + ` was created with unknown prop 'fo'` + ] +}; diff --git a/test/runtime/samples/dev-warning-unknown-props-2/main.svelte b/test/runtime/samples/dev-warning-unknown-props-2/main.svelte new file mode 100644 index 000000000000..1566cf3e41e7 --- /dev/null +++ b/test/runtime/samples/dev-warning-unknown-props-2/main.svelte @@ -0,0 +1,5 @@ + + + diff --git a/test/runtime/samples/each-block-destructured-object-reserved-key/_config.js b/test/runtime/samples/each-block-destructured-object-reserved-key/_config.js new file mode 100644 index 000000000000..c04e98469156 --- /dev/null +++ b/test/runtime/samples/each-block-destructured-object-reserved-key/_config.js @@ -0,0 +1,5 @@ +export default { + html: ` +

      bar

      + ` +}; diff --git a/test/runtime/samples/each-block-destructured-object-reserved-key/main.svelte b/test/runtime/samples/each-block-destructured-object-reserved-key/main.svelte new file mode 100644 index 000000000000..c3e11c3ea1ad --- /dev/null +++ b/test/runtime/samples/each-block-destructured-object-reserved-key/main.svelte @@ -0,0 +1,7 @@ + + +{#each foo as { in: bar }} +

      {bar}

      +{/each} diff --git a/test/runtime/samples/each-block-keyed-dynamic-2/_config.js b/test/runtime/samples/each-block-keyed-dynamic-2/_config.js new file mode 100644 index 000000000000..7eba75a5ff09 --- /dev/null +++ b/test/runtime/samples/each-block-keyed-dynamic-2/_config.js @@ -0,0 +1,23 @@ +export default { + html: ` + + 0 +
        + `, + + async test({ assert, component, target, window }) { + const button = target.querySelector("button"); + + const event = new window.MouseEvent("click"); + await button.dispatchEvent(event); + + assert.htmlEqual( + target.innerHTML, + ` + + 1 +
          + ` + ); + } +}; diff --git a/test/runtime/samples/each-block-keyed-dynamic-2/main.svelte b/test/runtime/samples/each-block-keyed-dynamic-2/main.svelte new file mode 100644 index 000000000000..ab455a585e84 --- /dev/null +++ b/test/runtime/samples/each-block-keyed-dynamic-2/main.svelte @@ -0,0 +1,20 @@ + + + +{num} +
            + {#each cards as c, i (i)} +
          • {c}
          • + {/each} +
          diff --git a/test/runtime/samples/each-block-string/_config.js b/test/runtime/samples/each-block-string/_config.js new file mode 100644 index 000000000000..7366c964ebb1 --- /dev/null +++ b/test/runtime/samples/each-block-string/_config.js @@ -0,0 +1,10 @@ +export default { + compileOptions: { + dev: true + }, + html: ` +
          f
          +
          o
          +
          o
          + ` +}; diff --git a/test/runtime/samples/each-block-string/main.svelte b/test/runtime/samples/each-block-string/main.svelte new file mode 100644 index 000000000000..ae60f0f6b32f --- /dev/null +++ b/test/runtime/samples/each-block-string/main.svelte @@ -0,0 +1,3 @@ +{#each 'foo' as c} +
          {c}
          +{/each} diff --git a/test/runtime/samples/event-handler-dynamic-2/_config.js b/test/runtime/samples/event-handler-dynamic-2/_config.js new file mode 100644 index 000000000000..c996d8f2aaec --- /dev/null +++ b/test/runtime/samples/event-handler-dynamic-2/_config.js @@ -0,0 +1,33 @@ +export default { + html: ` + +

          0

          + + + `, + + async test({ assert, target, window }) { + const [toggle, handler_a, handler_b] = target.querySelectorAll('button'); + const p = target.querySelector('p'); + + const event = new window.MouseEvent('click'); + + await handler_a.dispatchEvent(event); + assert.equal(p.innerHTML, '1'); + + await toggle.dispatchEvent(event); + + await handler_a.dispatchEvent(event); + assert.equal(p.innerHTML, '2'); + + await toggle.dispatchEvent(event); + + await handler_b.dispatchEvent(event); + assert.equal(p.innerHTML, '1'); + + await toggle.dispatchEvent(event); + + await handler_b.dispatchEvent(event); + assert.equal(p.innerHTML, '2'); + }, +}; diff --git a/test/runtime/samples/event-handler-dynamic-2/main.svelte b/test/runtime/samples/event-handler-dynamic-2/main.svelte new file mode 100644 index 000000000000..1b2041d3b80f --- /dev/null +++ b/test/runtime/samples/event-handler-dynamic-2/main.svelte @@ -0,0 +1,20 @@ + + + + +

          {number}

          + + + diff --git a/test/runtime/samples/event-handler-dynamic-bound-var/Nested.svelte b/test/runtime/samples/event-handler-dynamic-bound-var/Nested.svelte new file mode 100644 index 000000000000..948fc308c0a3 --- /dev/null +++ b/test/runtime/samples/event-handler-dynamic-bound-var/Nested.svelte @@ -0,0 +1,7 @@ + +{text} \ No newline at end of file diff --git a/test/runtime/samples/event-handler-dynamic-bound-var/_config.js b/test/runtime/samples/event-handler-dynamic-bound-var/_config.js new file mode 100644 index 000000000000..c832127c092d --- /dev/null +++ b/test/runtime/samples/event-handler-dynamic-bound-var/_config.js @@ -0,0 +1,20 @@ +export default { + html: ` + + Hello World + `, + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + + const event = new window.MouseEvent('click'); + + await button.dispatchEvent(event); + assert.htmlEqual( + target.innerHTML, + ` + + Bye World + ` + ); + }, +}; diff --git a/test/runtime/samples/event-handler-dynamic-bound-var/main.svelte b/test/runtime/samples/event-handler-dynamic-bound-var/main.svelte new file mode 100644 index 000000000000..bb7d9befc409 --- /dev/null +++ b/test/runtime/samples/event-handler-dynamic-bound-var/main.svelte @@ -0,0 +1,8 @@ + + + + + diff --git a/test/runtime/samples/event-handler-dynamic-hash/_config.js b/test/runtime/samples/event-handler-dynamic-hash/_config.js new file mode 100644 index 000000000000..e60e5615245f --- /dev/null +++ b/test/runtime/samples/event-handler-dynamic-hash/_config.js @@ -0,0 +1,56 @@ +export default { + html: ` +

          + + +

          +

          0

          + + `, + + 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, ` +

          + + +

          +

          0

          + + `); + + await updateButton1.dispatchEvent(event); + await button.dispatchEvent(event); + assert.htmlEqual(target.innerHTML, ` +

          + + +

          +

          1

          + + `); + + await updateButton2.dispatchEvent(event); + await button.dispatchEvent(event); + assert.htmlEqual(target.innerHTML, ` +

          + + +

          +

          2

          + + `); + }, +}; diff --git a/test/runtime/samples/event-handler-dynamic-hash/main.svelte b/test/runtime/samples/event-handler-dynamic-hash/main.svelte new file mode 100644 index 000000000000..c81af02006c7 --- /dev/null +++ b/test/runtime/samples/event-handler-dynamic-hash/main.svelte @@ -0,0 +1,23 @@ + + +

          + + +

          + +

          { number }

          + + \ No newline at end of file diff --git a/test/runtime/samples/event-handler-dynamic-invalid/_config.js b/test/runtime/samples/event-handler-dynamic-invalid/_config.js new file mode 100644 index 000000000000..ba1777f94503 --- /dev/null +++ b/test/runtime/samples/event-handler-dynamic-invalid/_config.js @@ -0,0 +1,28 @@ +export default { + html: ` + + `, + + 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); + }, +}; diff --git a/test/runtime/samples/event-handler-dynamic-invalid/main.svelte b/test/runtime/samples/event-handler-dynamic-invalid/main.svelte new file mode 100644 index 000000000000..f4e8c5fdb7f0 --- /dev/null +++ b/test/runtime/samples/event-handler-dynamic-invalid/main.svelte @@ -0,0 +1,13 @@ + + + + + diff --git a/test/runtime/samples/event-handler-dynamic-modifier-once/_config.js b/test/runtime/samples/event-handler-dynamic-modifier-once/_config.js new file mode 100644 index 000000000000..41daf374c82d --- /dev/null +++ b/test/runtime/samples/event-handler-dynamic-modifier-once/_config.js @@ -0,0 +1,16 @@ +export default { + html: ` + + `, + + 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); + } +}; diff --git a/test/runtime/samples/event-handler-dynamic-modifier-once/main.svelte b/test/runtime/samples/event-handler-dynamic-modifier-once/main.svelte new file mode 100644 index 000000000000..d363d708ba8f --- /dev/null +++ b/test/runtime/samples/event-handler-dynamic-modifier-once/main.svelte @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/test/runtime/samples/event-handler-dynamic-modifier-prevent-default/_config.js b/test/runtime/samples/event-handler-dynamic-modifier-prevent-default/_config.js new file mode 100644 index 000000000000..4fa032bf37ab --- /dev/null +++ b/test/runtime/samples/event-handler-dynamic-modifier-prevent-default/_config.js @@ -0,0 +1,16 @@ +export default { + html: ` + + `, + + 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); + } +}; diff --git a/test/runtime/samples/event-handler-dynamic-modifier-prevent-default/main.svelte b/test/runtime/samples/event-handler-dynamic-modifier-prevent-default/main.svelte new file mode 100644 index 000000000000..49d42f330523 --- /dev/null +++ b/test/runtime/samples/event-handler-dynamic-modifier-prevent-default/main.svelte @@ -0,0 +1,11 @@ + + + \ No newline at end of file diff --git a/test/runtime/samples/event-handler-dynamic-modifier-self/_config.js b/test/runtime/samples/event-handler-dynamic-modifier-self/_config.js new file mode 100644 index 000000000000..6d7d29e48288 --- /dev/null +++ b/test/runtime/samples/event-handler-dynamic-modifier-self/_config.js @@ -0,0 +1,16 @@ +export default { + html: ` +
          + +
          + `, + + 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); + }, +}; diff --git a/test/runtime/samples/event-handler-dynamic-modifier-self/main.svelte b/test/runtime/samples/event-handler-dynamic-modifier-self/main.svelte new file mode 100644 index 000000000000..b57d88ec020f --- /dev/null +++ b/test/runtime/samples/event-handler-dynamic-modifier-self/main.svelte @@ -0,0 +1,13 @@ + + +
          + +
          diff --git a/test/runtime/samples/event-handler-dynamic-modifier-stop-propagation/_config.js b/test/runtime/samples/event-handler-dynamic-modifier-stop-propagation/_config.js new file mode 100644 index 000000000000..8517429e5ceb --- /dev/null +++ b/test/runtime/samples/event-handler-dynamic-modifier-stop-propagation/_config.js @@ -0,0 +1,19 @@ +export default { + html: ` +
          + +
          + `, + + 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); + } +}; diff --git a/test/runtime/samples/event-handler-dynamic-modifier-stop-propagation/main.svelte b/test/runtime/samples/event-handler-dynamic-modifier-stop-propagation/main.svelte new file mode 100644 index 000000000000..bad73599276d --- /dev/null +++ b/test/runtime/samples/event-handler-dynamic-modifier-stop-propagation/main.svelte @@ -0,0 +1,20 @@ + + +
          + +
          \ No newline at end of file diff --git a/test/runtime/samples/event-handler-dynamic-multiple/_config.js b/test/runtime/samples/event-handler-dynamic-multiple/_config.js new file mode 100644 index 000000000000..cf17c61f6055 --- /dev/null +++ b/test/runtime/samples/event-handler-dynamic-multiple/_config.js @@ -0,0 +1,14 @@ +export default { + html: ` + + `, + + 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); + } +}; diff --git a/test/runtime/samples/event-handler-dynamic-multiple/main.svelte b/test/runtime/samples/event-handler-dynamic-multiple/main.svelte new file mode 100644 index 000000000000..2dbbe61ea652 --- /dev/null +++ b/test/runtime/samples/event-handler-dynamic-multiple/main.svelte @@ -0,0 +1,11 @@ + + + diff --git a/test/runtime/samples/event-handler-dynamic/_config.js b/test/runtime/samples/event-handler-dynamic/_config.js index 41cfd6e72943..e60e5615245f 100644 --- a/test/runtime/samples/event-handler-dynamic/_config.js +++ b/test/runtime/samples/event-handler-dynamic/_config.js @@ -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, `

          @@ -24,7 +30,7 @@ export default {

          0

          `); - + await updateButton1.dispatchEvent(event); await button.dispatchEvent(event); assert.htmlEqual(target.innerHTML, ` @@ -35,7 +41,7 @@ export default {

          1

          `); - + await updateButton2.dispatchEvent(event); await button.dispatchEvent(event); assert.htmlEqual(target.innerHTML, ` diff --git a/test/runtime/samples/event-handler-modifier-body-once/_config.js b/test/runtime/samples/event-handler-modifier-body-once/_config.js new file mode 100644 index 000000000000..412703401098 --- /dev/null +++ b/test/runtime/samples/event-handler-modifier-body-once/_config.js @@ -0,0 +1,11 @@ +export default { + async test({ assert, component, window }) { + const event = new window.MouseEvent('click'); + + await window.document.body.dispatchEvent(event); + assert.equal(component.count, 1); + + await window.document.body.dispatchEvent(event); + assert.equal(component.count, 1); + } +}; diff --git a/test/runtime/samples/event-handler-modifier-body-once/main.svelte b/test/runtime/samples/event-handler-modifier-body-once/main.svelte new file mode 100644 index 000000000000..423a75d1f056 --- /dev/null +++ b/test/runtime/samples/event-handler-modifier-body-once/main.svelte @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/test/runtime/samples/instrumentation-update-expression/_config.js b/test/runtime/samples/instrumentation-update-expression/_config.js new file mode 100644 index 000000000000..cc33422f6fb4 --- /dev/null +++ b/test/runtime/samples/instrumentation-update-expression/_config.js @@ -0,0 +1,31 @@ +export default { + html: ` +

          0

          + + +

          0

          + + + `, + async test({ assert, target, window }) { + const [foo, bar] = target.querySelectorAll('p'); + const [button1, button2, button3, button4] = target.querySelectorAll('button'); + const event = new window.MouseEvent('click'); + + await button1.dispatchEvent(event); + assert.equal(foo.innerHTML, '1'); + assert.equal(bar.innerHTML, '0'); + + await button2.dispatchEvent(event); + assert.equal(foo.innerHTML, '2'); + assert.equal(bar.innerHTML, '0'); + + await button3.dispatchEvent(event); + assert.equal(foo.innerHTML, '2'); + assert.equal(bar.innerHTML, '1'); + + await button4.dispatchEvent(event); + assert.equal(foo.innerHTML, '2'); + assert.equal(bar.innerHTML, '2'); + } +}; diff --git a/test/runtime/samples/instrumentation-update-expression/main.svelte b/test/runtime/samples/instrumentation-update-expression/main.svelte new file mode 100644 index 000000000000..0672f6330d83 --- /dev/null +++ b/test/runtime/samples/instrumentation-update-expression/main.svelte @@ -0,0 +1,14 @@ + + +

          {foo}

          + + + + +

          {bar.bar}

          + + + diff --git a/test/runtime/samples/keyed-each-dev-unique/_config.js b/test/runtime/samples/keyed-each-dev-unique/_config.js new file mode 100644 index 000000000000..8f46af9d5214 --- /dev/null +++ b/test/runtime/samples/keyed-each-dev-unique/_config.js @@ -0,0 +1,7 @@ +export default { + compileOptions: { + dev: true + }, + + error: `Cannot have duplicate keys in a keyed each` +}; diff --git a/test/runtime/samples/keyed-each-dev-unique/main.svelte b/test/runtime/samples/keyed-each-dev-unique/main.svelte new file mode 100644 index 000000000000..870e7beaa1c9 --- /dev/null +++ b/test/runtime/samples/keyed-each-dev-unique/main.svelte @@ -0,0 +1,7 @@ + + +{#each array as item (item)} + {item} +{/each} diff --git a/test/runtime/samples/lifecycle-onmount-infinite-loop/Child.svelte b/test/runtime/samples/lifecycle-onmount-infinite-loop/Child.svelte new file mode 100644 index 000000000000..ef16875b6448 --- /dev/null +++ b/test/runtime/samples/lifecycle-onmount-infinite-loop/Child.svelte @@ -0,0 +1 @@ +Child diff --git a/test/runtime/samples/lifecycle-onmount-infinite-loop/_config.js b/test/runtime/samples/lifecycle-onmount-infinite-loop/_config.js new file mode 100644 index 000000000000..a76a2686ac27 --- /dev/null +++ b/test/runtime/samples/lifecycle-onmount-infinite-loop/_config.js @@ -0,0 +1,6 @@ +export default { + test({ assert, component }) { + const { count } = component; + assert.deepEqual(count, 1); + } +}; diff --git a/test/runtime/samples/lifecycle-onmount-infinite-loop/main.svelte b/test/runtime/samples/lifecycle-onmount-infinite-loop/main.svelte new file mode 100644 index 000000000000..1fa4263e39ea --- /dev/null +++ b/test/runtime/samples/lifecycle-onmount-infinite-loop/main.svelte @@ -0,0 +1,16 @@ + + +
          diff --git a/test/runtime/samples/module-context-bind/_config.js b/test/runtime/samples/module-context-bind/_config.js new file mode 100644 index 000000000000..32bc9c4ce95d --- /dev/null +++ b/test/runtime/samples/module-context-bind/_config.js @@ -0,0 +1,4 @@ +export default { + skip_if_ssr: true, + html: '
          object
          ' +}; diff --git a/test/runtime/samples/module-context-bind/main.svelte b/test/runtime/samples/module-context-bind/main.svelte new file mode 100644 index 000000000000..1580102bd8fe --- /dev/null +++ b/test/runtime/samples/module-context-bind/main.svelte @@ -0,0 +1,11 @@ + + + + +
          {typeof bar}
          diff --git a/test/runtime/samples/reactive-values-no-implicit-member-expression/_config.js b/test/runtime/samples/reactive-values-no-implicit-member-expression/_config.js new file mode 100644 index 000000000000..05a81595898f --- /dev/null +++ b/test/runtime/samples/reactive-values-no-implicit-member-expression/_config.js @@ -0,0 +1,5 @@ +export default { + test({ assert, window }) { + assert.equal(window.document.title, 'foo'); + } +}; diff --git a/test/runtime/samples/reactive-values-no-implicit-member-expression/main.svelte b/test/runtime/samples/reactive-values-no-implicit-member-expression/main.svelte new file mode 100644 index 000000000000..a631d4d9f88c --- /dev/null +++ b/test/runtime/samples/reactive-values-no-implicit-member-expression/main.svelte @@ -0,0 +1,3 @@ + diff --git a/test/runtime/samples/reactive-values-store-destructured-undefined/_config.js b/test/runtime/samples/reactive-values-store-destructured-undefined/_config.js new file mode 100644 index 000000000000..5e3f15f5dcd6 --- /dev/null +++ b/test/runtime/samples/reactive-values-store-destructured-undefined/_config.js @@ -0,0 +1,6 @@ +export default { + html: ` +

          undefined

          +

          undefined

          + ` +}; diff --git a/test/runtime/samples/reactive-values-store-destructured-undefined/main.svelte b/test/runtime/samples/reactive-values-store-destructured-undefined/main.svelte new file mode 100644 index 000000000000..152e0e3e2e2a --- /dev/null +++ b/test/runtime/samples/reactive-values-store-destructured-undefined/main.svelte @@ -0,0 +1,9 @@ + + +

          {foo1}

          +

          {foo2}

          diff --git a/test/runtime/samples/spread-component-2/Widget.svelte b/test/runtime/samples/spread-component-2/Widget.svelte new file mode 100644 index 000000000000..ae27aeb5e531 --- /dev/null +++ b/test/runtime/samples/spread-component-2/Widget.svelte @@ -0,0 +1,13 @@ + + +

          foo: {foo}

          +

          baz: {baz} ({typeof baz})

          +

          qux: {qux}

          +

          quux: {quux}

          +

          selected: {selected}

          diff --git a/test/runtime/samples/spread-component-2/_config.js b/test/runtime/samples/spread-component-2/_config.js new file mode 100644 index 000000000000..6d36e8e60dfb --- /dev/null +++ b/test/runtime/samples/spread-component-2/_config.js @@ -0,0 +1,76 @@ +export default { + props: { + list: [{ + foo: 'lol', + baz: 40 + 2, + qux: 5, + quux: 'core' + }, { + foo: 'lolzz', + baz: 50 + 2, + qux: 1, + quux: 'quuxx' + }], + }, + + html: ` +
          +

          foo: lol

          +

          baz: 42 (number)

          +

          qux: 0

          +

          quux: core

          +

          selected: true

          +

          foo: lolzz

          +

          baz: 52 (number)

          +

          qux: 0

          +

          quux: quuxx

          +

          selected: false

          +
          + `, + + test({ assert, component, target }) { + component.list = [{ + foo: 'lol', + baz: 40 + 3, + qux: 8, + quux: 'heart' + }, { + foo: 'lolzz', + baz: 50 + 3, + qux: 8, + quux: 'heartxx' + }]; + + assert.htmlEqual(target.innerHTML, ` +
          +

          foo: lol

          +

          baz: 43 (number)

          +

          qux: 0

          +

          quux: heart

          +

          selected: true

          +

          foo: lolzz

          +

          baz: 53 (number)

          +

          qux: 0

          +

          quux: heartxx

          +

          selected: false

          +
          + `); + + component.qux = 1; + + assert.htmlEqual(target.innerHTML, ` +
          +

          foo: lol

          +

          baz: 43 (number)

          +

          qux: 1

          +

          quux: heart

          +

          selected: false

          +

          foo: lolzz

          +

          baz: 53 (number)

          +

          qux: 1

          +

          quux: heartxx

          +

          selected: true

          +
          + `); + } +}; diff --git a/test/runtime/samples/spread-component-2/main.svelte b/test/runtime/samples/spread-component-2/main.svelte new file mode 100644 index 000000000000..436e11f9c50d --- /dev/null +++ b/test/runtime/samples/spread-component-2/main.svelte @@ -0,0 +1,12 @@ + + +
          + {#each list as item, index (item.foo)} + + {/each} +
          diff --git a/test/runtime/samples/store-auto-subscribe-nullish/_config.js b/test/runtime/samples/store-auto-subscribe-nullish/_config.js new file mode 100644 index 000000000000..52e21cef05ed --- /dev/null +++ b/test/runtime/samples/store-auto-subscribe-nullish/_config.js @@ -0,0 +1,13 @@ +import { writable } from '../../../../store'; + +export default { + html: ` +

          undefined

          + `, + async test({ assert, component, target }) { + component.store = writable('foo'); + assert.htmlEqual(target.innerHTML, ` +

          foo

          + `); + } +}; diff --git a/test/runtime/samples/store-auto-subscribe-nullish/main.svelte b/test/runtime/samples/store-auto-subscribe-nullish/main.svelte new file mode 100644 index 000000000000..9c1ed4a56094 --- /dev/null +++ b/test/runtime/samples/store-auto-subscribe-nullish/main.svelte @@ -0,0 +1,5 @@ + + +

          {$store}

          diff --git a/test/runtime/samples/svg-tspan-preserve-space/_config.js b/test/runtime/samples/svg-tspan-preserve-space/_config.js new file mode 100644 index 000000000000..283af0a2b0c2 --- /dev/null +++ b/test/runtime/samples/svg-tspan-preserve-space/_config.js @@ -0,0 +1,3 @@ +export default { + html: `foo barfoo bar`, +}; diff --git a/test/runtime/samples/svg-tspan-preserve-space/main.svelte b/test/runtime/samples/svg-tspan-preserve-space/main.svelte new file mode 100644 index 000000000000..df43d575a906 --- /dev/null +++ b/test/runtime/samples/svg-tspan-preserve-space/main.svelte @@ -0,0 +1 @@ +foo {"bar"}foo bar \ No newline at end of file diff --git a/test/server-side-rendering/index.js b/test/server-side-rendering/index.js index 768917e83364..ee1319845dfe 100644 --- a/test/server-side-rendering/index.js +++ b/test/server-side-rendering/index.js @@ -1,13 +1,17 @@ import * as assert from "assert"; import * as fs from "fs"; import * as path from "path"; +import * as glob from 'tiny-glob/sync.js'; import { showOutput, loadConfig, + loadSvelte, setupHtmlEqual, tryToLoadJson, - shouldUpdateExpected + cleanRequireCache, + shouldUpdateExpected, + mkdirp } from "../helpers.js"; function tryToReadFile(file) { @@ -20,13 +24,11 @@ function tryToReadFile(file) { } const sveltePath = process.cwd().split('\\').join('/'); +let compile = null; describe("ssr", () => { before(() => { - require("../../register")({ - extensions: ['.svelte', '.html'], - sveltePath - }); + compile = loadSvelte(true).compile; return setupHtmlEqual(); }); @@ -34,9 +36,11 @@ describe("ssr", () => { fs.readdirSync(`${__dirname}/samples`).forEach(dir => { if (dir[0] === ".") return; + const config = loadConfig(`${__dirname}/samples/${dir}/_config.js`); + // add .solo to a sample directory name to only run that test, or // .show to always show the output. or both - const solo = /\.solo/.test(dir); + const solo = config.solo || /\.solo/.test(dir); const show = /\.show/.test(dir); if (solo && process.env.CI) { @@ -45,6 +49,18 @@ describe("ssr", () => { (solo ? it.only : it)(dir, () => { dir = path.resolve(`${__dirname}/samples`, dir); + + cleanRequireCache(); + + const compileOptions = { + sveltePath, + ...config.compileOptions, + generate: 'ssr', + format: 'cjs' + }; + + require("../../register")(compileOptions); + try { const Component = require(`${dir}/main.svelte`).default; @@ -127,21 +143,46 @@ describe("ssr", () => { (config.skip ? it.skip : solo ? it.only : it)(dir, () => { const cwd = path.resolve("test/runtime/samples", dir); - Object.keys(require.cache) - .filter(x => x.endsWith('.svelte')) - .forEach(file => { - delete require.cache[file]; - }); + cleanRequireCache(); delete global.window; - const compileOptions = Object.assign({ sveltePath }, config.compileOptions, { + const compileOptions = { + sveltePath, + ...config.compileOptions, generate: 'ssr', format: 'cjs' - }); + }; require("../../register")(compileOptions); + glob('**/*.svelte', { cwd }).forEach(file => { + if (file[0] === '_') return; + + const dir = `${cwd}/_output/ssr`; + const out = `${dir}/${file.replace(/\.svelte$/, '.js')}`; + + if (fs.existsSync(out)) { + fs.unlinkSync(out); + } + + mkdirp(dir); + + try { + const { js } = compile( + fs.readFileSync(`${cwd}/${file}`, 'utf-8'), + { + ...compileOptions, + filename: file + } + ); + + fs.writeFileSync(out, js.code); + } catch (err) { + // do nothing + } + }); + try { if (config.before_test) config.before_test(); diff --git a/test/server-side-rendering/samples/head-meta-hydrate-duplicate/_config.js b/test/server-side-rendering/samples/head-meta-hydrate-duplicate/_config.js new file mode 100644 index 000000000000..ae9b250f8657 --- /dev/null +++ b/test/server-side-rendering/samples/head-meta-hydrate-duplicate/_config.js @@ -0,0 +1,5 @@ +export default { + compileOptions: { + hydratable: true + } +}; diff --git a/test/server-side-rendering/samples/head-meta-hydrate-duplicate/_expected-head.html b/test/server-side-rendering/samples/head-meta-hydrate-duplicate/_expected-head.html new file mode 100644 index 000000000000..107753cdd0e5 --- /dev/null +++ b/test/server-side-rendering/samples/head-meta-hydrate-duplicate/_expected-head.html @@ -0,0 +1,4 @@ +Some Title + + + \ No newline at end of file diff --git a/test/server-side-rendering/samples/head-meta-hydrate-duplicate/_expected.html b/test/server-side-rendering/samples/head-meta-hydrate-duplicate/_expected.html new file mode 100644 index 000000000000..a469e618fa94 --- /dev/null +++ b/test/server-side-rendering/samples/head-meta-hydrate-duplicate/_expected.html @@ -0,0 +1,3 @@ + + +
          Just a dummy page.
          \ No newline at end of file diff --git a/test/server-side-rendering/samples/head-meta-hydrate-duplicate/main.svelte b/test/server-side-rendering/samples/head-meta-hydrate-duplicate/main.svelte new file mode 100644 index 000000000000..1a8b125dd2cf --- /dev/null +++ b/test/server-side-rendering/samples/head-meta-hydrate-duplicate/main.svelte @@ -0,0 +1,8 @@ + + Some Title + + + + + +
          Just a dummy page.
          \ No newline at end of file diff --git a/test/server-side-rendering/samples/head-multiple-title/A.svelte b/test/server-side-rendering/samples/head-multiple-title/A.svelte new file mode 100644 index 000000000000..b139b4ff7751 --- /dev/null +++ b/test/server-side-rendering/samples/head-multiple-title/A.svelte @@ -0,0 +1,3 @@ + + A + diff --git a/test/server-side-rendering/samples/head-multiple-title/B.svelte b/test/server-side-rendering/samples/head-multiple-title/B.svelte new file mode 100644 index 000000000000..4a29ecb04cbc --- /dev/null +++ b/test/server-side-rendering/samples/head-multiple-title/B.svelte @@ -0,0 +1,3 @@ + + B + diff --git a/test/server-side-rendering/samples/head-multiple-title/_expected-head.html b/test/server-side-rendering/samples/head-multiple-title/_expected-head.html new file mode 100644 index 000000000000..af5c5feba460 --- /dev/null +++ b/test/server-side-rendering/samples/head-multiple-title/_expected-head.html @@ -0,0 +1 @@ +B \ No newline at end of file diff --git a/test/server-side-rendering/samples/head-multiple-title/_expected.html b/test/server-side-rendering/samples/head-multiple-title/_expected.html new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test/server-side-rendering/samples/head-multiple-title/data.json b/test/server-side-rendering/samples/head-multiple-title/data.json new file mode 100644 index 000000000000..eab238e81696 --- /dev/null +++ b/test/server-side-rendering/samples/head-multiple-title/data.json @@ -0,0 +1,3 @@ +{ + "adjective": "custom" +} \ No newline at end of file diff --git a/test/server-side-rendering/samples/head-multiple-title/main.svelte b/test/server-side-rendering/samples/head-multiple-title/main.svelte new file mode 100644 index 000000000000..fb9a70b923dc --- /dev/null +++ b/test/server-side-rendering/samples/head-multiple-title/main.svelte @@ -0,0 +1,10 @@ + + + + Main + + + diff --git a/test/server-side-rendering/samples/spread-attributes-white-space/_expected.html b/test/server-side-rendering/samples/spread-attributes-white-space/_expected.html new file mode 100644 index 000000000000..a73bb17e8cb3 --- /dev/null +++ b/test/server-side-rendering/samples/spread-attributes-white-space/_expected.html @@ -0,0 +1,8 @@ + + + \ No newline at end of file diff --git a/test/server-side-rendering/samples/spread-attributes-white-space/main.svelte b/test/server-side-rendering/samples/spread-attributes-white-space/main.svelte new file mode 100644 index 000000000000..6919d9ea54cc --- /dev/null +++ b/test/server-side-rendering/samples/spread-attributes-white-space/main.svelte @@ -0,0 +1,12 @@ + + + + + diff --git a/test/store/index.js b/test/store/index.js index a39fab86e6e7..2af4a6f35d85 100644 --- a/test/store/index.js +++ b/test/store/index.js @@ -116,6 +116,15 @@ describe('store', () => { }); }); + const fake_observable = { + subscribe(fn) { + fn(42); + return { + unsubscribe: () => {} + }; + } + }; + describe('derived', () => { it('maps a single store', () => { const a = writable(1); @@ -346,6 +355,11 @@ describe('store', () => { b.set(2); assert.deepEqual(get(c), 'two 2'); }); + + it('works with RxJS-style observables', () => { + const d = derived(fake_observable, _ => _); + assert.equal(get(d), 42); + }); }); describe('get', () => { @@ -355,16 +369,7 @@ describe('store', () => { }); it('works with RxJS-style observables', () => { - const observable = { - subscribe(fn) { - fn(42); - return { - unsubscribe: () => {} - }; - } - }; - - assert.equal(get(observable), 42); + assert.equal(get(fake_observable), 42); }); }); }); diff --git a/test/validator/index.js b/test/validator/index.js index 9f991df4f207..9bce5e149b4a 100644 --- a/test/validator/index.js +++ b/test/validator/index.js @@ -20,6 +20,7 @@ describe("validate", () => { const input = fs.readFileSync(`${__dirname}/samples/${dir}/input.svelte`, "utf-8").replace(/\s+$/, ""); const expected_warnings = tryToLoadJson(`${__dirname}/samples/${dir}/warnings.json`) || []; const expected_errors = tryToLoadJson(`${__dirname}/samples/${dir}/errors.json`); + const options = tryToLoadJson(`${__dirname}/samples/${dir}/options.json`); let error; @@ -27,7 +28,9 @@ describe("validate", () => { const { warnings } = svelte.compile(input, { dev: config.dev, legacy: config.legacy, - generate: false + generate: false, + customElement: config.customElement, + ...options, }); assert.deepEqual(warnings.map(w => ({ diff --git a/test/validator/samples/binding-await-catch/errors.json b/test/validator/samples/binding-await-catch/errors.json new file mode 100644 index 000000000000..00141686f385 --- /dev/null +++ b/test/validator/samples/binding-await-catch/errors.json @@ -0,0 +1,9 @@ +[ + { + "code": "invalid-binding", + "message": "Cannot bind to a variable declared with {#await ... then} or {:catch} blocks", + "pos": 79, + "start": { "line": 6, "column": 9, "character": 79 }, + "end": { "line": 6, "column": 27, "character": 97 } + } +] diff --git a/test/validator/samples/binding-await-catch/input.svelte b/test/validator/samples/binding-await-catch/input.svelte new file mode 100644 index 000000000000..b640f6305bdd --- /dev/null +++ b/test/validator/samples/binding-await-catch/input.svelte @@ -0,0 +1,7 @@ + +{#await promise} +{:catch error} + +{/await} diff --git a/test/validator/samples/binding-await-then-2/errors.json b/test/validator/samples/binding-await-then-2/errors.json new file mode 100644 index 000000000000..e734ed4717f7 --- /dev/null +++ b/test/validator/samples/binding-await-then-2/errors.json @@ -0,0 +1,9 @@ +[ + { + "code": "invalid-binding", + "message": "Cannot bind to a variable declared with {#await ... then} or {:catch} blocks", + "pos": 78, + "start": { "line": 6, "column": 9, "character": 78 }, + "end": { "line": 6, "column": 19, "character": 88 } + } +] diff --git a/test/validator/samples/binding-await-then-2/input.svelte b/test/validator/samples/binding-await-then-2/input.svelte new file mode 100644 index 000000000000..e8c56c8e0b2c --- /dev/null +++ b/test/validator/samples/binding-await-then-2/input.svelte @@ -0,0 +1,7 @@ + +{#await promise} +{:then value} + +{/await} diff --git a/test/validator/samples/binding-await-then/errors.json b/test/validator/samples/binding-await-then/errors.json new file mode 100644 index 000000000000..a611e7731f19 --- /dev/null +++ b/test/validator/samples/binding-await-then/errors.json @@ -0,0 +1,9 @@ +[ + { + "code": "invalid-binding", + "message": "Cannot bind to a variable declared with {#await ... then} or {:catch} blocks", + "pos": 75, + "start": { "line": 5, "column": 9, "character": 75 }, + "end": { "line": 5, "column": 19, "character": 85 } + } +] diff --git a/test/validator/samples/binding-await-then/input.svelte b/test/validator/samples/binding-await-then/input.svelte new file mode 100644 index 000000000000..bc55ef97e464 --- /dev/null +++ b/test/validator/samples/binding-await-then/input.svelte @@ -0,0 +1,6 @@ + +{#await promise then value} + +{/await} diff --git a/test/validator/samples/component-dynamic/input.svelte b/test/validator/samples/component-dynamic/input.svelte new file mode 100644 index 000000000000..f591a84fe14c --- /dev/null +++ b/test/validator/samples/component-dynamic/input.svelte @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/test/validator/samples/component-dynamic/options.json b/test/validator/samples/component-dynamic/options.json new file mode 100644 index 000000000000..3a50892ebab1 --- /dev/null +++ b/test/validator/samples/component-dynamic/options.json @@ -0,0 +1,3 @@ +{ + "generate": true +} \ No newline at end of file diff --git a/test/validator/samples/component-dynamic/warnings.json b/test/validator/samples/component-dynamic/warnings.json new file mode 100644 index 000000000000..457ef11a1ed7 --- /dev/null +++ b/test/validator/samples/component-dynamic/warnings.json @@ -0,0 +1,47 @@ +[ + { + "code": "reactive-component", + "message": " will not be reactive if Let changes. Use if you want this reactivity.", + "pos": 190, + "end": { + "character": 197, + "column": 7, + "line": 15 + }, + "start": { + "character": 190, + "column": 0, + "line": 15 + } + }, + { + "message": " will not be reactive if ExportLet changes. Use if you want this reactivity.", + "code": "reactive-component", + "pos": 198, + "end": { + "character": 211, + "column": 13, + "line": 16 + }, + "start": { + "character": 198, + "column": 0, + "line": 16 + } + }, + { + "message": " will not be reactive if Reactive changes. Use if you want this reactivity.", + "code": "reactive-component", + "pos": 212, + "end": { + "character": 224, + "column": 12, + "line": 17 + }, + "start": { + "character": 212, + "column": 0, + "line": 17 + } + } +] diff --git a/test/validator/samples/each-block-invalid-context-destructured-object/errors.json b/test/validator/samples/each-block-invalid-context-destructured-object/errors.json new file mode 100644 index 000000000000..085021ff5ac0 --- /dev/null +++ b/test/validator/samples/each-block-invalid-context-destructured-object/errors.json @@ -0,0 +1,15 @@ +[{ + "code": "unexpected-reserved-word", + "message": "'case' is a reserved word in JavaScript and cannot be used here", + "start": { + "line": 1, + "column": 18, + "character": 18 + }, + "end": { + "line": 1, + "column": 18, + "character": 18 + }, + "pos": 18 +}] diff --git a/test/validator/samples/each-block-invalid-context-destructured-object/input.svelte b/test/validator/samples/each-block-invalid-context-destructured-object/input.svelte new file mode 100644 index 000000000000..a891f131a098 --- /dev/null +++ b/test/validator/samples/each-block-invalid-context-destructured-object/input.svelte @@ -0,0 +1,3 @@ +{#each cases as { case }} + {case.title} +{/each} diff --git a/test/validator/samples/tag-custom-element-options-missing/input.svelte b/test/validator/samples/tag-custom-element-options-missing/input.svelte new file mode 100644 index 000000000000..f5f5d7427059 --- /dev/null +++ b/test/validator/samples/tag-custom-element-options-missing/input.svelte @@ -0,0 +1 @@ + diff --git a/test/validator/samples/tag-custom-element-options-missing/warnings.json b/test/validator/samples/tag-custom-element-options-missing/warnings.json new file mode 100644 index 000000000000..185c6c317998 --- /dev/null +++ b/test/validator/samples/tag-custom-element-options-missing/warnings.json @@ -0,0 +1,15 @@ +[{ + "code": "missing-custom-element-compile-options", + "message": "The 'tag' option is used when generating a custom element. Did you forget the 'customElement: true' compile option?", + "start": { + "line": 1, + "column": 16, + "character": 16 + }, + "end": { + "line": 1, + "column": 36, + "character": 36 + }, + "pos": 16 +}] diff --git a/test/validator/samples/tag-custom-element-options-true/_config.js b/test/validator/samples/tag-custom-element-options-true/_config.js new file mode 100644 index 000000000000..ec3c350d4687 --- /dev/null +++ b/test/validator/samples/tag-custom-element-options-true/_config.js @@ -0,0 +1,3 @@ +export default { + customElement: true +}; diff --git a/test/validator/samples/tag-custom-element-options-true/input.svelte b/test/validator/samples/tag-custom-element-options-true/input.svelte new file mode 100644 index 000000000000..f5f5d7427059 --- /dev/null +++ b/test/validator/samples/tag-custom-element-options-true/input.svelte @@ -0,0 +1 @@ + diff --git a/test/validator/samples/unreferenced-variables/warnings.json b/test/validator/samples/unreferenced-variables/warnings.json index 7d9e0111bf08..dfac58ebdb13 100644 --- a/test/validator/samples/unreferenced-variables/warnings.json +++ b/test/validator/samples/unreferenced-variables/warnings.json @@ -6,7 +6,7 @@ "column": 12, "line": 8 }, - "message": "Component has unused export property 'd'. If it is for external reference only, please consider using `export const 'd'`", + "message": "Component has unused export property 'd'. If it is for external reference only, please consider using `export const d`", "pos": 102, "start": { "character": 102, @@ -21,7 +21,7 @@ "column": 15, "line": 8 }, - "message": "Component has unused export property 'e'. If it is for external reference only, please consider using `export const 'e'`", + "message": "Component has unused export property 'e'. If it is for external reference only, please consider using `export const e`", "pos": 105, "start": { "character": 105, @@ -36,7 +36,7 @@ "column": 18, "line": 9 }, - "message": "Component has unused export property 'g'. If it is for external reference only, please consider using `export const 'g'`", + "message": "Component has unused export property 'g'. If it is for external reference only, please consider using `export const g`", "pos": 125, "start": { "character": 125, @@ -51,7 +51,7 @@ "column": 18, "line": 10 }, - "message": "Component has unused export property 'h'. If it is for external reference only, please consider using `export const 'h'`", + "message": "Component has unused export property 'h'. If it is for external reference only, please consider using `export const h`", "pos": 145, "start": { "character": 145, @@ -66,7 +66,7 @@ "column": 25, "line": 12 }, - "message": "Component has unused export property 'j'. If it is for external reference only, please consider using `export const 'j'`", + "message": "Component has unused export property 'j'. If it is for external reference only, please consider using `export const j`", "pos": 187, "start": { "character": 187, diff --git a/test/vars/samples/modules-vars/_config.js b/test/vars/samples/modules-vars/_config.js new file mode 100644 index 000000000000..e178941db672 --- /dev/null +++ b/test/vars/samples/modules-vars/_config.js @@ -0,0 +1,72 @@ +export default { + test(assert, vars) { + assert.deepEqual(vars, [ + { + name: "a", + export_name: null, + injected: false, + module: true, + mutated: false, + reassigned: true, + referenced: false, + referenced_from_script: false, + writable: true + }, + { + name: "b", + export_name: null, + injected: false, + module: true, + mutated: true, + reassigned: false, + referenced: false, + referenced_from_script: false, + writable: true + }, + { + name: "c", + export_name: null, + injected: false, + module: true, + mutated: false, + reassigned: false, + referenced: false, + referenced_from_script: false, + writable: true + }, + { + name: "d", + export_name: null, + injected: false, + module: true, + mutated: false, + reassigned: false, + referenced: false, + referenced_from_script: false, + writable: true + }, + { + name: "c", + export_name: null, + injected: false, + module: false, + mutated: false, + reassigned: true, + referenced: false, + referenced_from_script: true, + writable: true + }, + { + name: "foo", + export_name: null, + injected: false, + module: false, + mutated: false, + reassigned: false, + referenced: false, + referenced_from_script: false, + writable: false + } + ]); + } +}; diff --git a/test/vars/samples/modules-vars/input.svelte b/test/vars/samples/modules-vars/input.svelte new file mode 100644 index 000000000000..8bbd5bdc5ea7 --- /dev/null +++ b/test/vars/samples/modules-vars/input.svelte @@ -0,0 +1,18 @@ + + \ No newline at end of file