diff --git a/.eslintignore b/.eslintignore index a0ca1e55c8..bfe7b1fa95 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,5 +1,6 @@ **/_actual.js **/expected.js +_output test/*/samples/*/output.js node_modules diff --git a/.eslintrc.js b/.eslintrc.js index c8ec8d1d01..946a157e40 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -36,7 +36,8 @@ module.exports = { } ], '@typescript-eslint/no-object-literal-type-assertion': 'off', - '@typescript-eslint/no-unused-vars': 'off' + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/prefer-interface': 'off' }, globals: { globalThis: false diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2488902b24..14824ecdfa 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 053f905294..7a14244929 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ node_modules /test/sourcemaps/samples/*/output.css.map /yarn-error.log _actual*.* +_output /types /site/cypress/screenshots/ @@ -32,5 +33,8 @@ _actual*.* /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/CHANGELOG.md b/CHANGELOG.md index a4ed0cf971..10e23686ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,103 @@ ## Unreleased +* Disallow attribute/prop names from matching two-way-bound names or `{shorthand}` attribute/prop names ([#4325](https://github.com/sveltejs/svelte/issues/4325)) + +## 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)) + +## 3.16.4 + +* Fix slots with props not propagating through to inner slots ([#4061](https://github.com/sveltejs/svelte/issues/4061)) +* Fix noting autosubscribed stores as `referenced` in `vars` for tooling ([#4081](https://github.com/sveltejs/svelte/issues/4081)) +* Fix cascading invalidations in certain situations ([#4094](https://github.com/sveltejs/svelte/issues/4094)) + +## 3.16.3 + +* Fix bitmask overflow when using slotted components ([#4077](https://github.com/sveltejs/svelte/issues/4077)) +* Remove unnecessary `$$invalidate` calls from init block ([#4018](https://github.com/sveltejs/svelte/issues/4018)) + +## 3.16.2 + +* Handle slot updates when parent component has a bitmask overflow ([#4078](https://github.com/sveltejs/svelte/pull/4078)) + +## 3.16.1 + +* Fix unused export warning for props used as stores ([#4021](https://github.com/sveltejs/svelte/issues/4021)) +* Fix `{:then}` without resolved value containing `{#each}` ([#4022](https://github.com/sveltejs/svelte/issues/4022)) +* Fix incorrect code generated with `loopGuardTimeout` ([#4034](https://github.com/sveltejs/svelte/issues/4034)) +* Fix handling of bitmask overflow and globals ([#4037](https://github.com/sveltejs/svelte/issues/4037)) +* Fix `{:then}` containing `{#if}` ([#4044](https://github.com/sveltejs/svelte/issues/4044)) +* Fix bare `import`s in `format: 'cjs'` output mode ([#4055](https://github.com/sveltejs/svelte/issues/4050)) +* Warn when using a known global as a component name ([#4070](https://github.com/sveltejs/svelte/issues/4070)) + +## 3.16.0 + * Use bitmasks to track changes ([#3945](https://github.com/sveltejs/svelte/pull/3945)) * Fix heisenbug with component styles ([#3977](https://github.com/sveltejs/svelte/issues/3977)) * Do not warn about missing expected props for `export function foo() {}` ([#3954](https://github.com/sveltejs/svelte/issues/3954)) * Fix `context="module"` exports with the same name as an instance variable ([#3983](https://github.com/sveltejs/svelte/issues/3983)) * Fix binding to contextual values from `{#each}` blocks referring to global variables ([#3992](https://github.com/sveltejs/svelte/issues/3992)) +* Use `requestAnimationFrame` callback argument for smoother transitions ([#4014](https://github.com/sveltejs/svelte/pull/4014)) +* Fix `listen_dev` argument order ([#4016](https://github.com/sveltejs/svelte/pull/4016)) ## 3.15.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9c2cb51034..f7df9770db 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ Svelte is a new way to build web applications. It's a compiler that takes your declarative components and converts them into efficient JavaScript that surgically updates the DOM. -The [Open Source Guides](https://opensource.guide/) website has a collection of resources for individuals, communities, and companies who want to learn how to run and contribute to an open source project. Contributors and people new to open source alike will find the following guides especially useful: +The [Open Source Guides](https://opensource.guide/) website has a collection of resources for individuals, communities, and companies. These resources help people who want to learn how to run and contribute to open source projects. Contributors and people new to open source alike will find the following guides especially useful: * [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) * [Building Welcoming Communities](https://opensource.guide/building-community/) @@ -30,7 +30,7 @@ One great way you can contribute to the project without writing any code is to h ## Bugs -We use [GitHub issues](https://github.com/sveltejs/svelte/issues) for our public bugs. If you would like to report a problem, take a look around and see if someone already opened an issue about it. If you a are certain this is a new, unreported bug, you can submit a [bug report](#reporting-new-issues). +We use [GitHub issues](https://github.com/sveltejs/svelte/issues) for our public bugs. If you would like to report a problem, take a look around and see if someone already opened an issue about it. If you are certain this is a new unreported bug, you can submit a [bug report](#reporting-new-issues). If you have questions about using Svelte, contact us on Discord at [svelte.dev/chat](https://svelte.dev/chat), and we will do our best to answer your questions. @@ -64,7 +64,7 @@ Working on your first Pull Request? You can learn how from this free video serie If you would like to request a new feature or enhancement but are not yet thinking about opening a pull request, you can also file an issue with [feature template](https://github.com/sveltejs/svelte/issues/new?template=feature_request.md). -If you're only fixing a bug, it's fine to submit a pull request right away but we still recommend to file an issue detailing what you're fixing. This is helpful in case we don't accept that specific fix but want to keep track of the issue. +If you're only fixing a bug, it's fine to submit a pull request right away but we still recommend that you file an issue detailing what you're fixing. This is helpful in case we don't accept that specific fix but want to keep track of the issue. ### Sending a pull request diff --git a/LICENSE b/LICENSE index b63fe48148..a8e26a756d 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 b5a0e895dc..e05154bd7c 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,8 @@ <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://travis-ci.org/sveltejs/svelte"> - <img src="https://api.travis-ci.org/sveltejs/svelte.svg?branch=master" + <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> diff --git a/package-lock.json b/package-lock.json index 4a45a6e5fd..2872c1b8dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "3.15.0", + "version": "3.18.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -30,16 +30,113 @@ "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 + } + } + }, "@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 +597,9 @@ "dev": true }, "code-red": { - "version": "0.0.26", - "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.26.tgz", - "integrity": "sha512-W4t68vk3xJjmkbuAKfEtaj7E+K82BtV+A4VjBlxHA6gDoSLc+sTB643JdJMSk27vpp5iEqHFuGnHieQGy/GmUQ==", + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.32.tgz", + "integrity": "sha512-mE+EZc2vJ4HxiejW5S2CvcVDKtopFEmrqAd9DTBDLCNjLgxekPP8wLi/ZiwDTwZwwW3dzeetaubLaMlIvkhVNw==", "dev": true, "requires": { "acorn": "^7.1.0", @@ -1496,9 +1593,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", @@ -3058,85 +3155,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==", - "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==", + "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": { - "@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 +3172,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" diff --git a/package.json b/package.json index 16bcfe825d..ff8b819668 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "3.15.0", + "version": "3.18.1", "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.26", + "code-red": "0.0.32", "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/rollup.config.js b/rollup.config.js index c55cbf2426..6f3d893a33 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 c2a65122d9..0261a69521 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 4c432dc6c9..6fd08fd8ee 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/2017-12-31-sapper-towards-the-ideal-web-app-framework.md b/site/content/blog/2017-12-31-sapper-towards-the-ideal-web-app-framework.md index 8799fdacce..cca200e966 100644 --- a/site/content/blog/2017-12-31-sapper-towards-the-ideal-web-app-framework.md +++ b/site/content/blog/2017-12-31-sapper-towards-the-ideal-web-app-framework.md @@ -53,7 +53,7 @@ What happens if we use the new model as a starting point? The same 'hello world' app that took 204kb with React and Next weighs just 7kb with Sapper. That number is likely to fall further in the future as we explore the space of optimisation possibilities, such as not shipping any JavaScript *at all* for pages that aren't interactive, beyond the tiny Sapper runtime that handles client-side routing. -What about a more 'real world' example? Conveniently, the [RealWorld](https://github.com/gothinkster/realworld) project, which challenges frameworks to develop an implementation of a Medium clone, gives us a way to find out. The [Sapper implementation](http://svelte-realworld.now.sh/) takes 39.6kb (11.8kb zipped) to render an interactive homepage. +What about a more 'real world' example? Conveniently, the [RealWorld](https://github.com/gothinkster/realworld) project, which challenges frameworks to develop an implementation of a Medium clone, gives us a way to find out. The [Sapper implementation](https://github.com/sveltejs/realworld) takes 39.6kb (11.8kb zipped) to render an interactive homepage. <aside><p>Code-splitting isn't free — if the reference implementation used code-splitting, it would be larger still</p></aside> 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 7a107c590b..b80223d820 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-20-write-less-code.md b/site/content/blog/2019-04-20-write-less-code.md index d6c8b77193..d56c5312e8 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 2456b85f9c..15fdffbde2 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 3d349af51d..026a2da5b3 100644 --- a/site/content/docs/01-component-format.md +++ b/site/content/docs/01-component-format.md @@ -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 89506753d6..0a4ca2ee1a 100644 --- a/site/content/docs/02-template-syntax.md +++ b/site/content/docs/02-template-syntax.md @@ -205,6 +205,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: @@ -1016,7 +1018,7 @@ DOMRect { ​top: number, width: number, x: number, - y:number + y: number } ``` @@ -1202,14 +1204,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> ``` diff --git a/site/content/docs/03-run-time.md b/site/content/docs/03-run-time.md index 14093b5264..c75ec694d9 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 e9126ccf13..c46cef117d 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. diff --git a/site/content/tutorial/02-reactivity/02-reactive-declarations/text.md b/site/content/tutorial/02-reactivity/02-reactive-declarations/text.md index 365908cf22..027a91a44a 100644 --- a/site/content/tutorial/02-reactivity/02-reactive-declarations/text.md +++ b/site/content/tutorial/02-reactivity/02-reactive-declarations/text.md @@ -11,7 +11,7 @@ let count = 0; $: doubled = count * 2; ``` -> Don't worry if this looks a little alien. It's valid (if unconventional) JavaScript, which Svelte interprets to mean 're-run this code whenever any of the referenced values change'. Once you get used to it, there's no going back. +> Don't worry if this looks a little alien. It's [valid](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label) (if unconventional) JavaScript, which Svelte interprets to mean 're-run this code whenever any of the referenced values change'. Once you get used to it, there's no going back. Let's use `doubled` in our markup: @@ -19,4 +19,4 @@ Let's use `doubled` in our markup: <p>{count} doubled is {doubled}</p> ``` -Of course, you could just write `{count * 2}` in the markup instead — you don't have to use reactive values. Reactive values become particularly valuable when you need to reference them multiple times, or you have values that depend on *other* reactive values. \ No newline at end of file +Of course, you could just write `{count * 2}` in the markup instead — you don't have to use reactive values. Reactive values become particularly valuable when you need to reference them multiple times, or you have values that depend on *other* reactive values. diff --git a/site/content/tutorial/12-actions/01-actions/text.md b/site/content/tutorial/12-actions/01-actions/text.md index 38de8f9a65..3706b31e7c 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 d841808a2a..a94d264217 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 0000000000..131a162359 --- /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 0000000000..74eb3fa50f --- /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 505b35e8f0..0000000000 --- a/site/src/routes/_components/WhosUsingSvelte.svelte +++ /dev/null @@ -1,90 +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://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://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://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://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 6f96731af0..92fc5ce96d 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 f89a9741ae..d5a8b7240f 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 cbbdf43e95..73fbffbc6a 100644 --- a/site/src/routes/index.svelte +++ b/site/src/routes/index.svelte @@ -1,9 +1,9 @@ + +

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 c6a8a8c95d..80c0591a4d 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 0000000000..3e5b375f0a --- /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 0000000000..10cf2c8b9a --- /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 0000000000..3e5b375f0a --- /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 0000000000..107753cdd0 --- /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 0000000000..482efd564d --- /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 0000000000..1a8b125dd2 --- /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 6c3a2a5b0b..ead6d90e06 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 78fc4855c6..22d9cd939c 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 8285646481..e129e66d71 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 d4f148cac9..7d66145f0a 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 cf30686662..db0e7cb007 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 6c639d9207..a314b0cff3 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/component-static-var/expected.js b/test/js/samples/component-static-var/expected.js index e01402b6d4..a65d9186a7 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-access-invalidate/expected.js b/test/js/samples/component-store-access-invalidate/expected.js index 151bd6ed0e..4c7bfd7009 100644 --- a/test/js/samples/component-store-access-invalidate/expected.js +++ b/test/js/samples/component-store-access-invalidate/expected.js @@ -43,7 +43,7 @@ function instance($$self, $$props, $$invalidate) { let $foo; const foo = writable(0); component_subscribe($$self, foo, value => $$invalidate(0, $foo = value)); - return [$foo]; + return [$foo, foo]; } class Component extends SvelteComponent { diff --git a/test/js/samples/component-store-reassign-invalidate/expected.js b/test/js/samples/component-store-reassign-invalidate/expected.js index 02a74cf22e..771b20dec4 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 5821faadf1..358363c661 100644 --- a/test/js/samples/debug-empty/expected.js +++ b/test/js/samples/debug-empty/expected.js @@ -103,7 +103,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 a1d6dba3b3..fc65c59eda 100644 --- a/test/js/samples/debug-foo-bar-baz-things/expected.js +++ b/test/js/samples/debug-foo-bar-baz-things/expected.js @@ -210,7 +210,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 af79667cc2..710d6b2232 100644 --- a/test/js/samples/debug-foo/expected.js +++ b/test/js/samples/debug-foo/expected.js @@ -198,7 +198,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/dev-warning-missing-data-computed/expected.js b/test/js/samples/dev-warning-missing-data-computed/expected.js index beb794a50c..cc16de67e6 100644 --- a/test/js/samples/dev-warning-missing-data-computed/expected.js +++ b/test/js/samples/dev-warning-missing-data-computed/expected.js @@ -107,7 +107,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 98f638dfcf..f5f6d07812 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/event-handler-dynamic/expected.js b/test/js/samples/event-handler-dynamic/expected.js index 34c33151bf..16b4a3f626 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 6f04e67808..c519fac668 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 3f324bb76d..c12c3523a0 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 c3e46f0c79..2a2254fbd7 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 8ff2b2798b..d588f0bf73 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 5a074d9754..12dfd3e90e 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 0000000000..21c7bfc83b --- /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 0000000000..476458a195 --- /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 344976ade6..fefe867e14 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 4127a6d7d6..7634481a2d 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-main-block/expected.js b/test/js/samples/instrumentation-script-main-block/expected.js new file mode 100644 index 0000000000..bc80924602 --- /dev/null +++ b/test/js/samples/instrumentation-script-main-block/expected.js @@ -0,0 +1,75 @@ +/* generated by Svelte vX.Y.Z */ +import { + SvelteComponent, + append, + detach, + element, + init, + insert, + noop, + safe_not_equal, + set_data, + text +} from "svelte/internal"; + +function create_fragment(ctx) { + let p; + let t0; + let t1; + + return { + c() { + p = element("p"); + t0 = text("x: "); + t1 = text(/*x*/ ctx[0]); + }, + m(target, anchor) { + insert(target, p, anchor); + append(p, t0); + append(p, t1); + }, + p(ctx, [dirty]) { + if (dirty & /*x*/ 1) set_data(t1, /*x*/ ctx[0]); + }, + i: noop, + o: noop, + d(detaching) { + if (detaching) detach(p); + } + }; +} + +function instance($$self, $$props, $$invalidate) { + let x = 0; + let y = 1; + x += 1; + + { + x += 2; + } + + setTimeout( + function foo() { + $$invalidate(0, x += 10); + $$invalidate(1, y += 20); + }, + 1000 + ); + + $$self.$$.update = () => { + if ($$self.$$.dirty & /*x, y*/ 3) { + $: $$invalidate(0, x += y); + } + }; + + return [x]; +} + +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/instrumentation-script-main-block/input.svelte b/test/js/samples/instrumentation-script-main-block/input.svelte new file mode 100644 index 0000000000..8c01783710 --- /dev/null +++ b/test/js/samples/instrumentation-script-main-block/input.svelte @@ -0,0 +1,19 @@ + + +

x: {x}

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 0d4493baf3..c154608cd5 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 0bd627eb87..77780baa99 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 e049a6d39b..4fe45616c7 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 093cccf63c..554ccf23b1 100644 --- a/test/js/samples/loop-protect/expected.js +++ b/test/js/samples/loop-protect/expected.js @@ -1,8 +1,13 @@ /* generated by Svelte vX.Y.Z */ import { SvelteComponentDev, + add_location, + binding_callbacks, + detach_dev, dispatch_dev, + element, init, + insert_dev, loop_guard, noop, safe_not_equal @@ -11,16 +16,27 @@ import { const file = undefined; function create_fragment(ctx) { + let div; + const block = { - c: noop, + c: function create() { + div = element("div"); + add_location(div, file, 22, 0, 288); + }, l: function claim(nodes) { throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); }, - m: noop, + m: function mount(target, anchor) { + insert_dev(target, div, anchor); + /*div_binding*/ ctx[1](div); + }, p: noop, i: noop, o: noop, - d: noop + d: function destroy(detaching) { + if (detaching) detach_dev(div); + /*div_binding*/ ctx[1](null); + } }; dispatch_dev("SvelteRegisterBlock", { @@ -34,62 +50,91 @@ function create_fragment(ctx) { return block; } -function instance($$self) { - const guard = loop_guard(100); +function foo() { + const guard = "foo"; + + { + const guard_1 = loop_guard(100); - while (true) { - foo(); - guard(); + while (true) { + console.log(guard); + guard_1(); + } } +} + +function instance($$self, $$props, $$invalidate) { + let node; - const guard_1 = loop_guard(100); + { + const guard = loop_guard(100); - for (; ; ) { - foo(); - guard_1(); + while (true) { + foo(); + guard(); + } } - const guard_2 = loop_guard(100); + { + const guard_2 = loop_guard(100); - while (true) { - foo(); - guard_2(); + for (; ; ) { + foo(); + guard_2(); + } } - const guard_4 = loop_guard(100); + { + const guard_3 = loop_guard(100); - do { - foo(); - guard_4(); - } while (true); + while (true) { + foo(); + guard_3(); + } + } + + { + const guard_5 = loop_guard(100); + + do { + foo(); + guard_5(); + } while (true); + } + + function div_binding($$value) { + binding_callbacks[$$value ? "unshift" : "push"](() => { + $$invalidate(0, node = $$value); + }); + } $$self.$capture_state = () => { return {}; }; $$self.$inject_state = $$props => { - + if ("node" in $$props) $$invalidate(0, node = $$props.node); }; $: { - const guard_3 = loop_guard(100); + const guard_4 = loop_guard(100); while (true) { foo(); - guard_3(); + guard_4(); } } $: { - const guard_5 = loop_guard(100); + const guard_6 = loop_guard(100); do { foo(); - guard_5(); + guard_6(); } while (true); } - return []; + return [node, div_binding]; } class Component extends SvelteComponentDev { diff --git a/test/js/samples/loop-protect/input.svelte b/test/js/samples/loop-protect/input.svelte index c39ea75f72..daac6ab1c4 100644 --- a/test/js/samples/loop-protect/input.svelte +++ b/test/js/samples/loop-protect/input.svelte @@ -1,4 +1,13 @@ \ No newline at end of file + + +
\ No newline at end of file diff --git a/test/js/samples/media-bindings/expected.js b/test/js/samples/media-bindings/expected.js index bfb1b8911d..52fef36792 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 276587eeca..803f06a882 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 e3d48f9922..c8cd1d84ce 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 8285646481..e129e66d71 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 f79212e25e..70c39eedd2 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/attribute-unique-binding-error/error.json b/test/parser/samples/attribute-unique-binding-error/error.json new file mode 100644 index 0000000000..dd14572149 --- /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 0000000000..78f854bad6 --- /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 0000000000..dd14572149 --- /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 0000000000..d486eab558 --- /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/script-comment-only/output.json b/test/parser/samples/script-comment-only/output.json index 3441d8a7bb..e090b30ae6 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 3c02b1fbde..be83eeea8b 100644 --- a/test/parser/samples/script-comment-trailing-multiline/output.json +++ b/test/parser/samples/script-comment-trailing-multiline/output.json @@ -134,7 +134,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 beca001042..a2bc00bc00 100644 --- a/test/parser/samples/script-comment-trailing/output.json +++ b/test/parser/samples/script-comment-trailing/output.json @@ -134,7 +134,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/runtime/index.js b/test/runtime/index.js index fc989d352f..f070eb8185 100644 --- a/test/runtime/index.js +++ b/test/runtime/index.js @@ -2,15 +2,18 @@ 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"; import { showOutput, loadConfig, loadSvelte, + cleanRequireCache, env, - setupHtmlEqual + setupHtmlEqual, + mkdirp } from "../helpers.js"; let svelte$; @@ -77,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; @@ -90,6 +89,33 @@ describe("runtime", () => { const window = env(); + glob('**/*.svelte', { cwd }).forEach(file => { + if (file[0] === '_') return; + + const dir = `${cwd}/_output/${hydrate ? 'hydratable' : 'normal'}`; + 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 + } + }); + return Promise.resolve() .then(() => { // hack to support transition tests @@ -107,7 +133,7 @@ describe("runtime", () => { set_raf(cb => { raf.callback = () => { raf.callback = null; - cb(); + cb(raf.time); flush(); }; }); @@ -195,7 +221,7 @@ describe("runtime", () => { } else { throw err; } - }).catch(err => { + }).catch(err => { failed.add(dir); showOutput(cwd, compileOptions, compile); // eslint-disable-line no-console throw err; 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 0000000000..0806d0fa90 --- /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 0000000000..a53ce81de0 --- /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 0000000000..a74ce41cb6 --- /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 0000000000..e91c4b6a14 --- /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 0000000000..e5e8980ed1 --- /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 0000000000..be652c7b79 --- /dev/null +++ b/test/runtime/samples/apply-directives-in-order/main.svelte @@ -0,0 +1,10 @@ + + + +

{value}

diff --git a/test/runtime/samples/await-then-if/_config.js b/test/runtime/samples/await-then-if/_config.js new file mode 100644 index 0000000000..b26688d9f3 --- /dev/null +++ b/test/runtime/samples/await-then-if/_config.js @@ -0,0 +1,25 @@ +let fulfil; + +const thePromise = new Promise(f => { + fulfil = f; +}); + +export default { + props: { + thePromise + }, + + html: ` + loading... + `, + + async test({ assert, component, target }) { + fulfil([]); + + await thePromise; + + assert.htmlEqual(target.innerHTML, ` +

promise array is empty

+ `); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/await-then-if/main.svelte b/test/runtime/samples/await-then-if/main.svelte new file mode 100644 index 0000000000..d292067b30 --- /dev/null +++ b/test/runtime/samples/await-then-if/main.svelte @@ -0,0 +1,13 @@ + + +{#await thePromise} + loading... +{:then r} + {#if r.length < 1} +

promise array is empty

+ {:else} +

promise array is not empty

+ {/if} +{/await} \ No newline at end of file diff --git a/test/runtime/samples/await-then-no-context/main.svelte b/test/runtime/samples/await-then-no-context/main.svelte new file mode 100644 index 0000000000..c729512149 --- /dev/null +++ b/test/runtime/samples/await-then-no-context/main.svelte @@ -0,0 +1,12 @@ + + +{#await promise} +
waiting
+{:then} + {#each test as t} +
t
+ {/each} +{/await} diff --git a/test/runtime/samples/bitmask-overflow-2/_config.js b/test/runtime/samples/bitmask-overflow-2/_config.js new file mode 100644 index 0000000000..0b63791292 --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-2/_config.js @@ -0,0 +1,3 @@ +export default { + error: `potato is not defined`, +}; \ No newline at end of file diff --git a/test/runtime/samples/bitmask-overflow-2/main.svelte b/test/runtime/samples/bitmask-overflow-2/main.svelte new file mode 100644 index 0000000000..10fa1bd5e2 --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-2/main.svelte @@ -0,0 +1,35 @@ + +

{x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20 + x21 + x22 + x23 + x24 + x25 + x26 + x27 + x28 + x29 + x30 + x31 + x32}

\ No newline at end of file diff --git a/test/runtime/samples/bitmask-overflow-3/_config.js b/test/runtime/samples/bitmask-overflow-3/_config.js new file mode 100644 index 0000000000..aee7d3237e --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-3/_config.js @@ -0,0 +1,3 @@ +export default { + error: `A is not defined`, +}; \ No newline at end of file diff --git a/test/runtime/samples/bitmask-overflow-3/main.svelte b/test/runtime/samples/bitmask-overflow-3/main.svelte new file mode 100644 index 0000000000..aa2c56a147 --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-3/main.svelte @@ -0,0 +1,4 @@ + +foo diff --git a/test/runtime/samples/bitmask-overflow-slot-2/Echo.svelte b/test/runtime/samples/bitmask-overflow-slot-2/Echo.svelte new file mode 100644 index 0000000000..c8905184dc --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-slot-2/Echo.svelte @@ -0,0 +1,73 @@ + + +

{d1}

+

{d2}

+

{d3}

+

{d4}

+

{d5}

+

{d6}

+

{d7}

+

{d8}

+

{d9}

+

{d10}

+

{d11}

+

{d12}

+

{d13}

+

{d14}

+

{d15}

+

{d16}

+

{d17}

+

{d18}

+

{d19}

+

{d20}

+

{d21}

+

{d22}

+

{d23}

+

{d24}

+

{d25}

+

{d26}

+

{d27}

+

{d28}

+

{d29}

+

{d30}

+

{d31}

+

{d32}

+

{d33}

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

d1

+

d2

+

d3

+

d4

+

d5

+

d6

+

d7

+

d8

+

d9

+

d10

+

d11

+

d12

+

d13

+

d14

+

d15

+

d16

+

d17

+

d18

+

d19

+

d20

+

d21

+

d22

+

d23

+

d24

+

d25

+

d26

+

d27

+

d28

+

d29

+

d30

+

d31

+

2

+

1

+

0:1

+

2:1

+

0

+

1

+

2

+ `, + + test({ assert, component, target }) { + component.reads = {}; + + component._0 = 'a'; + component._1 = 'b'; + component._2 = 'c'; + + assert.htmlEqual(target.innerHTML, ` +

d1

+

d2

+

d3

+

d4

+

d5

+

d6

+

d7

+

d8

+

d9

+

d10

+

d11

+

d12

+

d13

+

d14

+

d15

+

d16

+

d17

+

d18

+

d19

+

d20

+

d21

+

d22

+

d23

+

d24

+

d25

+

d26

+

d27

+

d28

+

d29

+

d30

+

d31

+

c

+

b

+

a:b

+

c:b

+

a

+

b

+

c

+ `); + + assert.deepEqual(component.reads, { + _0: 2, + _1: 2, + }); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/bitmask-overflow-slot-2/main.svelte b/test/runtime/samples/bitmask-overflow-slot-2/main.svelte new file mode 100644 index 0000000000..c15b4d5322 --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-slot-2/main.svelte @@ -0,0 +1,30 @@ + + + +

{bar}

+

{dummy}

+

{_0}

+

{_1}

+

{_2}

+
\ No newline at end of file diff --git a/test/runtime/samples/bitmask-overflow-slot/Echo.svelte b/test/runtime/samples/bitmask-overflow-slot/Echo.svelte new file mode 100644 index 0000000000..28eaa54060 --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-slot/Echo.svelte @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/test/runtime/samples/bitmask-overflow-slot/_config.js b/test/runtime/samples/bitmask-overflow-slot/_config.js new file mode 100644 index 0000000000..9b24d5541f --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-slot/_config.js @@ -0,0 +1,124 @@ +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

+

5:36

+

6:37

+

38

+

0

+ `, + + test({ assert, component, target }) { + component.reads = {}; + + component._0 = 'a'; + component._30 = 'b'; + component._31 = 'c'; + component._32 = 'd'; + component._40 = 'e'; + + component._5 = 'f'; + component._6 = 'g'; + component._36 = 'h'; + component._37 = 'i'; + + assert.htmlEqual(target.innerHTML, ` +

a

+

1

+

2

+

3

+

4

+

f

+

g

+

7

+

8

+

9

+

10

+

11

+

12

+

13

+

14

+

15

+

16

+

17

+

18

+

19

+

20

+

21

+

22

+

23

+

24

+

25

+

26

+

27

+

28

+

29

+

b

+

c

+

d

+

33

+

34

+

35

+

h

+

i

+

38

+

39

+

e

+

f:h

+

g:i

+

38

+

a

+ `); + + assert.deepEqual(component.reads, { + _0: 1, + _5: 3, + _6: 3, + _30: 1, + _31: 1, + _32: 1, + _36: 3, + _37: 3, + _40: 1 + }); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/bitmask-overflow-slot/main.svelte b/test/runtime/samples/bitmask-overflow-slot/main.svelte new file mode 100644 index 0000000000..89e60ce4b9 --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-slot/main.svelte @@ -0,0 +1,107 @@ + + + +

{read(_0, '_0')}

+

{read(_1, '_1')}

+

{read(_2, '_2')}

+

{read(_3, '_3')}

+

{read(_4, '_4')}

+

{read(_5, '_5')}

+

{read(_6, '_6')}

+

{read(_7, '_7')}

+

{read(_8, '_8')}

+

{read(_9, '_9')}

+

{read(_10, '_10')}

+

{read(_11, '_11')}

+

{read(_12, '_12')}

+

{read(_13, '_13')}

+

{read(_14, '_14')}

+

{read(_15, '_15')}

+

{read(_16, '_16')}

+

{read(_17, '_17')}

+

{read(_18, '_18')}

+

{read(_19, '_19')}

+

{read(_20, '_20')}

+

{read(_21, '_21')}

+

{read(_22, '_22')}

+

{read(_23, '_23')}

+

{read(_24, '_24')}

+

{read(_25, '_25')}

+

{read(_26, '_26')}

+

{read(_27, '_27')}

+

{read(_28, '_28')}

+

{read(_29, '_29')}

+

{read(_30, '_30')}

+

{read(_31, '_31')}

+

{read(_32, '_32')}

+

{read(_33, '_33')}

+

{read(_34, '_34')}

+

{read(_35, '_35')}

+

{read(_36, '_36')}

+

{read(_37, '_37')}

+

{read(_38, '_38')}

+

{read(_39, '_39')}

+

{read(_40, '_40')}

+ +

{read(_5, '_5') + ':' + read(_36, '_36')}

+

{foo}

+

{bar}

+ +

{dummy}

+
\ No newline at end of file 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 0000000000..5dfe32bc7f --- /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 0000000000..38b04b7b5e --- /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 0000000000..215a1390d9 --- /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 0000000000..4f4ac95014 --- /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 0000000000..aaa9895ea8 --- /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 0000000000..e7d4890e6b --- /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-let-in-slot/Inner.svelte b/test/runtime/samples/component-slot-let-in-slot/Inner.svelte new file mode 100644 index 0000000000..d0ea817d54 --- /dev/null +++ b/test/runtime/samples/component-slot-let-in-slot/Inner.svelte @@ -0,0 +1 @@ + diff --git a/test/runtime/samples/component-slot-let-in-slot/Outer.svelte b/test/runtime/samples/component-slot-let-in-slot/Outer.svelte new file mode 100644 index 0000000000..590a70564a --- /dev/null +++ b/test/runtime/samples/component-slot-let-in-slot/Outer.svelte @@ -0,0 +1,5 @@ + + + diff --git a/test/runtime/samples/component-slot-let-in-slot/_config.js b/test/runtime/samples/component-slot-let-in-slot/_config.js new file mode 100644 index 0000000000..a86d869581 --- /dev/null +++ b/test/runtime/samples/component-slot-let-in-slot/_config.js @@ -0,0 +1,12 @@ +export default { + props: { + prop: 'a', + }, + + html: 'a', + + test({ assert, component, target }) { + component.prop = 'b'; + assert.htmlEqual( target.innerHTML, 'b' ); + } +}; diff --git a/test/runtime/samples/component-slot-let-in-slot/main.svelte b/test/runtime/samples/component-slot-let-in-slot/main.svelte new file mode 100644 index 0000000000..7ebb4ebc21 --- /dev/null +++ b/test/runtime/samples/component-slot-let-in-slot/main.svelte @@ -0,0 +1,10 @@ + + + + {value} + 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 0000000000..d9034e4be2 --- /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 0000000000..fd8f22db00 --- /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 0000000000..89dfd006cc --- /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 0000000000..727927b157 --- /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/each-block-recursive-with-function-condition/_config.js b/test/runtime/samples/each-block-recursive-with-function-condition/_config.js new file mode 100644 index 0000000000..0795576bae --- /dev/null +++ b/test/runtime/samples/each-block-recursive-with-function-condition/_config.js @@ -0,0 +1,8 @@ +export default { + html: ` +

OK

+

OK

+
one
+
two
+ ` +}; diff --git a/test/runtime/samples/each-block-recursive-with-function-condition/main.svelte b/test/runtime/samples/each-block-recursive-with-function-condition/main.svelte new file mode 100644 index 0000000000..9b62c03cf6 --- /dev/null +++ b/test/runtime/samples/each-block-recursive-with-function-condition/main.svelte @@ -0,0 +1,13 @@ + + +{#each data as datum} + {#if datum.foo && a()} +

OK

+ + {:else} +
{datum.bar}
+ {/if} +{/each} 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 0000000000..948fc308c0 --- /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 0000000000..c832127c09 --- /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 0000000000..bb7d9befc4 --- /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 0000000000..e60e561524 --- /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 0000000000..c81af02006 --- /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 0000000000..ba1777f945 --- /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 0000000000..f4e8c5fdb7 --- /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 0000000000..41daf374c8 --- /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 0000000000..d363d708ba --- /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 0000000000..4fa032bf37 --- /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 0000000000..49d42f3305 --- /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 0000000000..6d7d29e482 --- /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 0000000000..b57d88ec02 --- /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 0000000000..8517429e5c --- /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 0000000000..bad7359927 --- /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 0000000000..cf17c61f60 --- /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 0000000000..2dbbe61ea6 --- /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 41cfd6e729..e60e561524 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 0000000000..4127034010 --- /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 0000000000..423a75d1f0 --- /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/if-block-component-store-function-conditionals/Widget.svelte b/test/runtime/samples/if-block-component-store-function-conditionals/Widget.svelte new file mode 100644 index 0000000000..a74ce95de5 --- /dev/null +++ b/test/runtime/samples/if-block-component-store-function-conditionals/Widget.svelte @@ -0,0 +1 @@ +

OK

\ No newline at end of file diff --git a/test/runtime/samples/if-block-component-store-function-conditionals/_config.js b/test/runtime/samples/if-block-component-store-function-conditionals/_config.js new file mode 100644 index 0000000000..db171f2fd1 --- /dev/null +++ b/test/runtime/samples/if-block-component-store-function-conditionals/_config.js @@ -0,0 +1,3 @@ +export default { + html: '

OK

', +}; diff --git a/test/runtime/samples/if-block-component-store-function-conditionals/main.svelte b/test/runtime/samples/if-block-component-store-function-conditionals/main.svelte new file mode 100644 index 0000000000..765654f0d2 --- /dev/null +++ b/test/runtime/samples/if-block-component-store-function-conditionals/main.svelte @@ -0,0 +1,12 @@ + + +{#if $a || b() } + +{:else} +
fail
+{/if} \ No newline at end of file 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 0000000000..8f46af9d52 --- /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 0000000000..870e7beaa1 --- /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 0000000000..ef16875b64 --- /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 0000000000..a76a2686ac --- /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 0000000000..1fa4263e39 --- /dev/null +++ b/test/runtime/samples/lifecycle-onmount-infinite-loop/main.svelte @@ -0,0 +1,16 @@ + + +
diff --git a/test/runtime/samples/loop-protect-inner-function/_config.js b/test/runtime/samples/loop-protect-inner-function/_config.js new file mode 100644 index 0000000000..862d4f4c0f --- /dev/null +++ b/test/runtime/samples/loop-protect-inner-function/_config.js @@ -0,0 +1,7 @@ +export default { + html: '
', + compileOptions: { + dev: true, + loopGuardTimeout: 100, + } +}; diff --git a/test/runtime/samples/loop-protect-inner-function/main.svelte b/test/runtime/samples/loop-protect-inner-function/main.svelte new file mode 100644 index 0000000000..cf5350efde --- /dev/null +++ b/test/runtime/samples/loop-protect-inner-function/main.svelte @@ -0,0 +1,7 @@ + +
\ No newline at end of file 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 0000000000..05a8159589 --- /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 0000000000..a631d4d9f8 --- /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 0000000000..5e3f15f5dc --- /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 0000000000..152e0e3e2e --- /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/store-auto-subscribe-event-callback/_config.js b/test/runtime/samples/store-auto-subscribe-event-callback/_config.js new file mode 100644 index 0000000000..747ed3e4ad --- /dev/null +++ b/test/runtime/samples/store-auto-subscribe-event-callback/_config.js @@ -0,0 +1,22 @@ +export default { + html: ` + + Dirty: false + Valid: false + `, + + async test({ assert, target, window }) { + const input = target.querySelector('input'); + + input.value = 'foo'; + const inputEvent = new window.InputEvent('input'); + + await input.dispatchEvent(inputEvent); + + assert.htmlEqual(target.innerHTML, ` + + Dirty: true + Valid: true + `); + }, +}; diff --git a/test/runtime/samples/store-auto-subscribe-event-callback/main.svelte b/test/runtime/samples/store-auto-subscribe-event-callback/main.svelte new file mode 100644 index 0000000000..eca7c202cd --- /dev/null +++ b/test/runtime/samples/store-auto-subscribe-event-callback/main.svelte @@ -0,0 +1,29 @@ + + + + +Dirty: {$validity.dirty} +Valid: {$validity.valid} 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 0000000000..52e21cef05 --- /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 0000000000..9c1ed4a560 --- /dev/null +++ b/test/runtime/samples/store-auto-subscribe-nullish/main.svelte @@ -0,0 +1,5 @@ + + +

{$store}

diff --git a/test/runtime/samples/store-invalidation-while-update-1/_config.js b/test/runtime/samples/store-invalidation-while-update-1/_config.js new file mode 100644 index 0000000000..d0361d2d23 --- /dev/null +++ b/test/runtime/samples/store-invalidation-while-update-1/_config.js @@ -0,0 +1,44 @@ +export default { + html: ` + +
+
simple
+ + `, + + async test({ assert, component, target, window }) { + const input = target.querySelector('input'); + const button = target.querySelector('button'); + + const inputEvent = new window.InputEvent('input'); + const clickEvent = new window.MouseEvent('click'); + + input.value = 'foo'; + await input.dispatchEvent(inputEvent); + + assert.htmlEqual(target.innerHTML, ` + +
foo
+
foo
+ + `); + + await button.dispatchEvent(clickEvent); + assert.htmlEqual(target.innerHTML, ` + +
foo
+
clicked
+ + `); + + input.value = 'bar'; + await input.dispatchEvent(inputEvent); + + assert.htmlEqual(target.innerHTML, ` + +
bar
+
bar
+ + `); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/store-invalidation-while-update-1/main.svelte b/test/runtime/samples/store-invalidation-while-update-1/main.svelte new file mode 100644 index 0000000000..f74808ee2e --- /dev/null +++ b/test/runtime/samples/store-invalidation-while-update-1/main.svelte @@ -0,0 +1,20 @@ + + + +
{v}
+
{$s}
+ diff --git a/test/runtime/samples/store-invalidation-while-update-2/_config.js b/test/runtime/samples/store-invalidation-while-update-2/_config.js new file mode 100644 index 0000000000..422034bc11 --- /dev/null +++ b/test/runtime/samples/store-invalidation-while-update-2/_config.js @@ -0,0 +1,44 @@ +export default { + html: ` +
+
simple
+ + + `, + + async test({ assert, component, target, window }) { + const input = target.querySelector('input'); + const button = target.querySelector('button'); + + const inputEvent = new window.InputEvent('input'); + const clickEvent = new window.MouseEvent('click'); + + input.value = 'foo'; + await input.dispatchEvent(inputEvent); + + assert.htmlEqual(target.innerHTML, ` +
foo
+
foo
+ + + `); + + await button.dispatchEvent(clickEvent); + assert.htmlEqual(target.innerHTML, ` +
foo
+
clicked
+ + + `); + + input.value = 'bar'; + await input.dispatchEvent(inputEvent); + + assert.htmlEqual(target.innerHTML, ` +
bar
+
bar
+ + + `); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/store-invalidation-while-update-2/main.svelte b/test/runtime/samples/store-invalidation-while-update-2/main.svelte new file mode 100644 index 0000000000..83e13742ce --- /dev/null +++ b/test/runtime/samples/store-invalidation-while-update-2/main.svelte @@ -0,0 +1,20 @@ + + +
{v}
+
{$s}
+ + 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 0000000000..283af0a2b0 --- /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 0000000000..df43d575a9 --- /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 768917e833..ee1319845d 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 0000000000..ae9b250f86 --- /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 0000000000..107753cdd0 --- /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 0000000000..a469e618fa --- /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 0000000000..1a8b125dd2 --- /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 0000000000..b139b4ff77 --- /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 0000000000..4a29ecb04c --- /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 0000000000..af5c5feba4 --- /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 0000000000..e69de29bb2 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 0000000000..eab238e816 --- /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 0000000000..fb9a70b923 --- /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 0000000000..a73bb17e8c --- /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 0000000000..6919d9ea54 --- /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 a39fab86e6..2af4a6f35d 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 9f991df4f2..8bf0400d7c 100644 --- a/test/validator/index.js +++ b/test/validator/index.js @@ -27,7 +27,8 @@ describe("validate", () => { const { warnings } = svelte.compile(input, { dev: config.dev, legacy: config.legacy, - generate: false + generate: false, + customElement: config.customElement }); 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 0000000000..00141686f3 --- /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 0000000000..b640f6305b --- /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 0000000000..e734ed4717 --- /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 0000000000..e8c56c8e0b --- /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 0000000000..a611e7731f --- /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 0000000000..bc55ef97e4 --- /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/missing-component-global/input.svelte b/test/validator/samples/missing-component-global/input.svelte new file mode 100644 index 0000000000..5d17448bd4 --- /dev/null +++ b/test/validator/samples/missing-component-global/input.svelte @@ -0,0 +1,3 @@ +
+ +
\ No newline at end of file diff --git a/test/validator/samples/missing-component-global/warnings.json b/test/validator/samples/missing-component-global/warnings.json new file mode 100644 index 0000000000..c9de56619a --- /dev/null +++ b/test/validator/samples/missing-component-global/warnings.json @@ -0,0 +1,15 @@ +[{ + "code": "missing-declaration", + "message": "'String' is not defined. Consider adding a +{$q} diff --git a/test/validator/samples/unreferenced-variables/warnings.json b/test/validator/samples/unreferenced-variables/warnings.json index 7d9e0111bf..dfac58ebdb 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/store-referenced/_config.js b/test/vars/samples/store-referenced/_config.js index cb92b67ea4..bac35d1dba 100644 --- a/test/vars/samples/store-referenced/_config.js +++ b/test/vars/samples/store-referenced/_config.js @@ -8,7 +8,7 @@ export default { module: false, mutated: false, reassigned: false, - referenced: false, + referenced: true, referenced_from_script: false, writable: true },