Merge branch 'master' into style-directives

pull/5923/head
Paul Murray 5 years ago committed by GitHub
commit 3e522aa98f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,25 +1,65 @@
# Svelte changelog
## Unreleased
## 3.41.0
* Expose `svelte/ssr` which exports lifecycle methods as no-ops ([#6416](https://github.com/sveltejs/svelte/pull/6416))
* Support `export { ... } from` syntax in components ([#2214](https://github.com/sveltejs/svelte/issues/2214))
* Support `export let { ... } =` syntax in components ([#5612](https://github.com/sveltejs/svelte/issues/5612))
* Support `{#await ... then/catch}` without a variable for the resolved/rejected value ([#6270](https://github.com/sveltejs/svelte/issues/6270))
## 3.40.3
* Fix `<slot>` data when a transition is cancelled before completing ([#5394](https://github.com/sveltejs/svelte/issues/5394))
* Fix destructuring into variables beginning with `$` so that they result in store updates ([#5653](https://github.com/sveltejs/svelte/issues/5653))
* Fix `in:` transition configuration not properly updating when it's changed after its initial creation ([#6505](https://github.com/sveltejs/svelte/issues/6505))
* Fix applying `:global()` for `>` selector combinator ([#6550](https://github.com/sveltejs/svelte/issues/6550))
* Fix mounting component at detached DOM node ([#6567](https://github.com/sveltejs/svelte/issues/6567))
## 3.40.2
* Fix dynamic `autofocus={...}` attribute handling ([#4995](https://github.com/sveltejs/svelte/issues/4995))
* Add filename to combined source map if needed ([#6089](https://github.com/sveltejs/svelte/pull/6089))
* In AST, parse empty attribute values as an empty string ([#6286](https://github.com/sveltejs/svelte/issues/6286))
* Fix tracking whether transition has started ([#6399](https://github.com/sveltejs/svelte/pull/6399))
* Fix incorrect scoping of `:global()` selectors ([#6550](https://github.com/sveltejs/svelte/issues/6550))
## 3.40.1
* Fix store reactivity regression when using reactive statements ([#6557](https://github.com/sveltejs/svelte/issues/6557))
## 3.40.0
* Support rendering a component in a shadow DOM ([#5869](https://github.com/sveltejs/svelte/issues/5869))
* Fix `:root` selector being erroneously scoped to component ([#4767](https://github.com/sveltejs/svelte/issues/4767))
* Fix `.end` in AST for expressions inside attributes ([#6258](https://github.com/sveltejs/svelte/issues/6258))
* Fix one-way `<select>` binding when it has a spread attribute ([#6433](https://github.com/sveltejs/svelte/issues/6433))
* Various hydration improvements and fixes ([#6449](https://github.com/sveltejs/svelte/pull/6449))
* Use smaller versions of internal helpers when compiling without hydration support ([#6462](https://github.com/sveltejs/svelte/issues/6462))
* Fix two-way binding of values when updating through synchronous component accessors ([#6502](https://github.com/sveltejs/svelte/issues/6502))
## 3.39.0
* Support `bind:group` in SSR ([#4621](https://github.com/sveltejs/svelte/pull/4621))
* Add a11y warning `a11y-mouse-events-have-key-events` which checks that `mouseover`/`mouseout` are accompanied by `focus`/`blur` event handlers ([#5938](https://github.com/sveltejs/svelte/pull/5938))
* Make it possible to silence more warnings ([#5954](https://github.com/sveltejs/svelte/issues/5954))
* Add `|trusted` event modifier ([#6137](https://github.com/sveltejs/svelte/issues/6137))
* Add `varsReport` compiler option to include all variables reference in the component in the `variables` report ([#6192](https://github.com/sveltejs/svelte/pull/6192))
* Throw compiler error when passing empty directive names ([#6299](https://github.com/sveltejs/svelte/issues/6299))
* Add `errorMode` compiler option to try to continue compiling when an error is detected ([#6194](https://github.com/sveltejs/svelte/pull/6194))
* Expose `svelte/ssr` which exports lifecycle methods as no-ops ([#6416](https://github.com/sveltejs/svelte/pull/6416))
* Add `getAllContexts` ([#6447](https://github.com/sveltejs/svelte/issues/6447))
* Throw proper error for `export default function() {}` and `export default class {}` rather than crashing the compiler ([#3275](https://github.com/sveltejs/svelte/issues/3275))
* Fix usage of falsy `input` values ([#6458](https://github.com/sveltejs/svelte/pull/6458))
* Fix ordering of elements in keyed `{#each}` ([#6445](https://github.com/sveltejs/svelte/pull/6445))
* Fix SSR rendering of falsy `input` values ([#4551](https://github.com/sveltejs/svelte/issues/4551))
* Fix `preserveComments` in SSR mode ([#4730](https://github.com/sveltejs/svelte/issues/4730))
* Fix compiler error when using `:where()` inside `:global()` ([#6434](https://github.com/sveltejs/svelte/issues/6434))
* Fix erroneous `unknown prop` warning when using slot on a component ([#6065](https://github.com/sveltejs/svelte/pull/6065))
* Fix `:global()` with pseudo element not being seen as global ([#6470](https://github.com/sveltejs/svelte/pull/6470))
* Allow `:global()` to contain multiple selectors when it is not part of a larger selector ([#6477](https://github.com/sveltejs/svelte/issues/6477))
* Add a11y warning `a11y-mouse-events-have-key-events` which checks that `mouseover`/`mouseout` are accompanied by `focus`/`blur` event handlers ([#5938](https://github.com/sveltejs/svelte/pull/5938))
* Remove deprecated a11y warning `a11y-no-onchange warning` ([#6457](https://github.com/sveltejs/svelte/issues/6457))
* Do not warn if `context="module"` variables are not the only dependencies in reactive statements ([#5954](https://github.com/sveltejs/svelte/issues/5954))
* Stop checking `a11y-media-has-caption` a11y warning on `<audio>` elements ([#6054](https://github.com/sveltejs/svelte/issues/6054))
* Fix erroneous "unknown prop" warning when using slot on a component ([#6065](https://github.com/sveltejs/svelte/pull/6065))
* Add sourcemaps to all HTML elements ([#6092](https://github.com/sveltejs/svelte/issues/6092))
* Relax `derived` function signature ([#6178](https://github.com/sveltejs/svelte/issues/6178))
* Support `bind:group` in SSR ([#4621](https://github.com/sveltejs/svelte/pull/4621))
* Add sourcemaps to html elements ([#6427](https://github.com/sveltejs/svelte/pull/6427))
* Throw compiler error when passing empty directive names ([#6299](https://github.com/sveltejs/svelte/issues/6299))
* Fix compiler error when using `:where()` inside `:global()` ([#6434](https://github.com/sveltejs/svelte/issues/6434))
* Fix ordering of elements in keyed `{#each}` ([#6444](https://github.com/sveltejs/svelte/issues/6444))
* Remove deprecated a11y warning `a11y-no-onchange warning` ([#6457](https://github.com/sveltejs/svelte/issues/6457))
* Fix `:global()` with pseudo element not being seen as global ([#6468](https://github.com/sveltejs/svelte/issues/6468))
* Allow `:global()` to contain multiple selectors when it is not part of a larger selector ([#6477](https://github.com/sveltejs/svelte/issues/6477))
* Make `<script>` and `<style>` end tag parsing more robust ([#6511](https://github.com/sveltejs/svelte/pull/6511))
## 3.38.3

349
package-lock.json generated

@ -1,6 +1,6 @@
{
"name": "svelte",
"version": "3.38.3",
"version": "3.41.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -143,6 +143,15 @@
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
"integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
"dev": true
},
"is-reference": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
"integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
"dev": true,
"requires": {
"@types/estree": "*"
}
}
}
},
@ -233,8 +242,8 @@
}
},
"@sveltejs/eslint-config": {
"version": "git+ssh://git@github.com/sveltejs/eslint-config.git#cca8177349dd5a02b19a5865afc4a7066921409a",
"from": "@sveltejs/eslint-config@github:sveltejs/eslint-config#v5.6.0",
"version": "github:sveltejs/eslint-config#31fd4faeea88990069502460b023698b1c9c2d13",
"from": "github:sveltejs/eslint-config#v5.7.0",
"dev": true
},
"@tootallnate/once": {
@ -244,9 +253,9 @@
"dev": true
},
"@types/estree": {
"version": "0.0.45",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.45.tgz",
"integrity": "sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g==",
"version": "0.0.50",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz",
"integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==",
"dev": true
},
"@types/is-windows": {
@ -947,34 +956,17 @@
}
},
"code-red": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/code-red/-/code-red-0.2.1.tgz",
"integrity": "sha512-qn8UyXkRqHJnWkrgc5AGDjkgoqlK5BtelIykSCl89HOV/HMtVxZw2GTwD2A7uMbLgGmch4/KyJX+mcWuPpqCtg==",
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/code-red/-/code-red-0.2.2.tgz",
"integrity": "sha512-CvM8mK6RkLCwMNt+/TBLmqC6eKcbky9AOR+jC+0ClSh4Mk2Ix7+sPqUEIAbJzT822oCu3D469prC7155657n2A==",
"dev": true,
"requires": {
"@types/estree": "^0.0.45",
"@types/estree": "^0.0.50",
"acorn": "^8.0.5",
"estree-walker": "^0.9.0",
"is-reference": "^2.0.0",
"periscopic": "^2.0.1",
"estree-walker": "^3.0.0",
"is-reference": "^3.0.0",
"periscopic": "^3.0.4",
"sourcemap-codec": "^1.4.8"
},
"dependencies": {
"estree-walker": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.9.0.tgz",
"integrity": "sha512-12U47o7XHUX329+x3FzNVjCx3SHEzMF0nkDv7r/HnBzX/xNTKxajBk6gyygaxrAFtLj39219oMfbtxv4KpaOiA==",
"dev": true
},
"is-reference": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-2.0.0.tgz",
"integrity": "sha512-kgaeJVq59jasPrhlGK/K61muTjLxMOZf4oMwI4X94nDWqkqLxDWVWrecCSP5c6OR8JF7Yul0X7h59lB1ho0epQ==",
"dev": true,
"requires": {
"@types/estree": "*"
}
}
}
},
"codecov": {
@ -1921,9 +1913,9 @@
"dev": true
},
"estree-walker": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.0.tgz",
"integrity": "sha512-vY6xMN2j47HfQfVWGRqHshr1olf+XS1Y488NoqjDP1c8E1TcoZr/D3eSGa6akBs76WL1X9nluWjgBsCKdt/qKg==",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.0.tgz",
"integrity": "sha512-s6ceX0NFiU/vKPiKvFdR83U1Zffu7upwZsGwpoqfg5rbbq1l50WQ5hCeIvM6E6oD4shUHCYMsiFPns4Jk0YfMQ==",
"dev": true
},
"esutils": {
@ -2576,9 +2568,9 @@
"dev": true
},
"is-reference": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
"integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.0.tgz",
"integrity": "sha512-Eo1W3wUoHWoCoVM4GVl/a+K0IgiqE5aIo4kJABFyMum1ZORlPkC+UC357sSQUL5w5QCE5kCC9upl75b7+7CY/Q==",
"dev": true,
"requires": {
"@types/estree": "*"
@ -3111,8 +3103,7 @@
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"mz": {
"version": "2.7.0",
@ -3331,14 +3322,6 @@
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2",
"wordwrap": "~1.0.0"
},
"dependencies": {
"wordwrap": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
"integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
"dev": true
}
}
},
"os-locale": {
@ -3473,21 +3456,13 @@
"dev": true
},
"periscopic": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/periscopic/-/periscopic-2.0.3.tgz",
"integrity": "sha512-FuCZe61mWxQOJAQFEfmt9FjzebRlcpFz8sFPbyaCKtdusPkMEbA9ey0eARnRav5zAhmXznhaQkKGFAPn7X9NUw==",
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.0.4.tgz",
"integrity": "sha512-SFx68DxCv0Iyo6APZuw/AKewkkThGwssmU0QWtTlvov3VAtPX+QJ4CadwSaz8nrT5jPIuxdvJWB4PnD2KNDxQg==",
"dev": true,
"requires": {
"estree-walker": "^2.0.2",
"is-reference": "^1.1.4"
},
"dependencies": {
"estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"dev": true
}
"estree-walker": "^3.0.0",
"is-reference": "^3.0.0"
}
},
"picomatch": {
@ -4093,184 +4068,9 @@
"es-abstract": "^1.17.5"
},
"dependencies": {
"es-abstract": {
"version": "1.17.5",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz",
"integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==",
"dev": true,
"requires": {
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1",
"is-callable": "^1.1.5",
"is-regex": "^1.0.5",
"object-inspect": "^1.7.0",
"object-keys": "^1.1.1",
"object.assign": "^4.1.0",
"string.prototype.trimleft": "^2.1.1",
"string.prototype.trimright": "^2.1.1"
}
},
"es-to-primitive": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
"integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
"dev": true,
"requires": {
"is-callable": "^1.1.4",
"is-date-object": "^1.0.1",
"is-symbol": "^1.0.2"
}
},
"has-symbols": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
"integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
"dev": true
},
"is-callable": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz",
"integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==",
"dev": true
},
"is-regex": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz",
"integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==",
"dev": true,
"requires": {
"has": "^1.0.3"
}
}
}
},
"string.prototype.trimleft": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz",
"integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.17.5",
"string.prototype.trimstart": "^1.0.0"
},
"dependencies": {
"es-abstract": {
"version": "1.17.5",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz",
"integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==",
"dev": true,
"requires": {
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1",
"is-callable": "^1.1.5",
"is-regex": "^1.0.5",
"object-inspect": "^1.7.0",
"object-keys": "^1.1.1",
"object.assign": "^4.1.0",
"string.prototype.trimleft": "^2.1.1",
"string.prototype.trimright": "^2.1.1"
}
},
"es-to-primitive": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
"integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
"dev": true,
"requires": {
"is-callable": "^1.1.4",
"is-date-object": "^1.0.1",
"is-symbol": "^1.0.2"
}
},
"has-symbols": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
"integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
"dev": true
},
"is-callable": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz",
"integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==",
"dev": true
},
"is-regex": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz",
"integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==",
"dev": true,
"requires": {
"has": "^1.0.3"
}
}
}
},
"string.prototype.trimright": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz",
"integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.17.5",
"string.prototype.trimend": "^1.0.0"
},
"dependencies": {
"es-abstract": {
"version": "1.17.5",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz",
"integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==",
"dev": true,
"requires": {
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1",
"is-callable": "^1.1.5",
"is-regex": "^1.0.5",
"object-inspect": "^1.7.0",
"object-keys": "^1.1.1",
"object.assign": "^4.1.0",
"string.prototype.trimleft": "^2.1.1",
"string.prototype.trimright": "^2.1.1"
}
},
"es-to-primitive": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
"integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
"dev": true,
"requires": {
"is-callable": "^1.1.4",
"is-date-object": "^1.0.1",
"is-symbol": "^1.0.2"
}
},
"has-symbols": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
"integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
"dev": true
},
"is-callable": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz",
"integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==",
"dev": true
},
"is-regex": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz",
"integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==",
"dev": true,
"requires": {
"has": "^1.0.3"
}
"version": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
"integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg=="
}
}
},
@ -4284,56 +4084,9 @@
"es-abstract": "^1.17.5"
},
"dependencies": {
"es-abstract": {
"version": "1.17.5",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz",
"integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==",
"dev": true,
"requires": {
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1",
"is-callable": "^1.1.5",
"is-regex": "^1.0.5",
"object-inspect": "^1.7.0",
"object-keys": "^1.1.1",
"object.assign": "^4.1.0",
"string.prototype.trimleft": "^2.1.1",
"string.prototype.trimright": "^2.1.1"
}
},
"es-to-primitive": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
"integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
"dev": true,
"requires": {
"is-callable": "^1.1.4",
"is-date-object": "^1.0.1",
"is-symbol": "^1.0.2"
}
},
"has-symbols": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
"integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
"dev": true
},
"is-callable": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz",
"integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==",
"dev": true
},
"is-regex": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz",
"integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==",
"dev": true,
"requires": {
"has": "^1.0.3"
}
"version": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
"integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg=="
}
}
},
@ -4449,30 +4202,12 @@
"uuid": "^3.3.2"
},
"dependencies": {
"agent-base": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz",
"integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==",
"dev": true
},
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"version": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"dev": true,
"requires": {
"ms": "^2.1.1"
}
},
"https-proxy-agent": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz",
"integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==",
"dev": true,
"requires": {
"agent-base": "5",
"debug": "4"
}
}
}
},
@ -4808,6 +4543,12 @@
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
"dev": true
},
"wordwrap": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
"integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
"dev": true
},
"wrap-ansi": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",

@ -1,6 +1,6 @@
{
"name": "svelte",
"version": "3.38.3",
"version": "3.41.0",
"description": "Cybernetically enhanced web apps",
"module": "index.mjs",
"main": "index",
@ -107,7 +107,7 @@
"@rollup/plugin-sucrase": "^3.1.0",
"@rollup/plugin-typescript": "^2.0.1",
"@rollup/plugin-virtual": "^2.0.0",
"@sveltejs/eslint-config": "github:sveltejs/eslint-config#v5.6.0",
"@sveltejs/eslint-config": "github:sveltejs/eslint-config#v5.7.0",
"@types/mocha": "^7.0.0",
"@types/node": "^8.10.53",
"@typescript-eslint/eslint-plugin": "^4.9.0",
@ -115,20 +115,20 @@
"acorn": "^8.4.1",
"agadoo": "^1.1.0",
"c8": "^5.0.1",
"code-red": "^0.2.1",
"code-red": "^0.2.2",
"codecov": "^3.5.0",
"css-tree": "^1.1.2",
"eslint": "^7.15.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-svelte3": "^2.7.3",
"estree-walker": "^1.0.0",
"is-reference": "^1.1.4",
"estree-walker": "^3.0.0",
"is-reference": "^3.0.0",
"jsdom": "^15.2.1",
"kleur": "^3.0.3",
"locate-character": "^2.0.5",
"magic-string": "^0.25.3",
"mocha": "^7.0.0",
"periscopic": "^2.0.3",
"periscopic": "^3.0.4",
"puppeteer": "^2.1.1",
"rollup": "^1.27.14",
"source-map": "^0.7.3",

@ -95,8 +95,6 @@ To change component state and trigger a re-render, just assign to a locally decl
Update expressions (`count += 1`) and property assignments (`obj.x = y`) have the same effect.
Because Svelte's reactivity is based on assignments, using array methods like `.push()` and `.splice()` won't automatically trigger updates. Options for getting around this can be found in the [tutorial](tutorial/updating-arrays-and-objects).
```sv
<script>
let count = 0;
@ -109,6 +107,24 @@ Because Svelte's reactivity is based on assignments, using array methods like `.
</script>
```
---
Because Svelte's reactivity is based on assignments, using array methods like `.push()` and `.splice()` won't automatically trigger updates. A subsequent assignment is required to trigger the update. This and more details can also be found in the [tutorial](tutorial/updating-arrays-and-objects).
```sv
<script>
let arr = [0, 1];
function handleClick () {
// this method call does not trigger an update
arr.push(2);
// this assignment will trigger an update
// if the markup references `arr`
arr = arr
}
</script>
```
#### 3. `$:` marks a statement as reactive
---

@ -516,6 +516,7 @@ The following modifiers are available:
* `capture` — fires the handler during the *capture* phase instead of the *bubbling* phase
* `once` — remove the handler after the first time it runs
* `self` — only trigger handler if event.target is the element itself
* `trusted` — only trigger handler if `event.trusted` is `true`. I.e. if the event is triggered by a user action.
Modifiers can be chained together, e.g. `on:click|once|capture={...}`.

@ -84,6 +84,8 @@ afterUpdate(callback: () => void)
Schedules a callback to run immediately after the component has been updated.
> The first time the callback runs will be after the initial `onMount`
```sv
<script>
import { afterUpdate } from 'svelte';
@ -198,6 +200,24 @@ Checks whether a given `key` has been set in the context of a parent component.
</script>
```
#### `getAllContexts`
```js
contexts: Map<any, any> = getAllContexts()
```
---
Retrieves the whole context map that belongs to the closest parent component. Must be called during component initialisation. Useful, for example, if you programmatically create a component and want to pass the existing context to it.
```sv
<script>
import { getAllContexts } from 'svelte';
const contexts = getAllContexts();
</script>
```
#### `createEventDispatcher`
```js
@ -929,7 +949,7 @@ The following initialisation options can be provided:
| option | default | description |
| --- | --- | --- |
| `target` | **none** | An `HTMLElement` to render to. This option is required
| `target` | **none** | An `HTMLElement` or `ShadowRoot` to render to. This option is required
| `anchor` | `null` | A child of `target` to render the component immediately before
| `props` | `{}` | An object of properties to supply to the component
| `context` | `new Map()` | A `Map` of root-level context key-value pairs to supply to the component

@ -45,6 +45,7 @@ The following options can be passed to the compiler. None are required:
| `name` | string | `"Component"`
| `format` | `"esm"` or `"cjs"` | `"esm"`
| `generate` | `"dom"` or `"ssr"` or `false` | `"dom"`
| `errorMode` | `"throw"` or `"warn"` | `"throw"`
| `varsReport` | `"strict"` or `"full"` or `false` | `"strict"`
| `dev` | boolean | `false`
| `immutable` | boolean | `false`
@ -67,6 +68,7 @@ The following options can be passed to the compiler. None are required:
| `name` | `"Component"` | `string` that sets the name of the resulting JavaScript class (though the compiler will rename it if it would otherwise conflict with other variables in scope). It will normally be inferred from `filename`.
| `format` | `"esm"` | If `"esm"`, creates a JavaScript module (with `import` and `export`). If `"cjs"`, creates a CommonJS module (with `require` and `module.exports`), which is useful in some server-side rendering situations or for testing.
| `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.
| `errorMode` | `"throw"` | If `"throw"`, Svelte throws when a compilation error occured. If `"warn"`, Svelte will treat errors as warnings and add them to the warning report.
| `varsReport` | `"strict"` | If `"strict"`, Svelte returns a variables report with only variables that are not globals nor internals. If `"full"`, Svelte returns a variables report with all detected variables. If `false`, no variables report is returned.
| `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.

@ -25,5 +25,6 @@ The full list of modifiers:
* `capture` — fires the handler during the *capture* phase instead of the *bubbling* phase ([MDN docs](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture))
* `once` — remove the handler after the first time it runs
* `self` — only trigger handler if event.target is the element itself
* `trusted` — only trigger handler if `event.trusted` is `true`. I.e. if the event is triggered by a user action.
You can chain modifiers together, e.g. `on:click|once|capture={...}`.

@ -17,3 +17,5 @@ Returning to our [earlier ice cream example](tutorial/group-inputs), we can repl
{/each}
</select>
```
> Press and hold the `control` key for selecting multiple options.

@ -3434,9 +3434,9 @@
}
},
"svelte": {
"version": "3.37.0",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.37.0.tgz",
"integrity": "sha512-TRF30F4W4+d+Jr2KzUUL1j8Mrpns/WM/WacxYlo5MMb2E5Qy2Pk1Guj6GylxsW9OnKQl1tnF8q3hG/hQ3h6VUA==",
"version": "3.39.0",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.39.0.tgz",
"integrity": "sha512-dcJCongL0cRkZWe9q+fde0T4HX8PksBywz2+EGDVIrdYdJaxTzrJu0RVeuDtL8Mx2hs4yn3W8zKPScuzG63hTg==",
"dev": true
},
"svelte-json-tree": {

@ -55,7 +55,7 @@
"rollup-plugin-terser": "^7.0.0",
"sapper": "^0.28.10",
"shelljs": "^0.8.3",
"svelte": "^3.37.0"
"svelte": "^3.39.0"
},
"engines": {
"node": ">=10.0.0"

@ -10,7 +10,6 @@ import {
Scope,
extract_identifiers
} from './utils/scope';
import { Node as PeriscopicNode } from 'periscopic';
import Stylesheet from './css/Stylesheet';
import { test } from '../config';
import Fragment from './nodes/Fragment';
@ -20,15 +19,15 @@ import error from '../utils/error';
import get_code_frame from '../utils/get_code_frame';
import flatten_reference from './utils/flatten_reference';
import is_used_as_reference from './utils/is_used_as_reference';
import is_reference from 'is-reference';
import is_reference, { NodeWithPropertyDefinition } from 'is-reference';
import TemplateScope from './nodes/shared/TemplateScope';
import fuzzymatch from '../utils/fuzzymatch';
import get_object from './utils/get_object';
import Slot from './nodes/Slot';
import { Node, ImportDeclaration, Identifier, Program, ExpressionStatement, AssignmentExpression, Literal } from 'estree';
import { Node, ImportDeclaration, ExportNamedDeclaration, Identifier, ExpressionStatement, AssignmentExpression, Literal, Property, RestElement, ExportDefaultDeclaration, ExportAllDeclaration } from 'estree';
import add_to_set from './utils/add_to_set';
import check_graph_for_cycles from './utils/check_graph_for_cycles';
import { print, x, b } from 'code-red';
import { print, b } from 'code-red';
import { is_reserved_keyword } from './utils/reserved_keywords';
import { apply_preprocessor_sourcemap } from '../utils/mapped_code';
import Element from './nodes/Element';
@ -36,6 +35,7 @@ import { DecodedSourceMap, RawSourceMap } from '@ampproject/remapping/dist/types
import { clone } from '../utils/clone';
import compiler_warnings from './compiler_warnings';
import compiler_errors from './compiler_errors';
import { extract_ignores_above_position, extract_svelte_ignore_from_comments } from '../utils/extract_svelte_ignore';
interface ComponentOptions {
namespace?: string;
@ -70,6 +70,8 @@ export default class Component {
var_lookup: Map<string, Var> = new Map();
imports: ImportDeclaration[] = [];
exports_from: ExportNamedDeclaration[] = [];
instance_exports_from: ExportNamedDeclaration[] = [];
hoistable_nodes: Set<Node> = new Set();
node_for_declaration: Map<string, Node> = new Map();
@ -171,12 +173,17 @@ export default class Component {
}
this.walk_module_js();
this.push_ignores(this.ast.instance ? extract_ignores_above_position(this.ast.instance.start, this.ast.html.children) : []);
this.walk_instance_js_pre_template();
this.pop_ignores();
this.fragment = new Fragment(this, ast.html);
this.name = this.get_unique_name(name);
this.push_ignores(this.ast.instance ? extract_ignores_above_position(this.ast.instance.start, this.ast.html.children) : []);
this.walk_instance_js_post_template();
this.pop_ignores();
this.elements.forEach(element => this.stylesheet.apply(element));
if (!compile_options.customElement) this.stylesheet.reify();
@ -267,6 +274,14 @@ export default class Component {
} else {
let name = node.name.slice(1);
if (compile_options.hydratable) {
if (internal_exports.has(`${name}_hydration`)) {
name += '_hydration';
} else if (internal_exports.has(`${name}Hydration`)) {
name += 'Hydration';
}
}
if (compile_options.dev) {
if (internal_exports.has(`${name}_dev`)) {
name += '_dev';
@ -320,7 +335,8 @@ export default class Component {
.map(variable => ({
name: variable.name,
as: variable.export_name
}))
})),
this.exports_from
);
css = compile_options.customElement
@ -429,14 +445,18 @@ export default class Component {
message: string;
}
) {
error(e.message, {
name: 'ValidationError',
code: e.code,
source: this.source,
start: pos.start,
end: pos.end,
filename: this.compile_options.filename
});
if (this.compile_options.errorMode === 'warn') {
this.warn(pos, e);
} else {
error(e.message, {
name: 'ValidationError',
code: e.code,
source: this.source,
start: pos.start,
end: pos.end,
filename: this.compile_options.filename
});
}
}
warn(
@ -475,14 +495,27 @@ export default class Component {
this.imports.push(node);
}
extract_exports(node) {
extract_exports(node, module_script = false) {
const ignores = extract_svelte_ignore_from_comments(node);
if (ignores.length) this.push_ignores(ignores);
const result = this._extract_exports(node, module_script);
if (ignores.length) this.pop_ignores();
return result;
}
private _extract_exports(node: ExportDefaultDeclaration | ExportNamedDeclaration | ExportAllDeclaration, module_script) {
if (node.type === 'ExportDefaultDeclaration') {
this.error(node, compiler_errors.default_export);
return this.error(node as any, compiler_errors.default_export);
}
if (node.type === 'ExportNamedDeclaration') {
if (node.source) {
this.error(node, compiler_errors.not_implemented);
if (module_script) {
this.exports_from.push(node);
} else {
this.instance_exports_from.push(node);
}
return null;
}
if (node.declaration) {
if (node.declaration.type === 'VariableDeclaration') {
@ -491,7 +524,7 @@ export default class Component {
const variable = this.var_lookup.get(name);
variable.export_name = name;
if (variable.writable && !(variable.referenced || variable.referenced_from_script || variable.subscribable)) {
this.warn(declarator, compiler_warnings.unused_export_let(this.name.name, name));
this.warn(declarator as any, compiler_warnings.unused_export_let(this.name.name, name));
}
});
});
@ -511,7 +544,7 @@ export default class Component {
variable.export_name = specifier.exported.name;
if (variable.writable && !(variable.referenced || variable.referenced_from_script || variable.subscribable)) {
this.warn(specifier, compiler_warnings.unused_export_let(this.name.name, specifier.exported.name));
this.warn(specifier as any, compiler_warnings.unused_export_let(this.name.name, specifier.exported.name));
}
}
});
@ -552,7 +585,7 @@ export default class Component {
scope.declarations.forEach((node, name) => {
if (name[0] === '$') {
this.error(node as any, compiler_errors.illegal_declaration);
return this.error(node as any, compiler_errors.illegal_declaration);
}
const writable = node.type === 'VariableDeclaration' && (node.kind === 'var' || node.kind === 'let');
@ -567,7 +600,7 @@ export default class Component {
globals.forEach((node, name) => {
if (name[0] === '$') {
this.error(node as any, compiler_errors.illegal_subscription);
return this.error(node as any, compiler_errors.illegal_subscription);
} else {
this.add_var({
name,
@ -587,7 +620,7 @@ export default class Component {
}
if (/^Export/.test(node.type)) {
const replacement = this.extract_exports(node);
const replacement = this.extract_exports(node, true);
if (replacement) {
body[i] = replacement;
} else {
@ -625,7 +658,7 @@ export default class Component {
instance_scope.declarations.forEach((node, name) => {
if (name[0] === '$') {
this.error(node as any, compiler_errors.illegal_declaration);
return this.error(node as any, compiler_errors.illegal_declaration);
}
const writable = node.type === 'VariableDeclaration' && (node.kind === 'var' || node.kind === 'let');
@ -641,8 +674,17 @@ export default class Component {
this.node_for_declaration.set(name, node);
});
globals.forEach((node, name) => {
// NOTE: add store variable first, then only $store value
// as `$store` will mark `store` variable as referenced and subscribable
const global_keys = Array.from(globals.keys());
const sorted_globals = [
...global_keys.filter(key => key[0] !== '$'),
...global_keys.filter(key => key[0] === '$')
];
sorted_globals.forEach(name => {
if (this.var_lookup.has(name)) return;
const node = globals.get(name);
if (this.injected_reactive_declaration_vars.has(name)) {
this.add_var({
@ -659,7 +701,7 @@ export default class Component {
});
} else if (name[0] === '$') {
if (name === '$' || name[1] === '$') {
this.error(node as any, compiler_errors.illegal_global(name));
return this.error(node as any, compiler_errors.illegal_global(name));
}
this.add_var({
@ -717,7 +759,7 @@ export default class Component {
let generator_count = 0;
walk(content, {
enter(node: Node, parent, prop, index) {
enter(node: Node, parent: Node, prop, index) {
if ((node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression') && node.generator === true) {
generator_count++;
}
@ -802,7 +844,7 @@ export default class Component {
if (node.type === 'AssignmentExpression' || node.type === 'UpdateExpression') {
const assignee = node.type === 'AssignmentExpression' ? node.left : node.argument;
const names = extract_names(assignee as PeriscopicNode);
const names = extract_names(assignee as Node);
const deep = assignee.type === 'MemberExpression';
@ -845,7 +887,7 @@ export default class Component {
this.warn(node as any, compiler_warnings.non_top_level_reactive_declaration);
}
if (is_reference(node, parent)) {
if (is_reference(node as NodeWithPropertyDefinition, parent as NodeWithPropertyDefinition)) {
const object = get_object(node);
const { name } = object;
@ -856,7 +898,7 @@ export default class Component {
if (name[1] !== '$' && scope.has(name.slice(1)) && scope.find_owner(name.slice(1)) !== this.instance_scope) {
if (!((/Function/.test(parent.type) && prop === 'params') || (parent.type === 'VariableDeclarator' && prop === 'id'))) {
this.error(node as any, compiler_errors.contextual_store);
return this.error(node as any, compiler_errors.contextual_store);
}
}
}
@ -901,7 +943,7 @@ export default class Component {
let scope = instance_scope;
walk(this.ast.instance.content, {
enter(node: Node, parent, key, index) {
enter(node: Node) {
if (/Function/.test(node.type)) {
return this.skip();
}
@ -910,75 +952,130 @@ export default class Component {
scope = map.get(node);
}
if (node.type === 'ExportNamedDeclaration' && node.declaration) {
return this.replace(node.declaration);
}
if (node.type === 'VariableDeclaration') {
// NOTE: `var` does not follow block scoping
if (node.kind === 'var' || scope === instance_scope) {
node.declarations.forEach(declarator => {
if (declarator.id.type !== 'Identifier') {
const inserts = [];
extract_names(declarator.id).forEach(name => {
const variable = component.var_lookup.get(name);
if (variable.export_name) {
// TODO is this still true post-#3539?
component.error(declarator as any, compiler_errors.destructured_prop);
const inserts = [];
const props = [];
function add_new_props(exported, local, default_value) {
props.push({
type: 'Property',
method: false,
shorthand: false,
computed: false,
kind: 'init',
key: exported,
value: default_value
? {
type: 'AssignmentPattern',
left: local,
right: default_value
}
: local
});
}
// transform
// ```
// export let { x, y = 123 } = OBJ, z = 456
// ```
// into
// ```
// let { x: x$, y: y$ = 123 } = OBJ;
// let { x = x$, y = y$, z = 456 } = $$props;
// ```
for (let index = 0; index < node.declarations.length; index++) {
const declarator = node.declarations[index];
if (declarator.id.type !== 'Identifier') {
function get_new_name(local) {
const variable = component.var_lookup.get(local.name);
if (variable.subscribable) {
inserts.push(get_insert(variable));
}
});
if (inserts.length) {
parent[key].splice(index + 1, 0, ...inserts);
if (variable.export_name && variable.writable) {
const alias_name = component.get_unique_name(local.name);
add_new_props({ type: 'Identifier', name: variable.export_name }, local, alias_name);
return alias_name;
}
return local;
}
return;
}
const { name } = declarator.id;
const variable = component.var_lookup.get(name);
function rename_identifiers(param: Node) {
switch (param.type) {
case 'ObjectPattern': {
const handle_prop = (prop: Property | RestElement) => {
if (prop.type === 'RestElement') {
rename_identifiers(prop);
} else if (prop.value.type === 'Identifier') {
prop.value = get_new_name(prop.value);
} else {
rename_identifiers(prop.value);
}
};
param.properties.forEach(handle_prop);
break;
}
case 'ArrayPattern': {
const handle_element = (element: Node, index: number, array: Node[]) => {
if (element) {
if (element.type === 'Identifier') {
array[index] = get_new_name(element);
} else {
rename_identifiers(element);
}
}
};
param.elements.forEach(handle_element);
break;
}
case 'RestElement':
param.argument = get_new_name(param.argument);
break;
case 'AssignmentPattern':
param.left = get_new_name(param.left);
break;
}
}
if (variable.export_name && variable.writable) {
declarator.id = {
type: 'ObjectPattern',
properties: [{
type: 'Property',
method: false,
shorthand: false,
computed: false,
kind: 'init',
key: { type: 'Identifier', name: variable.export_name },
value: declarator.init
? {
type: 'AssignmentPattern',
left: declarator.id,
right: declarator.init
}
: declarator.id
}]
};
declarator.init = x`$$props`;
rename_identifiers(declarator.id);
} else {
const { name } = declarator.id;
const variable = component.var_lookup.get(name);
const is_props = variable.export_name && variable.writable;
if (is_props) {
add_new_props({ type: 'Identifier', name: variable.export_name }, declarator.id, declarator.init);
node.declarations.splice(index--, 1);
}
if (variable.subscribable && (is_props || declarator.init)) {
inserts.push(get_insert(variable));
}
}
}
if (variable.subscribable && declarator.init) {
const insert = get_insert(variable);
parent[key].splice(index + 1, 0, ...insert);
}
});
this.replace(b`
${node.declarations.length ? node : null}
${ props.length > 0 && b`let { ${ props } } = $$props;`}
${inserts}
` as any);
return this.skip();
}
}
},
leave(node: Node, parent, _key, index) {
leave(node: Node) {
if (map.has(node)) {
scope = scope.parent;
}
if (node.type === 'ExportNamedDeclaration' && node.declaration) {
(parent as Program).body[index] = node.declaration;
}
}
});
}
@ -1081,7 +1178,7 @@ export default class Component {
scope = map.get(node);
}
if (is_reference(node as Node, parent as Node)) {
if (is_reference(node as NodeWithPropertyDefinition, parent as NodeWithPropertyDefinition)) {
const { name } = flatten_reference(node);
const owner = scope.find_owner(name);
@ -1169,12 +1266,16 @@ export default class Component {
}> = [];
this.ast.instance.content.body.forEach(node => {
const ignores = extract_svelte_ignore_from_comments(node);
if (ignores.length) this.push_ignores(ignores);
if (node.type === 'LabeledStatement' && node.label.name === '$') {
this.reactive_declaration_nodes.add(node);
const assignees = new Set<string>();
const assignee_nodes = new Set();
const dependencies = new Set<string>();
const module_dependencies = new Set<string>();
let scope = this.instance_scope;
const map = this.instance_scope_map;
@ -1199,7 +1300,7 @@ export default class Component {
} else if (node.type === 'UpdateExpression') {
const identifier = get_object(node.argument);
assignees.add(identifier.name);
} else if (is_reference(node as Node, parent as Node)) {
} else if (is_reference(node as NodeWithPropertyDefinition, parent as NodeWithPropertyDefinition)) {
const identifier = get_object(node);
if (!assignee_nodes.has(identifier)) {
const { name } = identifier;
@ -1211,7 +1312,7 @@ export default class Component {
variable.is_reactive_dependency = true;
if (variable.module) {
should_add_as_dependency = false;
component.warn(node as any, compiler_warnings.module_script_variable_reactive_declaration(name));
module_dependencies.add(name);
}
}
const is_writable_or_mutated =
@ -1236,6 +1337,10 @@ export default class Component {
}
});
if (module_dependencies.size > 0 && dependencies.size === 0) {
component.warn(node.body as any, compiler_warnings.module_script_variable_reactive_declaration(Array.from(module_dependencies)));
}
const { expression } = node.body as ExpressionStatement;
const declaration = expression && (expression as AssignmentExpression).left;
@ -1246,6 +1351,8 @@ export default class Component {
declaration
});
}
if (ignores.length) this.pop_ignores();
});
const lookup = new Map();
@ -1276,7 +1383,7 @@ export default class Component {
if (cycle && cycle.length) {
const declarationList = lookup.get(cycle[0]);
const declaration = declarationList[0];
this.error(declaration.node, compiler_errors.cyclical_reactive_declaration(cycle));
return this.error(declaration.node, compiler_errors.cyclical_reactive_declaration(cycle));
}
const add_declaration = declaration => {
@ -1299,7 +1406,7 @@ export default class Component {
warn_if_undefined(name: string, node, template_scope: TemplateScope) {
if (name[0] === '$') {
if (name === '$' || name[1] === '$' && !is_reserved_keyword(name)) {
this.error(node, compiler_errors.illegal_global(name));
return this.error(node, compiler_errors.illegal_global(name));
}
this.has_reactive_assignments = true; // TODO does this belong here?
@ -1348,13 +1455,13 @@ function process_component_options(component: Component, nodes) {
if (!chunk) return true;
if (value.length > 1) {
component.error(attribute, { code, message });
return component.error(attribute, { code, message });
}
if (chunk.type === 'Text') return chunk.data;
if (chunk.expression.type !== 'Literal') {
component.error(attribute, { code, message });
return component.error(attribute, { code, message });
}
return chunk.expression.value;
@ -1370,11 +1477,11 @@ function process_component_options(component: Component, nodes) {
const tag = get_value(attribute, compiler_errors.invalid_tag_attribute);
if (typeof tag !== 'string' && tag !== null) {
component.error(attribute, compiler_errors.invalid_tag_attribute);
return component.error(attribute, compiler_errors.invalid_tag_attribute);
}
if (tag && !/^[a-zA-Z][a-zA-Z0-9]*-[a-zA-Z0-9-]+$/.test(tag)) {
component.error(attribute, compiler_errors.invalid_tag_property);
return component.error(attribute, compiler_errors.invalid_tag_property);
}
if (tag && !component.compile_options.customElement) {
@ -1389,12 +1496,12 @@ function process_component_options(component: Component, nodes) {
const ns = get_value(attribute, compiler_errors.invalid_namespace_attribute);
if (typeof ns !== 'string') {
component.error(attribute, compiler_errors.invalid_namespace_attribute);
return component.error(attribute, compiler_errors.invalid_namespace_attribute);
}
if (valid_namespaces.indexOf(ns) === -1) {
const match = fuzzymatch(ns, valid_namespaces);
component.error(attribute, compiler_errors.invalid_namespace_property(ns, match));
return component.error(attribute, compiler_errors.invalid_namespace_property(ns, match));
}
component_options.namespace = ns;
@ -1407,7 +1514,7 @@ function process_component_options(component: Component, nodes) {
const value = get_value(attribute, compiler_errors.invalid_attribute_value(name));
if (typeof value !== 'boolean') {
component.error(attribute, compiler_errors.invalid_attribute_value(name));
return component.error(attribute, compiler_errors.invalid_attribute_value(name));
}
component_options[name] = value;
@ -1415,10 +1522,10 @@ function process_component_options(component: Component, nodes) {
}
default:
component.error(attribute, compiler_errors.invalid_options_attribute_unknown);
return component.error(attribute, compiler_errors.invalid_options_attribute_unknown);
}
} else {
component.error(attribute, compiler_errors.invalid_options_attribute);
return component.error(attribute, compiler_errors.invalid_options_attribute);
}
});
}

@ -174,10 +174,6 @@ export default {
code: 'default-export',
message: 'A component cannot have a default export'
},
not_implemented: {
code: 'not-implemented',
message: 'A component currently cannot have an export ... from'
},
illegal_declaration: {
code: 'illegal-declaration',
message: 'The $ prefix is reserved, and cannot be used for variable and import names'
@ -190,10 +186,6 @@ export default {
code: 'illegal-global',
message: `${name} is an illegal variable name`
}),
destructured_prop: {
code: 'destructured-prop',
message: 'Cannot declare props in destructured declaration'
},
cyclical_reactive_declaration: (cycle: string[]) => ({
code: 'cyclical-reactive-declaration',
message: `Cyclical dependency detected: ${cycle.join(' → ')}`

@ -20,9 +20,9 @@ export default {
code: 'non-top-level-reactive-declaration',
message: '$: has no effect outside of the top-level'
},
module_script_variable_reactive_declaration: (name: string) => ({
module_script_variable_reactive_declaration: (names: string[]) => ({
code: 'module-script-reactive-declaration',
message: `"${name}" is declared in a module script and will not be reactive`
message: `${names.map(name => `"${name}"`).join(', ')} ${names.length > 1 ? 'are' : 'is'} declared in a module script and will not be reactive`
}),
missing_declaration: (name: string, has_script: boolean) => ({
code: 'missing-declaration',

@ -1,7 +1,7 @@
import list from '../utils/list';
import { ModuleFormat } from '../interfaces';
import { b, x } from 'code-red';
import { Identifier, ImportDeclaration } from 'estree';
import { Identifier, ImportDeclaration, ExportNamedDeclaration } from 'estree';
const wrappers = { esm, cjs };
@ -19,20 +19,21 @@ export default function create_module(
helpers: Array<{ name: string; alias: Identifier }>,
globals: Array<{ name: string; alias: Identifier }>,
imports: ImportDeclaration[],
module_exports: Export[]
module_exports: Export[],
exports_from: ExportNamedDeclaration[]
) {
const internal_path = `${sveltePath}/internal`;
helpers.sort((a, b) => (a.name < b.name) ? -1 : 1);
globals.sort((a, b) => (a.name < b.name) ? -1 : 1);
if (format === 'esm') {
return esm(program, name, banner, sveltePath, internal_path, helpers, globals, imports, module_exports);
}
const formatter = wrappers[format];
if (format === 'cjs') return cjs(program, name, banner, sveltePath, internal_path, helpers, globals, imports, module_exports);
if (!formatter) {
throw new Error(`options.format is invalid (must be ${list(Object.keys(wrappers))})`);
}
throw new Error(`options.format is invalid (must be ${list(Object.keys(wrappers))})`);
return formatter(program, name, banner, sveltePath, internal_path, helpers, globals, imports, module_exports, exports_from);
}
function edit_source(source, sveltePath) {
@ -76,7 +77,8 @@ function esm(
helpers: Array<{ name: string; alias: Identifier }>,
globals: Array<{ name: string; alias: Identifier }>,
imports: ImportDeclaration[],
module_exports: Export[]
module_exports: Export[],
exports_from: ExportNamedDeclaration[]
) {
const import_declaration = {
type: 'ImportDeclaration',
@ -94,6 +96,9 @@ function esm(
imports.forEach(node => {
node.source.value = edit_source(node.source.value, sveltePath);
});
exports_from.forEach(node => {
node.source!.value = edit_source(node.source!.value, sveltePath);
});
const exports = module_exports.length > 0 && {
type: 'ExportNamedDeclaration',
@ -110,6 +115,7 @@ function esm(
${import_declaration}
${internal_globals}
${imports}
${exports_from}
${program.body}
@ -127,7 +133,8 @@ function cjs(
helpers: Array<{ name: string; alias: Identifier }>,
globals: Array<{ name: string; alias: Identifier }>,
imports: ImportDeclaration[],
module_exports: Export[]
module_exports: Export[],
exports_from: ExportNamedDeclaration[]
) {
const internal_requires = {
type: 'VariableDeclaration',
@ -183,6 +190,13 @@ function cjs(
const exports = module_exports.map(x => b`exports.${{ type: 'Identifier', name: x.as }} = ${{ type: 'Identifier', name: x.name }};`);
const user_exports_from = exports_from.map(node => {
const init = x`require("${edit_source(node.source.value, sveltePath)}")`;
return node.specifiers.map(specifier => {
return b`exports.${specifier.exported} = ${init}.${specifier.local};`;
});
});
program.body = b`
/* ${banner} */
@ -190,6 +204,7 @@ function cjs(
${internal_requires}
${internal_globals}
${user_requires}
${user_exports_from}
${program.body}

@ -47,8 +47,9 @@ export default class Selector {
this.local_blocks = this.blocks.slice(0, i);
const host_only = this.blocks.length === 1 && this.blocks[0].host;
const root_only = this.blocks.length === 1 && this.blocks[0].root;
this.used = this.local_blocks.length === 0 || host_only;
this.used = this.local_blocks.length === 0 || host_only || root_only;
}
apply(node: Element) {
@ -138,7 +139,7 @@ export default class Selector {
for (let i = start; i < end; i += 1) {
if (this.blocks[i].global) {
component.error(this.blocks[i].selectors[0], compiler_errors.css_invalid_global);
return component.error(this.blocks[i].selectors[0], compiler_errors.css_invalid_global);
}
}
@ -226,7 +227,8 @@ function apply_selector(blocks: Block[], node: Element, to_encapsulate: Array<{
return false;
} else if (block.combinator.name === '>') {
if (apply_selector(blocks, get_element_parent(node), to_encapsulate)) {
const has_global_parent = blocks.every(block => block.global);
if (has_global_parent || apply_selector(blocks, get_element_parent(node), to_encapsulate)) {
to_encapsulate.push({ node, block });
return true;
}
@ -273,18 +275,16 @@ function block_might_apply_to_node(block: Block, node: Element): BlockAppliesToN
const selector = block.selectors[i];
const name = typeof selector.name === 'string' && selector.name.replace(/\\(.)/g, '$1');
if (selector.type === 'PseudoClassSelector' && name === 'host') {
if (selector.type === 'PseudoClassSelector' && (name === 'host' || name === 'root')) {
return BlockAppliesToNode.NotPossible;
}
if (selector.type === 'PseudoClassSelector' || selector.type === 'PseudoElementSelector') {
continue;
if (block.selectors.length === 1 && selector.type === 'PseudoClassSelector' && name === 'global') {
return BlockAppliesToNode.NotPossible;
}
if (selector.type === 'PseudoClassSelector' && name === 'global') {
// TODO shouldn't see this here... maybe we should enforce that :global(...)
// cannot be sandwiched between non-global selectors?
return BlockAppliesToNode.NotPossible;
if (selector.type === 'PseudoClassSelector' || selector.type === 'PseudoElementSelector') {
continue;
}
if (selector.type === 'ClassSelector') {
@ -582,6 +582,7 @@ function loop_child(children: INode[], adjacent_only: boolean) {
class Block {
host: boolean;
root: boolean;
combinator: CssNode;
selectors: CssNode[]
start: number;
@ -591,6 +592,7 @@ class Block {
constructor(combinator: CssNode) {
this.combinator = combinator;
this.host = false;
this.root = false;
this.selectors = [];
this.start = null;
@ -604,6 +606,7 @@ class Block {
this.start = selector.start;
this.host = selector.type === 'PseudoClassSelector' && selector.name === 'host';
}
this.root = this.root || selector.type === 'PseudoClassSelector' && selector.name === 'root';
this.selectors.push(selector);
this.end = selector.end;

@ -7,6 +7,7 @@ import Component from '../Component';
import { CssNode } from './interfaces';
import hash from '../utils/hash';
import compiler_warnings from '../compiler_warnings';
import { extract_ignores_above_position } from '../../utils/extract_svelte_ignore';
function remove_css_prefix(name: string): string {
return name.replace(/^-((webkit)|(moz)|(o)|(ms))-/, '');
@ -447,10 +448,13 @@ export default class Stylesheet {
}
warn_on_unused_selectors(component: Component) {
const ignores = !this.ast.css ? [] : extract_ignores_above_position(this.ast.css.start, this.ast.html.children);
component.push_ignores(ignores);
this.children.forEach(child => {
child.warn_on_unused_selector((selector: Selector) => {
component.warn(selector.node, compiler_warnings.css_unused_selector(this.source.slice(selector.node.start, selector.node.end)));
});
});
component.pop_ignores();
}
}

@ -14,6 +14,7 @@ const valid_options = [
'filename',
'sourcemap',
'generate',
'errorMode',
'varsReport',
'outputFilename',
'cssOutputFilename',

@ -22,12 +22,14 @@ export default class Animation extends Node {
if (parent.animation) {
component.error(this, compiler_errors.duplicate_animation);
return;
}
const block = parent.parent;
if (!block || block.type !== 'EachBlock' || !block.key) {
// TODO can we relax the 'immediate child' rule?
component.error(this, compiler_errors.invalid_animation_immediate);
return;
}
(block as EachBlock).has_animation = true;

@ -37,6 +37,7 @@ export default class Binding extends Node {
if (info.expression.type !== 'Identifier' && info.expression.type !== 'MemberExpression') {
component.error(info, compiler_errors.invalid_directive_value);
return;
}
this.name = info.name;
@ -50,9 +51,11 @@ export default class Binding extends Node {
// make sure we track this as a mutable ref
if (scope.is_let(name)) {
component.error(this, compiler_errors.invalid_binding_let);
return;
} else if (scope.names.has(name)) {
if (scope.is_await(name)) {
component.error(this, compiler_errors.invalid_binding_await);
return;
}
scope.dependencies_for_name.get(name).forEach(name => {
@ -66,12 +69,14 @@ export default class Binding extends Node {
if (!variable || variable.global) {
component.error(this.expression.node as any, compiler_errors.binding_undeclared(name));
return;
}
variable[this.expression.node.type === 'MemberExpression' ? 'mutated' : 'reassigned'] = true;
if (info.expression.type === 'Identifier' && !variable.writable) {
component.error(this.expression.node as any, compiler_errors.invalid_binding_writibale);
return;
}
}

@ -3,8 +3,6 @@ import Component from '../Component';
import Node from './shared/Node';
import TemplateScope from './shared/TemplateScope';
const pattern = /^\s*svelte-ignore\s+([\s\S]+)\s*$/m;
export default class Comment extends Node {
type: 'Comment';
data: string;
@ -13,8 +11,6 @@ export default class Comment extends Node {
constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
this.data = info.data;
const match = pattern.exec(this.data);
this.ignores = match ? match[1].split(/[^\S]/).map(x => x.trim()).filter(Boolean) : [];
this.ignores = info.ignores;
}
}

@ -63,6 +63,7 @@ export default class EachBlock extends AbstractBlock {
if (this.children.length !== 1) {
const child = this.children.find(child => !!(child as Element).animation);
component.error((child as Element).animation, compiler_errors.invalid_animation_sole);
return;
}
}

@ -144,6 +144,7 @@ export default class Element extends Node {
const value_attribute = info.attributes.find(node => node.name === 'value');
if (value_attribute) {
component.error(value_attribute, compiler_errors.textarea_duplicate_value);
return;
}
// this is an egregious hack, but it's the easiest way to get <textarea>
@ -278,22 +279,23 @@ export default class Element extends Node {
// Errors
if (/(^[0-9-.])|[\^$@%&#?!|()[\]{}^*+~;]/.test(name)) {
component.error(attribute, compiler_errors.illegal_attribute(name));
return component.error(attribute, compiler_errors.illegal_attribute(name));
}
if (name === 'slot') {
if (!attribute.is_static) {
component.error(attribute, compiler_errors.invalid_slot_attribute);
return component.error(attribute, compiler_errors.invalid_slot_attribute);
}
if (component.slot_outlets.has(name)) {
component.error(attribute, compiler_errors.duplicate_slot_attribute(name));
return component.error(attribute, compiler_errors.duplicate_slot_attribute(name));
component.slot_outlets.add(name);
// this code was unreachable. Still needed?
// component.slot_outlets.add(name);
}
if (!(parent.type === 'SlotTemplate' || within_custom_element(parent))) {
component.error(attribute, compiler_errors.invalid_slotted_content);
return component.error(attribute, compiler_errors.invalid_slotted_content);
}
}
@ -525,7 +527,7 @@ export default class Element extends Node {
validate_bindings_foreign() {
this.bindings.forEach(binding => {
if (binding.name !== 'this') {
this.component.error(binding, compiler_errors.invalid_binding_foreign(binding.name));
return this.component.error(binding, compiler_errors.invalid_binding_foreign(binding.name));
}
});
}
@ -541,13 +543,13 @@ export default class Element extends Node {
if (!attribute) return null;
if (!attribute.is_static) {
component.error(attribute, compiler_errors.invalid_type);
return component.error(attribute, compiler_errors.invalid_type);
}
const value = attribute.get_static_value();
if (value === true) {
component.error(attribute, compiler_errors.missing_type);
return component.error(attribute, compiler_errors.missing_type);
}
return value;
@ -562,7 +564,7 @@ export default class Element extends Node {
this.name !== 'textarea' &&
this.name !== 'select'
) {
component.error(binding, compiler_errors.invalid_binding_elements(this.name, 'value'));
return component.error(binding, compiler_errors.invalid_binding_elements(this.name, 'value'));
}
if (this.name === 'select') {
@ -571,45 +573,45 @@ export default class Element extends Node {
);
if (attribute && !attribute.is_static) {
component.error(attribute, compiler_errors.dynamic_multiple_attribute);
return component.error(attribute, compiler_errors.dynamic_multiple_attribute);
}
} else {
check_type_attribute();
}
} else if (name === 'checked' || name === 'indeterminate') {
if (this.name !== 'input') {
component.error(binding, compiler_errors.invalid_binding_elements(this.name, name));
return component.error(binding, compiler_errors.invalid_binding_elements(this.name, name));
}
const type = check_type_attribute();
if (type !== 'checkbox') {
component.error(binding, compiler_errors.invalid_binding_no_checkbox(name, type === 'radio'));
return component.error(binding, compiler_errors.invalid_binding_no_checkbox(name, type === 'radio'));
}
} else if (name === 'group') {
if (this.name !== 'input') {
component.error(binding, compiler_errors.invalid_binding_elements(this.name, 'group'));
return component.error(binding, compiler_errors.invalid_binding_elements(this.name, 'group'));
}
const type = check_type_attribute();
if (type !== 'checkbox' && type !== 'radio') {
component.error(binding, compiler_errors.invalid_binding_element_with('<input type="checkbox"> or <input type="radio">', 'group'));
return component.error(binding, compiler_errors.invalid_binding_element_with('<input type="checkbox"> or <input type="radio">', 'group'));
}
} else if (name === 'files') {
if (this.name !== 'input') {
component.error(binding, compiler_errors.invalid_binding_elements(this.name, 'files'));
return component.error(binding, compiler_errors.invalid_binding_elements(this.name, 'files'));
}
const type = check_type_attribute();
if (type !== 'file') {
component.error(binding, compiler_errors.invalid_binding_element_with('<input type="file">', 'files'));
return component.error(binding, compiler_errors.invalid_binding_element_with('<input type="file">', 'files'));
}
} else if (name === 'open') {
if (this.name !== 'details') {
component.error(binding, compiler_errors.invalid_binding_element_with('<details>', name));
return component.error(binding, compiler_errors.invalid_binding_element_with('<details>', name));
}
} else if (
name === 'currentTime' ||
@ -625,22 +627,22 @@ export default class Element extends Node {
name === 'ended'
) {
if (this.name !== 'audio' && this.name !== 'video') {
component.error(binding, compiler_errors.invalid_binding_element_with('audio> or <video>', name));
return component.error(binding, compiler_errors.invalid_binding_element_with('audio> or <video>', name));
}
} else if (
name === 'videoHeight' ||
name === 'videoWidth'
) {
if (this.name !== 'video') {
component.error(binding, compiler_errors.invalid_binding_element_with('<video>', name));
return component.error(binding, compiler_errors.invalid_binding_element_with('<video>', name));
}
} else if (dimensions.test(name)) {
if (this.name === 'svg' && (name === 'offsetWidth' || name === 'offsetHeight')) {
component.error(binding, compiler_errors.invalid_binding_on(binding.name, `<svg>. Use '${name.replace('offset', 'client')}' instead`));
return component.error(binding, compiler_errors.invalid_binding_on(binding.name, `<svg>. Use '${name.replace('offset', 'client')}' instead`));
} else if (svg.test(this.name)) {
component.error(binding, compiler_errors.invalid_binding_on(binding.name, 'SVG elements'));
return component.error(binding, compiler_errors.invalid_binding_on(binding.name, 'SVG elements'));
} else if (is_void(this.name)) {
component.error(binding, compiler_errors.invalid_binding_on(binding.name, `void elements like <${this.name}>. Use a wrapper element instead`));
return component.error(binding, compiler_errors.invalid_binding_on(binding.name, `void elements like <${this.name}>. Use a wrapper element instead`));
}
} else if (
name === 'textContent' ||
@ -651,12 +653,12 @@ export default class Element extends Node {
);
if (!contenteditable) {
component.error(binding, compiler_errors.missing_contenteditable_attribute);
return component.error(binding, compiler_errors.missing_contenteditable_attribute);
} else if (contenteditable && !contenteditable.is_static) {
component.error(contenteditable, compiler_errors.dynamic_contenteditable_attribute);
return component.error(contenteditable, compiler_errors.dynamic_contenteditable_attribute);
}
} else if (name !== 'this') {
component.error(binding, compiler_errors.invalid_binding(binding.name));
return component.error(binding, compiler_errors.invalid_binding(binding.name));
}
});
}
@ -678,16 +680,16 @@ export default class Element extends Node {
this.handlers.forEach(handler => {
if (handler.modifiers.has('passive') && handler.modifiers.has('preventDefault')) {
component.error(handler, compiler_errors.invalid_event_modifier_combination('passive', 'preventDefault'));
return component.error(handler, compiler_errors.invalid_event_modifier_combination('passive', 'preventDefault'));
}
if (handler.modifiers.has('passive') && handler.modifiers.has('nonpassive')) {
component.error(handler, compiler_errors.invalid_event_modifier_combination('passive', 'nonpassive'));
return component.error(handler, compiler_errors.invalid_event_modifier_combination('passive', 'nonpassive'));
}
handler.modifiers.forEach(modifier => {
if (!valid_modifiers.has(modifier)) {
component.error(handler, compiler_errors.invalid_event_modifier(list(Array.from(valid_modifiers))));
return component.error(handler, compiler_errors.invalid_event_modifier(list(Array.from(valid_modifiers))));
}
if (modifier === 'passive') {
@ -703,7 +705,7 @@ export default class Element extends Node {
if (component.compile_options.legacy && (modifier === 'once' || modifier === 'passive')) {
// TODO this could be supported, but it would need a few changes to
// how event listeners work
component.error(handler, compiler_errors.invalid_event_modifier_legacy(modifier));
return component.error(handler, compiler_errors.invalid_event_modifier_legacy(modifier));
}
});

@ -16,6 +16,7 @@ export default class Head extends Node {
if (info.attributes.length) {
component.error(info.attributes[0], compiler_errors.invalid_attribute_head);
return;
}
this.children = map_children(component, parent, scope, info.children.filter(child => {

@ -42,7 +42,7 @@ export default class InlineComponent extends Node {
/* eslint-disable no-fallthrough */
switch (node.type) {
case 'Action':
component.error(node, compiler_errors.invalid_action);
return component.error(node, compiler_errors.invalid_action);
case 'Attribute':
if (node.name.startsWith('--')) {
@ -59,7 +59,7 @@ export default class InlineComponent extends Node {
break;
case 'Class':
component.error(node, compiler_errors.invalid_class);
return component.error(node, compiler_errors.invalid_class);
case 'EventHandler':
this.handlers.push(new EventHandler(component, this, scope, node));
@ -70,7 +70,7 @@ export default class InlineComponent extends Node {
break;
case 'Transition':
component.error(node, compiler_errors.invalid_transition);
return component.error(node, compiler_errors.invalid_transition);
default:
throw new Error(`Not implemented: ${node.type}`);
@ -95,13 +95,13 @@ export default class InlineComponent extends Node {
this.handlers.forEach(handler => {
handler.modifiers.forEach(modifier => {
if (modifier !== 'once') {
component.error(handler, compiler_errors.invalid_event_modifier_component);
return component.error(handler, compiler_errors.invalid_event_modifier_component);
}
});
});
const children = [];
for (let i=info.children.length - 1; i >= 0; i--) {
for (let i = info.children.length - 1; i >= 0; i--) {
const child = info.children[i];
if (child.type === 'SlotTemplate') {
children.push(child);
@ -117,7 +117,7 @@ export default class InlineComponent extends Node {
};
// transfer attributes
for (let i=child.attributes.length - 1; i >= 0; i--) {
for (let i = child.attributes.length - 1; i >= 0; i--) {
const attribute = child.attributes[i];
if (attribute.type === 'Let') {
slot_template.attributes.push(attribute);

@ -27,7 +27,7 @@ export default class Let extends Node {
walk(info.expression, {
enter(node: Identifier|BasePattern) {
if (!applicable.has(node.type)) {
component.error(node as any, compiler_errors.invalid_let);
return component.error(node as any, compiler_errors.invalid_let);
}
if (node.type === 'Identifier') {

@ -18,17 +18,17 @@ export default class Slot extends Element {
info.attributes.forEach(attr => {
if (attr.type !== 'Attribute' && attr.type !== 'Spread') {
component.error(attr, compiler_errors.invalid_slot_directive);
return component.error(attr, compiler_errors.invalid_slot_directive);
}
if (attr.name === 'name') {
if (attr.value.length !== 1 || attr.value[0].type !== 'Text') {
component.error(attr, compiler_errors.dynamic_slot_name);
return component.error(attr, compiler_errors.dynamic_slot_name);
}
this.slot_name = attr.value[0].data;
if (this.slot_name === 'default') {
component.error(attr, compiler_errors.invalid_slot_name);
return component.error(attr, compiler_errors.invalid_slot_name);
}
}

@ -46,11 +46,11 @@ export default class SlotTemplate extends Node {
if (node.name === 'slot') {
this.slot_attribute = new Attribute(component, this, scope, node);
if (!this.slot_attribute.is_static) {
component.error(node, compiler_errors.invalid_slot_attribute);
return component.error(node, compiler_errors.invalid_slot_attribute);
}
const value = this.slot_attribute.get_static_value();
if (typeof value === 'boolean') {
component.error(node, compiler_errors.invalid_slot_attribute_value_missing);
return component.error(node, compiler_errors.invalid_slot_attribute_value_missing);
}
this.slot_template_name = value as string;
break;
@ -68,7 +68,7 @@ export default class SlotTemplate extends Node {
validate_slot_template_placement() {
if (this.parent.type !== 'InlineComponent') {
this.component.error(this, compiler_errors.invalid_slotted_content_fragment);
return this.component.error(this, compiler_errors.invalid_slotted_content_fragment);
}
}
}

@ -16,11 +16,12 @@ export default class Title extends Node {
if (info.attributes.length > 0) {
component.error(info.attributes[0], compiler_errors.illegal_attribute_title);
return;
}
info.children.forEach(child => {
if (child.type !== 'Text' && child.type !== 'MustacheTag') {
component.error(child, compiler_errors.illegal_structure_title);
return component.error(child, compiler_errors.illegal_structure_title);
}
});

@ -27,6 +27,7 @@ export default class Transition extends Node {
if ((info.intro && parent.intro) || (info.outro && parent.outro)) {
const parent_transition = (parent.intro || parent.outro);
component.error(info, compiler_errors.duplicate_transition(this.directive, parent_transition.directive));
return;
}
this.expression = info.expression

@ -37,7 +37,7 @@ export default class Window extends Node {
const { parts } = flatten_reference(node.expression);
// TODO is this constraint necessary?
component.error(node.expression, compiler_errors.invalid_binding_window(parts));
return component.error(node.expression, compiler_errors.invalid_binding_window(parts));
}
if (!~valid_bindings.indexOf(node.name)) {
@ -48,9 +48,9 @@ export default class Window extends Node {
);
if (match) {
component.error(node, compiler_errors.invalid_binding_on(node.name, '<svelte:window>', ` (did you mean '${match}'?)`));
return component.error(node, compiler_errors.invalid_binding_on(node.name, '<svelte:window>', ` (did you mean '${match}'?)`));
} else {
component.error(node, compiler_errors.invalid_binding_on(node.name, '<svelte:window>', ` — valid bindings are ${list(valid_bindings)}`));
return component.error(node, compiler_errors.invalid_binding_on(node.name, '<svelte:window>', ` — valid bindings are ${list(valid_bindings)}`));
}
}

@ -1,7 +1,7 @@
import { x } from 'code-red';
import { Node, Identifier, Expression } from 'estree';
import { walk } from 'estree-walker';
import is_reference from 'is-reference';
import is_reference, { NodeWithPropertyDefinition } from 'is-reference';
import { clone } from '../../../utils/clone';
export interface Context {
@ -85,7 +85,7 @@ function update_reference(contexts: Context[], n: number, expression: Expression
expression = clone(expression) as Expression;
walk(expression, {
enter(node, parent: Node) {
if (is_reference(node, parent)) {
if (is_reference(node as NodeWithPropertyDefinition, parent as NodeWithPropertyDefinition)) {
this.replace(find_from_context(node as Identifier));
this.skip();
}

@ -17,7 +17,6 @@ import replace_object from '../../utils/replace_object';
import is_contextual from './is_contextual';
import EachBlock from '../EachBlock';
import { clone } from '../../../utils/clone';
import { Node as PeriscopicNode } from 'periscopic';
import compiler_errors from '../../compiler_errors';
type Owner = INode;
@ -86,7 +85,7 @@ export default class Expression {
if (name[0] === '$') {
const store_name = name.slice(1);
if (template_scope.names.has(store_name) || scope.has(store_name)) {
component.error(node, compiler_errors.contextual_store);
return component.error(node, compiler_errors.contextual_store);
}
}
@ -355,7 +354,7 @@ export default class Expression {
// (a or b). In destructuring cases (`[d, e] = [e, d]`) there
// may be more, in which case we need to tack the extra ones
// onto the initial function call
const names = new Set(extract_names(assignee as PeriscopicNode));
const names = new Set(extract_names(assignee as Node));
const traced: Set<string> = new Set();
names.forEach(name => {

@ -71,7 +71,7 @@ export default class Block {
get_unique_name: (name: string) => Identifier;
has_update_method = false;
autofocus: string;
autofocus?: { element_var: string, condition_expression?: any };
constructor(options: BlockOptions) {
this.parent = options.parent;
@ -239,7 +239,11 @@ export default class Block {
}
if (this.autofocus) {
this.chunks.mount.push(b`${this.autofocus}.focus();`);
if (this.autofocus.condition_expression) {
this.chunks.mount.push(b`if (${this.autofocus.condition_expression}) ${this.autofocus.element_var}.focus();`);
} else {
this.chunks.mount.push(b`${this.autofocus.element_var}.focus();`);
}
}
this.render_listeners();

@ -3,12 +3,13 @@ import Component from '../Component';
import Renderer from './Renderer';
import { CompileOptions, CssResult } from '../../interfaces';
import { walk } from 'estree-walker';
import { extract_names, Node as PeriscopicNode, Scope } from 'periscopic';
import { extract_names, Scope } from 'periscopic';
import { invalidate } from './invalidate';
import Block from './Block';
import { ClassDeclaration, FunctionExpression, Node, Statement, ObjectExpression, Expression } from 'estree';
import { ImportDeclaration, ClassDeclaration, FunctionExpression, Node, Statement, ObjectExpression, Expression } from 'estree';
import { apply_preprocessor_sourcemap } from '../../utils/mapped_code';
import { RawSourceMap, DecodedSourceMap } from '@ampproject/remapping/dist/types/types';
import { flatten } from '../../utils/flatten';
export default function dom(
component: Component,
@ -49,11 +50,8 @@ export default function dom(
if (should_add_css) {
body.push(b`
function ${add_css}() {
var style = @element("style");
style.id = "${component.stylesheet.id}-style";
style.textContent = "${styles}";
@append(@_document.head, style);
function ${add_css}(target) {
@append_styles(target, "${component.stylesheet.id}", "${styles}");
}
`);
}
@ -150,7 +148,7 @@ export default function dom(
kind: 'set',
key: { type: 'Identifier', name: prop.export_name },
value: x`function(${prop.name}) {
this.$set({ ${prop.export_name}: ${prop.name} });
this.$$set({ ${prop.export_name}: ${prop.name} });
@flush();
}`
});
@ -176,6 +174,46 @@ export default function dom(
}
});
component.instance_exports_from.forEach(exports_from => {
const import_declaration = {
...exports_from,
type: 'ImportDeclaration',
specifiers: [],
source: exports_from.source
};
component.imports.push(import_declaration as ImportDeclaration);
exports_from.specifiers.forEach(specifier => {
if (component.component_options.accessors) {
const name = component.get_unique_name(specifier.exported.name);
import_declaration.specifiers.push({
...specifier,
type: 'ImportSpecifier',
imported: specifier.local,
local: name
});
accessors.push({
type: 'MethodDefinition',
kind: 'get',
key: { type: 'Identifier', name: specifier.exported.name },
value: x`function() {
return ${name}
}`
});
} else if (component.compile_options.dev) {
accessors.push({
type: 'MethodDefinition',
kind: 'get',
key: { type: 'Identifier', name: specifier.exported.name },
value: x`function() {
throw new @_Error("<${component.tag}>: Props cannot be read directly from the component instance unless compiling with 'accessors: true' or '<svelte:options accessors/>'");
}`
});
}
});
});
if (component.compile_options.dev) {
// checking that expected ones were passed
const expected = props.filter(prop => prop.writable && !prop.initialised);
@ -252,7 +290,7 @@ export default function dom(
// (a or b). In destructuring cases (`[d, e] = [e, d]`) there
// may be more, in which case we need to tack the extra ones
// onto the initial function call
const names = new Set(extract_names(assignee as PeriscopicNode));
const names = new Set(extract_names(assignee as Node));
this.replace(invalidate(renderer, scope, node, names, execution_context === null));
}
@ -485,7 +523,7 @@ export default function dom(
${css.code && b`this.shadowRoot.innerHTML = \`<style>${css.code.replace(/\\/g, '\\\\')}${options.dev ? `\n/*# sourceMappingURL=${css.map.toUrl()} */` : ''}</style>\`;`}
@init(this, { target: this.shadowRoot, props: ${init_props}, customElement: true }, ${definition}, ${has_create_fragment ? 'create_fragment' : 'null'}, ${not_equal}, ${prop_indexes}, ${dirty});
@init(this, { target: this.shadowRoot, props: ${init_props}, customElement: true }, ${definition}, ${has_create_fragment ? 'create_fragment' : 'null'}, ${not_equal}, ${prop_indexes}, null, ${dirty});
${dev_props_check}
@ -532,12 +570,21 @@ export default function dom(
name: options.dev ? '@SvelteComponentDev' : '@SvelteComponent'
};
const optional_parameters = [];
if (should_add_css) {
optional_parameters.push(add_css);
} else if (dirty) {
optional_parameters.push(x`null`);
}
if (dirty) {
optional_parameters.push(dirty);
}
const declaration = b`
class ${name} extends ${superclass} {
constructor(options) {
super(${options.dev && 'options'});
${should_add_css && b`if (!@_document.getElementById("${component.stylesheet.id}-style")) ${add_css}();`}
@init(this, options, ${definition}, ${has_create_fragment ? 'create_fragment' : 'null'}, ${not_equal}, ${prop_indexes}, ${dirty});
@init(this, options, ${definition}, ${has_create_fragment ? 'create_fragment' : 'null'}, ${not_equal}, ${prop_indexes}, ${optional_parameters});
${options.dev && b`@dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "${name.name}", options, id: create_fragment.name });`}
${dev_props_check}
@ -550,18 +597,5 @@ export default function dom(
body.push(declaration);
}
return { js: flatten(body, []), css };
}
function flatten(nodes: any[], target: any[]) {
for (let i = 0; i < nodes.length; i += 1) {
const node = nodes[i];
if (Array.isArray(node)) {
flatten(node, target);
} else {
target.push(node);
}
}
return target;
return { js: flatten(body), css };
}

@ -346,7 +346,7 @@ export default class EachBlockWrapper extends Wrapper {
this.else.fragment.render(this.else.block, null, x`#nodes` as Identifier);
}
this.context_props = this.node.contexts.map(prop => b`child_ctx[${renderer.context_lookup.get(prop.key.name).index}] = ${prop.default_modifier(prop.modifier(x`list[i]`), name => renderer.context_lookup.has(name) ? x`child_ctx[${renderer.context_lookup.get(name).index}]`: { type: 'Identifier', name })};`);
this.context_props = this.node.contexts.map(prop => b`child_ctx[${renderer.context_lookup.get(prop.key.name).index}] = ${prop.default_modifier(prop.modifier(x`list[i]`), name => renderer.context_lookup.has(name) ? x`child_ctx[${renderer.context_lookup.get(name).index}]` : { type: 'Identifier', name })};`);
if (this.node.has_binding) this.context_props.push(b`child_ctx[${renderer.context_lookup.get(this.vars.each_block_value.name).index}] = list;`);
if (this.node.has_binding || this.node.has_index_binding || this.node.index) this.context_props.push(b`child_ctx[${renderer.context_lookup.get(this.index_name.name).index}] = i;`);

@ -132,7 +132,7 @@ export default class AttributeWrapper extends BaseAttributeWrapper {
`);
} else if (this.is_src) {
block.chunks.hydrate.push(
b`if (${element.var}.src !== ${init}) ${method}(${element.var}, "${name}", ${this.last});`
b`if (!@src_url_equal(${element.var}.src, ${init})) ${method}(${element.var}, "${name}", ${this.last});`
);
updater = b`${method}(${element.var}, "${name}", ${should_cache ? this.last : value});`;
} else if (property_name) {
@ -169,8 +169,11 @@ export default class AttributeWrapper extends BaseAttributeWrapper {
}
// special case autofocus. has to be handled in a bit of a weird way
if (this.node.is_true && name === 'autofocus') {
block.autofocus = element.var;
if (name === 'autofocus') {
block.autofocus = {
element_var: element.var,
condition_expression: this.node.is_true ? undefined : value
};
}
}
@ -193,7 +196,7 @@ export default class AttributeWrapper extends BaseAttributeWrapper {
if (should_cache) {
condition = this.is_src
? x`${condition} && (${element.var}.src !== (${last} = ${value}))`
? x`${condition} && (!@src_url_equal(${element.var}.src, (${last} = ${value})))`
: x`${condition} && (${last} !== (${last} = ${value}))`;
}

@ -670,10 +670,10 @@ export default class ElementWrapper extends Wrapper {
}
block.chunks.mount.push(b`
if (${data}.multiple) @select_options(${this.var}, ${data}.value);
(${data}.multiple ? @select_options : @select_option)(${this.var}, ${data}.value);
`);
block.chunks.update.push(b`
if (${block.renderer.dirty(Array.from(dependencies))} && ${data}.multiple) @select_options(${this.var}, ${data}.value);
if (${block.renderer.dirty(Array.from(dependencies))}) (${data}.multiple ? @select_options : @select_option)(${this.var}, ${data}.value);;
`);
} else if (this.node.name === 'input' && this.attributes.find(attr => attr.node.name === 'value')) {
const type = this.node.get_static_attribute_value('type');
@ -688,6 +688,12 @@ export default class ElementWrapper extends Wrapper {
`);
}
}
if (['button', 'input', 'keygen', 'select', 'textarea'].includes(this.node.name)) {
block.chunks.mount.push(b`
if (${this.var}.autofocus) ${this.var}.focus();
`);
}
}
add_transitions(
@ -755,7 +761,7 @@ export default class ElementWrapper extends Wrapper {
intro_block = b`
@add_render_callback(() => {
if (${outro_name}) ${outro_name}.end(1);
if (!${intro_name}) ${intro_name} = @create_in_transition(${this.var}, ${fn}, ${snippet});
${intro_name} = @create_in_transition(${this.var}, ${fn}, ${snippet});
${intro_name}.start();
});
`;

@ -107,7 +107,7 @@ export default class SlotWrapper extends Wrapper {
if (spread_dynamic_dependencies.size) {
get_slot_spread_changes_fn = renderer.component.get_unique_name(`get_${sanitize(slot_name)}_slot_spread_changes`);
renderer.blocks.push(b`
const ${get_slot_spread_changes_fn} = #dirty => ${renderer.dirty(Array.from(spread_dynamic_dependencies))} > 0 ? -1 : 0;
const ${get_slot_spread_changes_fn} = #dirty => ${renderer.dirty(Array.from(spread_dynamic_dependencies))};
`);
}
} else {
@ -168,27 +168,41 @@ export default class SlotWrapper extends Wrapper {
if (block.has_outros) {
condition = x`!#current || ${condition}`;
}
let dirty = x`#dirty`;
if (block.has_outros) {
dirty = x`!#current ? ${renderer.get_initial_dirty()} : ${dirty}`;
// conditions to treat everything as dirty
const all_dirty_conditions = [
get_slot_spread_changes_fn ? x`${get_slot_spread_changes_fn}(#dirty)` : null,
block.has_outros ? x`!#current` : null
].filter(Boolean);
const all_dirty_condition = all_dirty_conditions.length ? all_dirty_conditions.reduce((condition1, condition2) => x`${condition1} || ${condition2}`) : null;
let slot_update;
if (all_dirty_condition) {
const dirty = x`${all_dirty_condition} ? @get_all_dirty_from_scope(${renderer.reference('$$scope')}) : @get_slot_changes(${slot_definition}, ${renderer.reference('$$scope')}, #dirty, ${get_slot_changes_fn})`;
slot_update = b`
if (${slot}.p && ${condition}) {
@update_slot_base(${slot}, ${slot_definition}, #ctx, ${renderer.reference('$$scope')}, ${dirty}, ${get_slot_context_fn});
}
`;
} else {
slot_update = b`
if (${slot}.p && ${condition}) {
@update_slot(${slot}, ${slot_definition}, #ctx, ${renderer.reference('$$scope')}, #dirty, ${get_slot_changes_fn}, ${get_slot_context_fn});
}
`;
}
const slot_update = get_slot_spread_changes_fn ? b`
if (${slot}.p && ${condition}) {
@update_slot_spread(${slot}, ${slot_definition}, #ctx, ${renderer.reference('$$scope')}, ${dirty}, ${get_slot_changes_fn}, ${get_slot_spread_changes_fn}, ${get_slot_context_fn});
}
` : b`
if (${slot}.p && ${condition}) {
@update_slot(${slot}, ${slot_definition}, #ctx, ${renderer.reference('$$scope')}, ${dirty}, ${get_slot_changes_fn}, ${get_slot_context_fn});
}
`;
let fallback_condition = renderer.dirty(fallback_dynamic_dependencies);
let fallback_dirty = x`#dirty`;
if (block.has_outros) {
fallback_condition = x`!#current || ${fallback_condition}`;
fallback_dirty = x`!#current ? ${renderer.get_initial_dirty()} : ${fallback_dirty}`;
}
const fallback_update = has_fallback && fallback_dynamic_dependencies.length > 0 && b`
if (${slot_or_fallback} && ${slot_or_fallback}.p && ${fallback_condition}) {
${slot_or_fallback}.p(#ctx, ${dirty});
${slot_or_fallback}.p(#ctx, ${fallback_dirty});
}
`;

@ -131,7 +131,7 @@ export default function(node: Element, renderer: Renderer, options: RenderOption
const value = get_attribute_expression(value_attribute);
const type = node.get_static_attribute_value('type');
const bound = expression.node;
const condition = type === 'checkbox' ? x`~${bound}.indexOf(${value})`: x`${value} === ${bound}`;
const condition = type === 'checkbox' ? x`~${bound}.indexOf(${value})` : x`${value} === ${bound}`;
renderer.add_expression(x`${condition} ? @add_attribute("checked", true, 1) : ""`);
}
} else if (contenteditable && (name === 'textContent' || name === 'innerHTML')) {

@ -6,7 +6,7 @@ import Renderer from './Renderer';
import { INode as TemplateNode } from '../nodes/interfaces'; // TODO
import Text from '../nodes/Text';
import { LabeledStatement, Statement, Node } from 'estree';
import { Node as PeriscopicNode , extract_names } from 'periscopic';
import { extract_names } from 'periscopic';
import { walk } from 'estree-walker';
import { invalidate } from '../render_dom/invalidate';
@ -90,7 +90,7 @@ export default function ssr(
if (node.type === 'AssignmentExpression' || node.type === 'UpdateExpression') {
const assignee = node.type === 'AssignmentExpression' ? node.left : node.argument;
const names = new Set(extract_names(assignee as PeriscopicNode));
const names = new Set(extract_names(assignee as Node));
const to_invalidate = new Set<string>();
for (const name of names) {

@ -1,11 +1,11 @@
import { Node } from 'estree';
import is_reference from 'is-reference';
import is_reference, { NodeWithPropertyDefinition } from 'is-reference';
export default function is_used_as_reference(
node: Node,
parent: Node
): boolean {
if (!is_reference(node, parent)) {
if (!is_reference(node as NodeWithPropertyDefinition, parent as NodeWithPropertyDefinition)) {
return false;
}
if (!parent) {

@ -1,8 +1,8 @@
import { Node } from 'estree';
import { Node as PeriscopicNode, analyze, Scope, extract_names, extract_identifiers } from 'periscopic';
import { analyze, Scope, extract_names, extract_identifiers } from 'periscopic';
export function create_scopes(expression: Node) {
return analyze(expression as PeriscopicNode);
return analyze(expression);
}
export { Scope, extract_names, extract_identifiers };

@ -24,6 +24,12 @@ export interface MustacheTag extends BaseNode {
expression: Node;
}
export interface Comment extends BaseNode {
type: 'Comment';
data: string;
ignores: string[];
}
export type DirectiveType = 'Action'
| 'Animation'
| 'Binding'
@ -53,7 +59,8 @@ export type TemplateNode = Text
| MustacheTag
| BaseNode
| Directive
| Transition;
| Transition
| Comment;
export interface Parser {
readonly template: string;
@ -117,6 +124,7 @@ export interface CompileOptions {
name?: string;
filename?: string;
generate?: 'dom' | 'ssr' | false;
errorMode?: 'throw' | 'warn';
varsReport?: 'full' | 'strict' | false;
sourcemap?: object | string;

@ -290,16 +290,24 @@ export default function mustache(parser: Parser) {
const await_block_shorthand = type === 'AwaitBlock' && parser.eat('then');
if (await_block_shorthand) {
parser.require_whitespace();
block.value = read_context(parser);
parser.allow_whitespace();
if (parser.match_regex(/\s*}/)) {
parser.allow_whitespace();
} else {
parser.require_whitespace();
block.value = read_context(parser);
parser.allow_whitespace();
}
}
const await_block_catch_shorthand = !await_block_shorthand && type === 'AwaitBlock' && parser.eat('catch');
if (await_block_catch_shorthand) {
parser.require_whitespace();
block.error = read_context(parser);
parser.allow_whitespace();
if (parser.match_regex(/\s*}/)) {
parser.allow_whitespace();
} else {
parser.require_whitespace();
block.error = read_context(parser);
parser.allow_whitespace();
}
}
parser.eat('}', true);

@ -7,6 +7,7 @@ import { is_void } from '../../utils/names';
import { Parser } from '../index';
import { Directive, DirectiveType, TemplateNode, Text, MustacheTag } from '../../interfaces';
import fuzzymatch from '../../utils/fuzzymatch';
import { extract_svelte_ignore } from '../../utils/extract_svelte_ignore';
import parser_errors from '../errors';
// eslint-disable-next-line no-useless-escape
@ -65,7 +66,8 @@ export default function tag(parser: Parser) {
start,
end: parser.index,
type: 'Comment',
data
data,
ignores: extract_svelte_ignore(data)
});
return;
@ -461,6 +463,15 @@ function get_directive_type(name: string): DirectiveType {
function read_attribute_value(parser: Parser) {
const quote_mark = parser.eat("'") ? "'" : parser.eat('"') ? '"' : null;
if (quote_mark && parser.eat(quote_mark)) {
return [{
start: parser.index - 1,
end: parser.index - 1,
type: 'Text',
raw: '',
data: ''
}];
}
const regex = (
quote_mark === "'" ? /'/ :
@ -485,10 +496,10 @@ function read_sequence(parser: Parser, done: () => boolean): TemplateNode[] {
const chunks: TemplateNode[] = [];
function flush() {
function flush(end: number) {
if (current_chunk.raw) {
current_chunk.data = decode_character_references(current_chunk.raw);
current_chunk.end = parser.index;
current_chunk.end = end;
chunks.push(current_chunk);
}
}
@ -497,10 +508,10 @@ function read_sequence(parser: Parser, done: () => boolean): TemplateNode[] {
const index = parser.index;
if (done()) {
flush();
flush(parser.index);
return chunks;
} else if (parser.eat('{')) {
flush();
flush(parser.index - 1);
parser.allow_whitespace();
const expression = read_expression(parser);

@ -124,7 +124,7 @@ function parse_tag_attributes(str: string) {
.filter(Boolean)
.reduce((attrs, attr) => {
const i = attr.indexOf('=');
const [key, value] = i > 0 ? [attr.slice(0, i), attr.slice(i+1)] : [attr];
const [key, value] = i > 0 ? [attr.slice(0, i), attr.slice(i + 1)] : [attr];
const [, unquoted] = (value && value.match(/^['"](.*)['"]$/)) || [];
return { ...attrs, [key]: unquoted ?? value ?? true };

@ -32,7 +32,7 @@ function calculate_replacements(
get_replacement(...match).then(
replacement => {
const matched_string = match[0];
const offset = match[match.length-2];
const offset = match[match.length - 2];
return ({ offset, length: matched_string.length, replacement });
}

@ -7,8 +7,8 @@ export function clone(val) {
let k, out, tmp;
if (Array.isArray(val)) {
out = Array(k=val.length);
while (k--) out[k] = (tmp=val[k]) && typeof tmp === 'object' ? clone(tmp) : tmp;
out = Array(k = val.length);
while (k--) out[k] = (tmp = val[k]) && typeof tmp === 'object' ? clone(tmp) : tmp;
return out;
}
@ -23,7 +23,7 @@ export function clone(val) {
writable: true
});
} else if (typeof val[k] !== 'function') { // MODIFICATION: skip functions
out[k] = (tmp=val[k]) && typeof tmp === 'object' ? clone(tmp) : tmp;
out[k] = (tmp = val[k]) && typeof tmp === 'object' ? clone(tmp) : tmp;
}
}
return out;

@ -0,0 +1,34 @@
import { TemplateNode } from '../interfaces';
import { flatten } from './flatten';
const pattern = /^\s*svelte-ignore\s+([\s\S]+)\s*$/m;
export function extract_svelte_ignore(text: string): string[] {
const match = pattern.exec(text);
return match ? match[1].split(/[^\S]/).map(x => x.trim()).filter(Boolean) : [];
}
export function extract_svelte_ignore_from_comments<Node extends { leadingComments?: Array<{value: string}> }>(node: Node): string[] {
return flatten((node.leadingComments || []).map(comment => extract_svelte_ignore(comment.value)));
}
export function extract_ignores_above_position(position: number, template_nodes: TemplateNode[]): string[] {
const previous_node_idx = template_nodes.findIndex(child => child.end === position);
if (previous_node_idx === -1) {
return [];
}
for (let i = previous_node_idx; i >= 0; i--) {
const node = template_nodes[i];
if (node.type !== 'Comment' && node.type !== 'Text') {
return [];
}
if (node.type === 'Comment') {
if (node.ignores.length) {
return node.ignores;
}
}
}
return [];
}

@ -0,0 +1,14 @@
export function flatten<T>(nodes: T[][], target?: T[]): T[];
export function flatten<T>(nodes: T[], target?: T[]): T[];
export function flatten(nodes: any[], target: any[] = []): any[] {
for (let i = 0; i < nodes.length; i += 1) {
const node = nodes[i];
if (Array.isArray(node)) {
flatten(node, target);
} else {
target.push(node);
}
}
return target;
}

@ -251,6 +251,11 @@ export function combine_sourcemaps(
if (!map.file) delete map.file; // skip optional field `file`
// When source maps are combined and the leading map is empty, sources is not set.
// Add the filename to the empty array in this case.
// Further improvements to remapping may help address this as well https://github.com/ampproject/remapping/issues/116
if (!map.sources.length) map.sources = [filename];
return map;
}
@ -295,8 +300,8 @@ export function apply_preprocessor_sourcemap(filename: string, svelte_map: Sourc
export function parse_attached_sourcemap(processed: Processed, tag_name: 'script' | 'style'): void {
const r_in = '[#@]\\s*sourceMappingURL\\s*=\\s*(\\S*)';
const regex = (tag_name == 'script')
? new RegExp('(?://'+r_in+')|(?:/\\*'+r_in+'\\s*\\*/)$')
: new RegExp('/\\*'+r_in+'\\s*\\*/$');
? new RegExp('(?://' + r_in + ')|(?:/\\*' + r_in + '\\s*\\*/)$')
: new RegExp('/\\*' + r_in + '\\s*\\*/$');
function log_warning(message) {
// code_start: help to find preprocessor
const code_start = processed.code.length < 100 ? processed.code : (processed.code.slice(0, 100) + ' [...]');

@ -7,6 +7,7 @@ export {
afterUpdate,
setContext,
getContext,
getAllContexts,
hasContext,
tick,
createEventDispatcher,

@ -38,6 +38,7 @@ interface T$$ {
on_destroy: any[];
skip_bound: boolean;
on_disconnect: any[];
root:Element|ShadowRoot
}
export function bind(component, name, callback) {
@ -103,7 +104,7 @@ function make_dirty(component, i) {
component.$$.dirty[(i / 31) | 0] |= (1 << (i % 31));
}
export function init(component, options, instance, create_fragment, not_equal, props, dirty = [-1]) {
export function init(component, options, instance, create_fragment, not_equal, props, append_styles, dirty = [-1]) {
const parent_component = current_component;
set_current_component(component);
@ -128,9 +129,12 @@ export function init(component, options, instance, create_fragment, not_equal, p
// everything else
callbacks: blank_object(),
dirty,
skip_bound: false
skip_bound: false,
root: options.target || parent_component.$$.root
};
append_styles && append_styles($$.root);
let ready = false;
$$.ctx = instance

@ -1,4 +1,4 @@
import { custom_event, append, insert, detach, listen, attr } from './dom';
import { custom_event, append, append_hydration, insert, insert_hydration, detach, listen, attr } from './dom';
import { SvelteComponent } from './Component';
export function dispatch_dev<T=any>(type: string, detail?: T) {
@ -10,11 +10,21 @@ export function append_dev(target: Node, node: Node) {
append(target, node);
}
export function append_hydration_dev(target: Node, node: Node) {
dispatch_dev('SvelteDOMInsert', { target, node });
append_hydration(target, node);
}
export function insert_dev(target: Node, node: Node, anchor?: Node) {
dispatch_dev('SvelteDOMInsert', { target, node, anchor });
insert(target, node, anchor);
}
export function insert_hydration_dev(target: Node, node: Node, anchor?: Node) {
dispatch_dev('SvelteDOMInsert', { target, node, anchor });
insert_hydration(target, node, anchor);
}
export function detach_dev(node: Node) {
dispatch_dev('SvelteDOMRemove', { node });
detach(node);
@ -105,7 +115,7 @@ export interface SvelteComponentDev {
[accessor: string]: any;
}
interface IComponentOptions<Props extends Record<string, any> = Record<string, any>> {
target: Element;
target: Element|ShadowRoot;
anchor?: Element;
props?: Props;
context?: Map<any, any>;

@ -14,7 +14,7 @@ export function end_hydrating() {
type NodeEx = Node & {
claim_order?: number,
hydrate_init? : true,
actual_end_child?: Node,
actual_end_child?: NodeEx,
childNodes: NodeListOf<NodeEx>,
};
@ -37,8 +37,20 @@ function init_hydrate(target: NodeEx) {
type NodeEx2 = NodeEx & {claim_order: number};
// We know that all children have claim_order values since the unclaimed have been detached
const children = target.childNodes as NodeListOf<NodeEx2>;
// We know that all children have claim_order values since the unclaimed have been detached if target is not <head>
let children: ArrayLike<NodeEx2> = target.childNodes as NodeListOf<NodeEx2>;
// If target is <head>, there may be children without claim_order
if (target.nodeName === 'HEAD') {
const myChildren = [];
for (let i = 0; i < children.length; i++) {
const node = children[i];
if (node.claim_order !== undefined) {
myChildren.push(node);
}
}
children = myChildren;
}
/*
* Reorder claimed children optimally.
@ -70,7 +82,8 @@ function init_hydrate(target: NodeEx) {
// Find the largest subsequence length such that it ends in a value less than our current value
// upper_bound returns first greater value, so we subtract one
const seqLen = upper_bound(1, longest + 1, idx => children[m[idx]].claim_order, current) - 1;
// with fast path for when we are on the current longest subsequence
const seqLen = ((longest > 0 && children[m[longest]].claim_order <= current) ? longest + 1 : upper_bound(1, longest, idx => children[m[idx]].claim_order, current)) - 1;
p[i] = m[seqLen] + 1;
@ -112,15 +125,63 @@ function init_hydrate(target: NodeEx) {
}
}
export function append(target: NodeEx, node: NodeEx) {
export function append(target: Node, node: Node) {
target.appendChild(node);
}
export function append_styles(
target: Node,
style_sheet_id: string,
styles: string
) {
const append_styles_to = get_root_for_style(target);
if (!append_styles_to.getElementById(style_sheet_id)) {
const style = element('style');
style.id = style_sheet_id;
style.textContent = styles;
append_stylesheet(append_styles_to, style);
}
}
export function get_root_for_style(node: Node): ShadowRoot | Document {
if (!node) return document;
const root = node.getRootNode ? node.getRootNode() : node.ownerDocument;
if ((root as ShadowRoot).host) {
return root as ShadowRoot;
}
return document;
}
export function append_empty_stylesheet(node: Node) {
const style_element = element('style') as HTMLStyleElement;
append_stylesheet(get_root_for_style(node), style_element);
return style_element;
}
function append_stylesheet(node: ShadowRoot | Document, style: HTMLStyleElement) {
append((node as Document).head || node, style);
}
export function append_hydration(target: NodeEx, node: NodeEx) {
if (is_hydrating) {
init_hydrate(target);
if ((target.actual_end_child === undefined) || ((target.actual_end_child !== null) && (target.actual_end_child.parentElement !== target))) {
target.actual_end_child = target.firstChild;
}
// Skip nodes of undefined ordering
while ((target.actual_end_child !== null) && (target.actual_end_child.claim_order === undefined)) {
target.actual_end_child = target.actual_end_child.nextSibling;
}
if (node !== target.actual_end_child) {
target.insertBefore(node, target.actual_end_child);
// We only insert if the ordering of this node should be modified or the parent node is not target
if (node.claim_order !== undefined || node.parentNode !== target) {
target.insertBefore(node, target.actual_end_child);
}
} else {
target.actual_end_child = node.nextSibling;
}
@ -129,9 +190,13 @@ export function append(target: NodeEx, node: NodeEx) {
}
}
export function insert(target: NodeEx, node: NodeEx, anchor?: NodeEx) {
export function insert(target: Node, node: Node, anchor?: Node) {
target.insertBefore(node, anchor || null);
}
export function insert_hydration(target: NodeEx, node: NodeEx, anchor?: NodeEx) {
if (is_hydrating && !anchor) {
append(target, node);
append_hydration(target, node);
} else if (node.parentNode !== target || node.nextSibling != anchor) {
target.insertBefore(node, anchor || null);
}
@ -304,11 +369,15 @@ export function children(element: Element) {
return Array.from(element.childNodes);
}
function claim_node<R extends ChildNodeEx>(nodes: ChildNodeArray, predicate: (node: ChildNodeEx) => node is R, processNode: (node: ChildNodeEx) => void, createNode: () => R, dontUpdateLastIndex: boolean = false) {
// Try to find nodes in an order such that we lengthen the longest increasing subsequence
function init_claim_info(nodes: ChildNodeArray) {
if (nodes.claim_info === undefined) {
nodes.claim_info = {last_index: 0, total_claimed: 0};
}
}
function claim_node<R extends ChildNodeEx>(nodes: ChildNodeArray, predicate: (node: ChildNodeEx) => node is R, processNode: (node: ChildNodeEx) => ChildNodeEx | undefined, createNode: () => R, dontUpdateLastIndex: boolean = false) {
// Try to find nodes in an order such that we lengthen the longest increasing subsequence
init_claim_info(nodes);
const resultNode = (() => {
// We first try to find an element after the previous one
@ -316,9 +385,13 @@ function claim_node<R extends ChildNodeEx>(nodes: ChildNodeArray, predicate: (no
const node = nodes[i];
if (predicate(node)) {
processNode(node);
const replacement = processNode(node);
nodes.splice(i, 1);
if (replacement === undefined) {
nodes.splice(i, 1);
} else {
nodes[i] = replacement;
}
if (!dontUpdateLastIndex) {
nodes.claim_info.last_index = i;
}
@ -333,12 +406,16 @@ function claim_node<R extends ChildNodeEx>(nodes: ChildNodeArray, predicate: (no
const node = nodes[i];
if (predicate(node)) {
processNode(node);
const replacement = processNode(node);
nodes.splice(i, 1);
if (replacement === undefined) {
nodes.splice(i, 1);
} else {
nodes[i] = replacement;
}
if (!dontUpdateLastIndex) {
nodes.claim_info.last_index = i;
} else {
} else if (replacement === undefined) {
// Since we spliced before the last_index, we decrease it
nodes.claim_info.last_index--;
}
@ -368,6 +445,7 @@ export function claim_element(nodes: ChildNodeArray, name: string, attributes: {
}
}
remove.forEach(v => node.removeAttribute(v));
return undefined;
},
() => svg ? svg_element(name as keyof SVGElementTagNameMap) : element(name as keyof HTMLElementTagNameMap)
);
@ -378,7 +456,14 @@ export function claim_text(nodes: ChildNodeArray, data) {
nodes,
(node: ChildNode): node is Text => node.nodeType === 3,
(node: Text) => {
node.data = '' + data;
const dataStr = '' + data;
if (node.data.startsWith(dataStr)) {
if (node.data.length !== dataStr.length) {
return node.splitText(dataStr.length);
}
} else {
node.data = dataStr;
}
},
() => text(data),
true // Text nodes should not update last index since it is likely not worth it to eliminate an increasing subsequence of actual elements
@ -404,12 +489,19 @@ export function claim_html_tag(nodes) {
const start_index = find_comment(nodes, 'HTML_TAG_START', 0);
const end_index = find_comment(nodes, 'HTML_TAG_END', start_index);
if (start_index === end_index) {
return new HtmlTag();
return new HtmlTagHydration();
}
init_claim_info(nodes);
const html_tag_nodes = nodes.splice(start_index, end_index + 1);
detach(html_tag_nodes[0]);
detach(html_tag_nodes[html_tag_nodes.length - 1]);
return new HtmlTag(html_tag_nodes.slice(1, html_tag_nodes.length - 1));
const claimed_nodes = html_tag_nodes.slice(1, html_tag_nodes.length - 1);
for (const n of claimed_nodes) {
n.claim_order = nodes.claim_info.total_claimed;
nodes.claim_info.total_claimed += 1;
}
return new HtmlTagHydration(claimed_nodes);
}
export function set_data(text, data) {
@ -539,7 +631,7 @@ export function custom_event<T=any>(type: string, detail?: T, bubbles: boolean =
}
export function query_selector_all(selector: string, parent: HTMLElement = document.body) {
return Array.from(parent.querySelectorAll(selector));
return Array.from(parent.querySelectorAll(selector)) as ChildNodeArray;
}
export class HtmlTag {
@ -547,27 +639,24 @@ export class HtmlTag {
e: HTMLElement;
// html tag nodes
n: ChildNode[];
// hydration claimed nodes
l: ChildNode[] | void;
// target
t: HTMLElement;
// anchor
a: HTMLElement;
constructor(claimed_nodes?: ChildNode[]) {
constructor() {
this.e = this.n = null;
this.l = claimed_nodes;
}
c(html: string) {
this.h(html);
}
m(html: string, target: HTMLElement, anchor: HTMLElement = null) {
if (!this.e) {
this.e = element(target.nodeName as keyof HTMLElementTagNameMap);
this.t = target;
if (this.l) {
this.n = this.l;
} else {
this.h(html);
}
this.c(html);
}
this.i(anchor);
@ -595,6 +684,29 @@ export class HtmlTag {
}
}
export class HtmlTagHydration extends HtmlTag {
// hydration claimed nodes
l: ChildNode[] | void;
constructor(claimed_nodes?: ChildNode[]) {
super();
this.e = this.n = null;
this.l = claimed_nodes;
}
c(html: string) {
if (this.l) {
this.n = this.l;
} else {
super.c(html);
}
}
i(anchor) {
for (let i = 0; i < this.n.length; i += 1) {
insert_hydration(this.t, this.n[i], anchor);
}
}
}
export function attribute_to_object(attributes: NamedNodeMap) {
const result = {};
for (const attribute of attributes) {

@ -54,6 +54,10 @@ export function getContext<T>(key): T {
return get_current_component().$$.context.get(key);
}
export function getAllContexts<T extends Map<any, any> = Map<any, any>>(): T {
return get_current_component().$$.context;
}
export function hasContext(key): boolean {
return get_current_component().$$.context.has(key);
}

@ -1,4 +1,4 @@
import { element } from './dom';
import { append_empty_stylesheet, get_root_for_style } from './dom';
import { raf } from './environment';
interface ExtendedDoc extends Document {
@ -29,9 +29,9 @@ export function create_rule(node: Element & ElementCSSInlineStyle, a: number, b:
const rule = keyframes + `100% {${fn(b, 1 - b)}}\n}`;
const name = `__svelte_${hash(rule)}_${uid}`;
const doc = node.ownerDocument as ExtendedDoc;
const doc = get_root_for_style(node) as ExtendedDoc;
active_docs.add(doc);
const stylesheet = doc.__svelte_stylesheet || (doc.__svelte_stylesheet = doc.head.appendChild(element('style') as HTMLStyleElement).sheet as CSSStyleSheet);
const stylesheet = doc.__svelte_stylesheet || (doc.__svelte_stylesheet = append_empty_stylesheet(node).sheet as CSSStyleSheet);
const current_rules = doc.__svelte_rules || (doc.__svelte_rules = {});
if (!current_rules[name]) {

@ -144,6 +144,7 @@ export function create_in_transition(node: Element & ElementCSSInlineStyle, fn:
start() {
if (started) return;
started = true;
delete_rule(node);
if (is_function(config)) {

@ -40,6 +40,16 @@ export function safe_not_equal(a, b) {
return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function');
}
let src_url_equal_anchor;
export function src_url_equal(element_src, url) {
if (!src_url_equal_anchor) {
src_url_equal_anchor = document.createElement('a');
}
src_url_equal_anchor.href = url;
return element_src === src_url_equal_anchor.href;
}
export function not_equal(a, b) {
return a != a ? b == b : a !== b;
}
@ -79,7 +89,7 @@ export function create_slot(definition, ctx, $$scope, fn) {
}
}
export function get_slot_context(definition, ctx, $$scope, fn) {
function get_slot_context(definition, ctx, $$scope, fn) {
return definition[1] && fn
? assign($$scope.ctx.slice(), definition[1](fn(ctx)))
: $$scope.ctx;
@ -109,20 +119,28 @@ export function get_slot_changes(definition, $$scope, dirty, fn) {
return $$scope.dirty;
}
export function update_slot(slot, slot_definition, ctx, $$scope, dirty, get_slot_changes_fn, get_slot_context_fn) {
const slot_changes = get_slot_changes(slot_definition, $$scope, dirty, get_slot_changes_fn);
export function update_slot_base(slot, slot_definition, ctx, $$scope, slot_changes, get_slot_context_fn) {
if (slot_changes) {
const slot_context = get_slot_context(slot_definition, ctx, $$scope, get_slot_context_fn);
slot.p(slot_context, slot_changes);
}
}
export function update_slot_spread(slot, slot_definition, ctx, $$scope, dirty, get_slot_changes_fn, get_slot_spread_changes_fn, get_slot_context_fn) {
const slot_changes = get_slot_spread_changes_fn(dirty) | get_slot_changes(slot_definition, $$scope, dirty, get_slot_changes_fn);
if (slot_changes) {
const slot_context = get_slot_context(slot_definition, ctx, $$scope, get_slot_context_fn);
slot.p(slot_context, slot_changes);
export function update_slot(slot, slot_definition, ctx, $$scope, dirty, get_slot_changes_fn, get_slot_context_fn) {
const slot_changes = get_slot_changes(slot_definition, $$scope, dirty, get_slot_changes_fn);
update_slot_base(slot, slot_definition, ctx, $$scope, slot_changes, get_slot_context_fn);
}
export function get_all_dirty_from_scope($$scope) {
if ($$scope.ctx.length > 32) {
const dirty = [];
const length = $$scope.ctx.length / 32;
for (let i = 0; i < length; i++) {
dirty[i] = -1;
}
return dirty;
}
return -1;
}
export function exclude_internal_props(props) {
@ -159,7 +177,7 @@ export function null_to_empty(value) {
return value == null ? '' : value;
}
export function set_store_value(store, ret, value = ret) {
export function set_store_value(store, ret, value) {
store.set(value);
return ret;
}

@ -1,6 +1,7 @@
export {
setContext,
getContext,
getAllContexts,
hasContext,
tick,
createEventDispatcher,

@ -63,17 +63,16 @@ export function readable<T>(value?: T, start?: StartStopNotifier<T>): Readable<T
*/
export function writable<T>(value?: T, start: StartStopNotifier<T> = noop): Writable<T> {
let stop: Unsubscriber;
const subscribers: Array<SubscribeInvalidateTuple<T>> = [];
const subscribers: Set<SubscribeInvalidateTuple<T>> = new Set();
function set(new_value: T): void {
if (safe_not_equal(value, new_value)) {
value = new_value;
if (stop) { // store is ready
const run_queue = !subscriber_queue.length;
for (let i = 0; i < subscribers.length; i += 1) {
const s = subscribers[i];
s[1]();
subscriber_queue.push(s, value);
for (const subscriber of subscribers) {
subscriber[1]();
subscriber_queue.push(subscriber, value);
}
if (run_queue) {
for (let i = 0; i < subscriber_queue.length; i += 2) {
@ -91,18 +90,15 @@ export function writable<T>(value?: T, start: StartStopNotifier<T> = noop): Writ
function subscribe(run: Subscriber<T>, invalidate: Invalidator<T> = noop): Unsubscriber {
const subscriber: SubscribeInvalidateTuple<T> = [run, invalidate];
subscribers.push(subscriber);
if (subscribers.length === 1) {
subscribers.add(subscriber);
if (subscribers.size === 1) {
stop = start(set) || noop;
}
run(value);
return () => {
const index = subscribers.indexOf(subscriber);
if (index !== -1) {
subscribers.splice(index, 1);
}
if (subscribers.length === 0) {
subscribers.delete(subscriber);
if (subscribers.size === 0) {
stop();
stop = null;
}

@ -0,0 +1,27 @@
export default {
warnings: [
{
code: 'css-unused-selector',
end: {
character: 111,
column: 21,
line: 8
},
frame: `
6: color: red;
7: }
8: a:global(.foo) > div {
^
9: color: red;
10: }
`,
message: 'Unused CSS selector "a:global(.foo) > div"',
pos: 91,
start: {
character: 91,
column: 1,
line: 8
}
}
]
};

@ -0,0 +1 @@
div>div.svelte-xyz.svelte-xyz{color:red}div.svelte-xyz.foo>div.svelte-xyz{color:red}

@ -0,0 +1,3 @@
<div class="svelte-xyz">
<div class="svelte-xyz"></div>
</div>

@ -0,0 +1,15 @@
<style>
:global(div) > div {
color: red;
}
div:global(.foo) > div {
color: red;
}
a:global(.foo) > div {
color: red;
}
</style>
<div>
<div />
</div>

@ -0,0 +1,3 @@
<div class="svelte-xyz">
<div class="svelte-xyz"></div>
</div>

@ -0,0 +1,9 @@
<style>
:global(a) > :global(b) > div {
color: red;
}
</style>
<div>
<div />
</div>

@ -0,0 +1,3 @@
export default {
warnings: []
};

@ -0,0 +1,3 @@
<div class="svelte-xyz">
<div class="svelte-xyz"></div>
</div>

@ -0,0 +1,9 @@
<style>
:global(div) > div {
color: red;
}
</style>
<div>
<div />
</div>

@ -0,0 +1 @@
export default {};

@ -0,0 +1 @@
:root{color:red}.foo:root{color:blue}:root.foo{color:green}

@ -0,0 +1,13 @@
<style>
:root {
color: red;
}
.foo:root {
color: blue;
}
:root.foo {
color: green;
}
</style>
<h1>Hello!</h1>

@ -1,4 +1,4 @@
<title>Some Title</title>
<link href="/" rel="canonical">
<meta content="some description" name="description">
<meta content="some keywords" name="keywords">
<title>Some Title</title>

@ -2,6 +2,7 @@
import {
SvelteComponent,
append,
append_styles,
attr,
detach,
element,
@ -13,11 +14,8 @@ import {
text
} from "svelte/internal";
function add_css() {
var style = element("style");
style.id = "svelte-1a7i8ec-style";
style.textContent = "p.svelte-1a7i8ec{color:red}";
append(document.head, style);
function add_css(target) {
append_styles(target, "svelte-1a7i8ec", "p.svelte-1a7i8ec{color:red}");
}
function create_fragment(ctx) {
@ -58,8 +56,7 @@ function instance($$self, $$props, $$invalidate) {
class Component extends SvelteComponent {
constructor(options) {
super();
if (!document.getElementById("svelte-1a7i8ec-style")) add_css();
init(this, options, instance, create_fragment, safe_not_equal, { foo: 0 });
init(this, options, instance, create_fragment, safe_not_equal, { foo: 0 }, add_css);
}
}

@ -1,7 +1,7 @@
/* generated by Svelte vX.Y.Z */
import {
SvelteComponent,
append,
append_styles,
attr,
detach,
element,
@ -11,11 +11,8 @@ import {
safe_not_equal
} from "svelte/internal";
function add_css() {
var style = element("style");
style.id = "svelte-1slhpfn-style";
style.textContent = "@media(min-width: 1px){div.svelte-1slhpfn{color:red}}";
append(document.head, style);
function add_css(target) {
append_styles(target, "svelte-1slhpfn", "@media(min-width: 1px){div.svelte-1slhpfn{color:red}}");
}
function create_fragment(ctx) {
@ -41,8 +38,7 @@ function create_fragment(ctx) {
class Component extends SvelteComponent {
constructor(options) {
super();
if (!document.getElementById("svelte-1slhpfn-style")) add_css();
init(this, options, null, create_fragment, safe_not_equal, {});
init(this, options, null, create_fragment, safe_not_equal, {}, add_css);
}
}

@ -46,7 +46,8 @@ class Component extends SvelteElement {
null,
create_fragment,
safe_not_equal,
{}
{},
null
);
if (options) {

@ -0,0 +1,5 @@
export default {
options: {
accessors: true
}
};

@ -0,0 +1,34 @@
/* generated by Svelte vX.Y.Z */
import { SvelteComponent, init, safe_not_equal } from "svelte/internal";
import { f as f_1, g as g_1 } from './d';
import { h as h_1 } from './e';
import { i as j } from './f';
export { d as e } from './c';
export { c } from './b';
export { a, b } from './a';
class Component extends SvelteComponent {
constructor(options) {
super();
init(this, options, null, null, safe_not_equal, {});
}
get f() {
return f_1;
}
get g() {
return g_1;
}
get h() {
return h_1;
}
get j() {
return j;
}
}
export default Component;

@ -0,0 +1,11 @@
<script context="module">
export { a, b } from './a';
export { c } from './b';
export { d as e } from './c';
</script>
<script>
export { f, g } from './d';
export { h } from './e';
export { i as j } from './f';
</script>

@ -0,0 +1,6 @@
export default {
options: {
accessors: true,
format: 'cjs'
}
};

@ -0,0 +1,36 @@
/* generated by Svelte vX.Y.Z */
"use strict";
const { SvelteComponent, init, safe_not_equal } = require("svelte/internal");
const { f: f_1, g: g_1 } = require("./d");
const { h: h_1 } = require("./e");
const { i: j } = require("./f");
exports.e = require("./c").d;
exports.c = require("./b").c;
exports.a = require("./a").a;
exports.b = require("./a").b;
class Component extends SvelteComponent {
constructor(options) {
super();
init(this, options, null, null, safe_not_equal, {});
}
get f() {
return f_1;
}
get g() {
return g_1;
}
get h() {
return h_1;
}
get j() {
return j;
}
}
exports.default = Component;

@ -0,0 +1,11 @@
<script context="module">
export { a, b } from './a';
export { c } from './b';
export { d as e } from './c';
</script>
<script>
export { f, g } from './d';
export { h } from './e';
export { i as j } from './f';
</script>

@ -0,0 +1,18 @@
/* generated by Svelte vX.Y.Z */
import { SvelteComponent, init, safe_not_equal } from "svelte/internal";
import './d';
import './e';
import './f';
export { d as e } from './c';
export { c } from './b';
export { a, b } from './a';
class Component extends SvelteComponent {
constructor(options) {
super();
init(this, options, null, null, safe_not_equal, {});
}
}
export default Component;

@ -0,0 +1,11 @@
<script context="module">
export { a, b } from './a';
export { c } from './b';
export { d as e } from './c';
</script>
<script>
export { f, g } from './d';
export { h } from './e';
export { i as j } from './f';
</script>

@ -8,10 +8,11 @@ import {
detach,
element,
init,
insert,
insert_hydration,
noop,
safe_not_equal,
space
space,
src_url_equal
} from "svelte/internal";
function create_fragment(ctx) {
@ -35,13 +36,13 @@ function create_fragment(ctx) {
this.h();
},
h() {
if (img.src !== (img_src_value = "donuts.jpg")) attr(img, "src", img_src_value);
if (!src_url_equal(img.src, img_src_value = "donuts.jpg")) attr(img, "src", img_src_value);
attr(img, "alt", "donuts");
},
m(target, anchor) {
insert(target, img, anchor);
insert(target, t, anchor);
insert(target, div, anchor);
insert_hydration(target, img, anchor);
insert_hydration(target, t, anchor);
insert_hydration(target, div, anchor);
},
p: noop,
i: noop,

@ -7,10 +7,11 @@ import {
detach,
element,
init,
insert,
insert_hydration,
noop,
safe_not_equal,
space
space,
src_url_equal
} from "svelte/internal";
function create_fragment(ctx) {
@ -35,21 +36,21 @@ function create_fragment(ctx) {
},
h() {
attr(img0, "alt", "potato");
if (img0.src !== (img0_src_value = /*url*/ ctx[0])) attr(img0, "src", img0_src_value);
if (!src_url_equal(img0.src, img0_src_value = /*url*/ ctx[0])) attr(img0, "src", img0_src_value);
attr(img1, "alt", "potato");
if (img1.src !== (img1_src_value = "" + (/*slug*/ ctx[1] + ".jpg"))) attr(img1, "src", img1_src_value);
if (!src_url_equal(img1.src, img1_src_value = "" + (/*slug*/ ctx[1] + ".jpg"))) attr(img1, "src", img1_src_value);
},
m(target, anchor) {
insert(target, img0, anchor);
insert(target, t, anchor);
insert(target, img1, anchor);
insert_hydration(target, img0, anchor);
insert_hydration(target, t, anchor);
insert_hydration(target, img1, anchor);
},
p(ctx, [dirty]) {
if (dirty & /*url*/ 1 && img0.src !== (img0_src_value = /*url*/ ctx[0])) {
if (dirty & /*url*/ 1 && !src_url_equal(img0.src, img0_src_value = /*url*/ ctx[0])) {
attr(img0, "src", img0_src_value);
}
if (dirty & /*slug*/ 2 && img1.src !== (img1_src_value = "" + (/*slug*/ ctx[1] + ".jpg"))) {
if (dirty & /*slug*/ 2 && !src_url_equal(img1.src, img1_src_value = "" + (/*slug*/ ctx[1] + ".jpg"))) {
attr(img1, "src", img1_src_value);
}
},

@ -0,0 +1,55 @@
{
"html": {
"start": 0,
"end": 18,
"type": "Fragment",
"children": [
{
"start": 0,
"end": 18,
"type": "Element",
"name": "input",
"attributes": [
{
"start": 7,
"end": 15,
"type": "Attribute",
"name": "foo",
"value": [
{
"start": 11,
"end": 12,
"type": "Text",
"raw": "a",
"data": "a"
},
{
"start": 12,
"end": 15,
"type": "MustacheTag",
"expression": {
"type": "Literal",
"start": 13,
"end": 14,
"loc": {
"start": {
"line": 1,
"column": 13
},
"end": {
"line": 1,
"column": 14
}
},
"value": 1,
"raw": "1"
}
}
]
}
],
"children": []
}
]
}
}

@ -18,7 +18,7 @@
"value": [
{
"start": 12,
"end": 20,
"end": 19,
"type": "Text",
"raw": "color: ",
"data": "color: "

@ -0,0 +1,16 @@
{
"html": {
"start": 0,
"end": 30,
"type": "Fragment",
"children": [
{
"start": 0,
"end": 30,
"type": "Comment",
"data": " svelte-ignore foo bar ",
"ignores": ["foo", "bar"]
}
]
}
}

@ -8,7 +8,8 @@
"start": 0,
"end": 18,
"type": "Comment",
"data": " a comment "
"data": " a comment ",
"ignores": []
}
]
}

@ -0,0 +1,2 @@
<span attr=""></span>
<span attr=''></span>

@ -0,0 +1,64 @@
{
"html": {
"start": 0,
"end": 43,
"type": "Fragment",
"children": [
{
"start": 0,
"end": 21,
"type": "Element",
"name": "span",
"attributes": [
{
"start": 6,
"end": 13,
"type": "Attribute",
"name": "attr",
"value": [
{
"start": 12,
"end": 12,
"type": "Text",
"raw": "",
"data": ""
}
]
}
],
"children": []
},
{
"start": 21,
"end": 22,
"type": "Text",
"raw": "\n",
"data": "\n"
},
{
"start": 22,
"end": 43,
"type": "Element",
"name": "span",
"attributes": [
{
"start": 28,
"end": 35,
"type": "Attribute",
"name": "attr",
"value": [
{
"start": 34,
"end": 34,
"type": "Text",
"raw": "",
"data": ""
}
]
}
],
"children": []
}
]
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save