Merge branch 'master' into fix/7550

pull/7551/head
Tan Li Hau 4 years ago committed by GitHub
commit 673517ce1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

1
.gitignore vendored

@ -1,6 +1,5 @@
.idea .idea
.DS_Store .DS_Store
.nyc_output
.vscode .vscode
node_modules node_modules
*.map *.map

@ -2,8 +2,50 @@
## Unreleased ## Unreleased
* Faster SSR ([#5701](https://github.com/sveltejs/svelte/pull/5701)) * Fix hydration issue with using `{@html}` and components in `svelte:head` ([#4533](https://github.com/sveltejs/svelte/issues/4533), [#6463](https://github.com/sveltejs/svelte/issues/6463), [#7444](https://github.com/sveltejs/svelte/issues/7444))
* Fix `class:` directive updates with `<svelte:element>` ([#7521](https://github.com/sveltejs/svelte/issues/7521)) * Warn instead of throwing error if `<svelte:element>` is void tag ([#7566](https://github.com/sveltejs/svelte/issues/7566))
* Treat `inert` as boolean attribute ([#7785](https://github.com/sveltejs/svelte/pull/7785))
* Supporting scoped style for `<svelte:element>` ([#7443](https://github.com/sveltejs/svelte/issues/7443))
* Supports SVG elements with `<svelte:element>`([#7613](https://github.com/sveltejs/svelte/issues/7613))
* Warn user when binding on a `{...rest}` object in `{#each}` block ([#6860](https://github.com/sveltejs/svelte/issues/6860))
* support `--style-props` for `<svelte:component>` ([#7461](https://github.com/sveltejs/svelte/issues/7461))
* Add a11y warnings:
* `a11y-no-noninteractive-tabindex`: check for tabindex on non-interactive elements ([#6693](https://github.com/sveltejs/svelte/pull/6693))
* `a11y-click-events-have-key-events`: check if click event is accompanied by key events ([#5073](https://github.com/sveltejs/svelte/pull/5073))
## 3.50.1
* Add all global objects and functions as known globals ([#3805](https://github.com/sveltejs/svelte/issues/3805), [#7223](https://github.com/sveltejs/svelte/issues/7223))
* Fix regression with style manager ([#7828](https://github.com/sveltejs/svelte/issues/7828))
## 3.50.0
* Add a11y warnings:
* `a11y-incorrect-aria-attribute-type`: check ARIA state and property values ([#6978](https://github.com/sveltejs/svelte/pull/6978))
* `a11y-no-abstract-role`: check that ARIA roles are non-abstract ([#6241](https://github.com/sveltejs/svelte/pull/6241))
* `a11y-no-interactive-element-to-noninteractive-role`: check for non-interactive roles used on interactive elements ([#5955](https://github.com/sveltejs/svelte/pull/5955))
* `a11y-role-has-required-aria-props`: check that elements with `role` attribute have all required attributes for that role ([#5852](https://github.com/sveltejs/svelte/pull/5852))
* Add `ComponentEvents` convenience type ([#7702](https://github.com/sveltejs/svelte/pull/7702))
* Add `SveltePreprocessor` utility type ([#7742](https://github.com/sveltejs/svelte/pull/7742))
* Enhance action typings ([#7805](https://github.com/sveltejs/svelte/pull/7805))
* Remove empty stylesheets created from transitions ([#4801](https://github.com/sveltejs/svelte/issues/4801), [#7164](https://github.com/sveltejs/svelte/issues/7164))
* Make `a11y-label-has-associated-control` warning check all descendants for input control ([#5528](https://github.com/sveltejs/svelte/issues/5528))
* Only show lowercase component name warnings for non-HTML/SVG elements ([#5712](https://github.com/sveltejs/svelte/issues/5712))
* Disallow invalid CSS selectors starting with a combinator ([#7643](https://github.com/sveltejs/svelte/issues/7643))
* Use `Node.parentNode` instead of `Node.parentElement` for legacy browser support ([#7723](https://github.com/sveltejs/svelte/issues/7723))
* Handle arrow function on `<slot>` inside `<svelte:fragment>` ([#7485](https://github.com/sveltejs/svelte/issues/7485))
* Improve parsing speed when encountering large blocks of whitespace ([#7675](https://github.com/sveltejs/svelte/issues/7675))
* Fix `class:` directive updates in aborted/restarted transitions ([#7764](https://github.com/sveltejs/svelte/issues/7764))
## 3.49.0
* Improve performance of string escaping during SSR ([#5701](https://github.com/sveltejs/svelte/pull/5701))
* Add `ComponentType` and `ComponentProps` convenience types ([#6770](https://github.com/sveltejs/svelte/pull/6770))
* Add support for CSS `@layer` ([#7504](https://github.com/sveltejs/svelte/issues/7504))
* Export `CompileOptions` from `svelte/compiler` ([#7658](https://github.com/sveltejs/svelte/pull/7658))
* Fix DOM-less components not being properly destroyed ([#7488](https://github.com/sveltejs/svelte/issues/7488))
* Fix `class:` directive updates with `<svelte:element>` ([#7521](https://github.com/sveltejs/svelte/issues/7521), [#7571](https://github.com/sveltejs/svelte/issues/7571))
* Harden attribute escaping during SSR ([#7530](https://github.com/sveltejs/svelte/pull/7530))
## 3.48.0 ## 3.48.0

@ -64,7 +64,7 @@ npm run test -- -g transition
## svelte.dev ## svelte.dev
The source code for https://svelte.dev, including all the documentation, lives in the [site](site) directory. The site is built with [SvelteKit](https://kit.svelte.dev). The source code for https://svelte.dev lives in the [sites](https://github.com/sveltejs/sites) repository, with all the documentation in the [site/content](site/content) directory. The site is built with [SvelteKit](https://kit.svelte.dev).
### Is svelte.dev down? ### Is svelte.dev down?

@ -0,0 +1,24 @@
// This script generates the TypeScript definitions
const { execSync } = require('child_process');
const { readFileSync, writeFileSync } = require('fs');
execSync('tsc -p src/compiler --emitDeclarationOnly && tsc -p src/runtime --emitDeclarationOnly');
// We need to add these types to the .d.ts files here because if we add them before building, the build will fail,
// because the TS->JS transformation doesn't know these exports are types and produces code that fails at runtime.
// We can't use `export type` syntax either because the TS version we're on doesn't have this feature yet.
function modify(path, modifyFn) {
const content = readFileSync(path, 'utf8');
writeFileSync(path, modifyFn(content));
}
modify(
'types/runtime/index.d.ts',
content => content.replace('SvelteComponentTyped', 'SvelteComponentTyped, ComponentType, ComponentConstructorOptions, ComponentProps, ComponentEvents')
);
modify(
'types/compiler/index.d.ts',
content => content + '\nexport { CompileOptions, ModuleFormat, EnableSourcemap, CssHashGetter } from "./interfaces"'
);

87
package-lock.json generated

@ -1,12 +1,12 @@
{ {
"name": "svelte", "name": "svelte",
"version": "3.48.0", "version": "3.50.1",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "svelte", "name": "svelte",
"version": "3.48.0", "version": "3.49.0",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@ampproject/remapping": "^0.3.0", "@ampproject/remapping": "^0.3.0",
@ -18,12 +18,15 @@
"@rollup/plugin-typescript": "^2.0.1", "@rollup/plugin-typescript": "^2.0.1",
"@rollup/plugin-virtual": "^2.0.0", "@rollup/plugin-virtual": "^2.0.0",
"@sveltejs/eslint-config": "github:sveltejs/eslint-config#v5.8.0", "@sveltejs/eslint-config": "github:sveltejs/eslint-config#v5.8.0",
"@types/aria-query": "^5.0.0",
"@types/mocha": "^7.0.0", "@types/mocha": "^7.0.0",
"@types/node": "^8.10.53", "@types/node": "^8.10.53",
"@typescript-eslint/eslint-plugin": "^5.22.0", "@typescript-eslint/eslint-plugin": "^5.22.0",
"@typescript-eslint/parser": "^5.22.0", "@typescript-eslint/parser": "^5.22.0",
"acorn": "^8.4.1", "acorn": "^8.4.1",
"agadoo": "^1.1.0", "agadoo": "^1.1.0",
"aria-query": "^5.0.0",
"axobject-query": "^3.0.1",
"code-red": "^0.2.5", "code-red": "^0.2.5",
"css-tree": "^1.1.2", "css-tree": "^1.1.2",
"eslint": "^8.0.0", "eslint": "^8.0.0",
@ -39,7 +42,7 @@
"periscopic": "^3.0.4", "periscopic": "^3.0.4",
"puppeteer": "^2.0.0", "puppeteer": "^2.0.0",
"rollup": "^1.27.14", "rollup": "^1.27.14",
"source-map": "^0.7.3", "source-map": "^0.7.4",
"source-map-support": "^0.5.13", "source-map-support": "^0.5.13",
"sourcemap-codec": "^1.4.8", "sourcemap-codec": "^1.4.8",
"tiny-glob": "^0.2.6", "tiny-glob": "^0.2.6",
@ -285,6 +288,12 @@
"resolved": "git+ssh://git@github.com/sveltejs/eslint-config.git#31fd4faeea88990069502460b023698b1c9c2d13", "resolved": "git+ssh://git@github.com/sveltejs/eslint-config.git#31fd4faeea88990069502460b023698b1c9c2d13",
"dev": true "dev": true
}, },
"node_modules/@types/aria-query": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.0.tgz",
"integrity": "sha512-P+dkdFu0n08PDIvw+9nT9ByQnd+Udc8DaWPb9HKfaPwCvWvQpC5XaMRx2xLWECm9x1VKNps6vEAlirjA6+uNrQ==",
"dev": true
},
"node_modules/@types/estree": { "node_modules/@types/estree": {
"version": "0.0.50", "version": "0.0.50",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz",
@ -698,6 +707,15 @@
"sprintf-js": "~1.0.2" "sprintf-js": "~1.0.2"
} }
}, },
"node_modules/aria-query": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz",
"integrity": "sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==",
"dev": true,
"engines": {
"node": ">=6.0"
}
},
"node_modules/array-equal": { "node_modules/array-equal": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
@ -795,6 +813,15 @@
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",
"dev": true "dev": true
}, },
"node_modules/axobject-query": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.0.1.tgz",
"integrity": "sha512-vy5JPSOibF9yAeC2PoemRdA1MuSXX7vX5osdoxKf/6OUeppAWekZ3JIJVNWFMH6wgj7uHYyqZUSqE/b/3JLV1A==",
"dev": true,
"engines": {
"node": ">=6.0"
}
},
"node_modules/balanced-match": { "node_modules/balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@ -4020,9 +4047,9 @@
} }
}, },
"node_modules/source-map": { "node_modules/source-map": {
"version": "0.7.3", "version": "0.7.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">= 8" "node": ">= 8"
@ -4221,9 +4248,9 @@
} }
}, },
"node_modules/svelte": { "node_modules/svelte": {
"version": "3.43.0", "version": "3.49.0",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.43.0.tgz", "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.49.0.tgz",
"integrity": "sha512-T2pMPHrxXp+SM8pLLUXLQgkdo+JhTls7aqj9cD7z8wT2ccP+OrCAmtQS7h6pvMjitaZhXFNnCK582NxDpy8HSw==", "integrity": "sha512-+lmjic1pApJWDfPCpUUTc1m8azDqYCG1JN9YEngrx/hUyIcFJo6VZhj0A1Ai0wqoHcEIuQy+e9tk+4uDgdtsFA==",
"dev": true, "dev": true,
"peer": true, "peer": true,
"engines": { "engines": {
@ -4402,9 +4429,9 @@
"dev": true "dev": true
}, },
"node_modules/typescript": { "node_modules/typescript": {
"version": "3.7.5", "version": "3.9.10",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.5.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz",
"integrity": "sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==", "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==",
"dev": true, "dev": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
@ -4927,6 +4954,12 @@
"dev": true, "dev": true,
"from": "@sveltejs/eslint-config@github:sveltejs/eslint-config#v5.8.0" "from": "@sveltejs/eslint-config@github:sveltejs/eslint-config#v5.8.0"
}, },
"@types/aria-query": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.0.tgz",
"integrity": "sha512-P+dkdFu0n08PDIvw+9nT9ByQnd+Udc8DaWPb9HKfaPwCvWvQpC5XaMRx2xLWECm9x1VKNps6vEAlirjA6+uNrQ==",
"dev": true
},
"@types/estree": { "@types/estree": {
"version": "0.0.50", "version": "0.0.50",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz",
@ -5208,6 +5241,12 @@
"sprintf-js": "~1.0.2" "sprintf-js": "~1.0.2"
} }
}, },
"aria-query": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz",
"integrity": "sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==",
"dev": true
},
"array-equal": { "array-equal": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
@ -5284,6 +5323,12 @@
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",
"dev": true "dev": true
}, },
"axobject-query": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.0.1.tgz",
"integrity": "sha512-vy5JPSOibF9yAeC2PoemRdA1MuSXX7vX5osdoxKf/6OUeppAWekZ3JIJVNWFMH6wgj7uHYyqZUSqE/b/3JLV1A==",
"dev": true
},
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@ -7787,9 +7832,9 @@
"dev": true "dev": true
}, },
"source-map": { "source-map": {
"version": "0.7.3", "version": "0.7.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
"dev": true "dev": true
}, },
"source-map-support": { "source-map-support": {
@ -7943,9 +7988,9 @@
"dev": true "dev": true
}, },
"svelte": { "svelte": {
"version": "3.43.0", "version": "3.49.0",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.43.0.tgz", "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.49.0.tgz",
"integrity": "sha512-T2pMPHrxXp+SM8pLLUXLQgkdo+JhTls7aqj9cD7z8wT2ccP+OrCAmtQS7h6pvMjitaZhXFNnCK582NxDpy8HSw==", "integrity": "sha512-+lmjic1pApJWDfPCpUUTc1m8azDqYCG1JN9YEngrx/hUyIcFJo6VZhj0A1Ai0wqoHcEIuQy+e9tk+4uDgdtsFA==",
"dev": true, "dev": true,
"peer": true "peer": true
}, },
@ -8096,9 +8141,9 @@
"dev": true "dev": true
}, },
"typescript": { "typescript": {
"version": "3.7.5", "version": "3.9.10",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.5.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz",
"integrity": "sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==", "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==",
"dev": true "dev": true
}, },
"unbox-primitive": { "unbox-primitive": {

@ -1,6 +1,6 @@
{ {
"name": "svelte", "name": "svelte",
"version": "3.48.0", "version": "3.50.1",
"description": "Cybernetically enhanced web apps", "description": "Cybernetically enhanced web apps",
"module": "index.mjs", "module": "index.mjs",
"main": "index", "main": "index",
@ -95,7 +95,7 @@
"pretest": "npm run build", "pretest": "npm run build",
"posttest": "agadoo internal/index.mjs", "posttest": "agadoo internal/index.mjs",
"prepublishOnly": "node check_publish_env.js && npm run lint && npm test", "prepublishOnly": "node check_publish_env.js && npm run lint && npm test",
"tsd": "tsc -p src/compiler --emitDeclarationOnly && tsc -p src/runtime --emitDeclarationOnly", "tsd": "node ./generate-type-definitions.js",
"lint": "eslint \"{src,test}/**/*.{ts,js}\"" "lint": "eslint \"{src,test}/**/*.{ts,js}\""
}, },
"repository": { "repository": {
@ -124,12 +124,15 @@
"@rollup/plugin-typescript": "^2.0.1", "@rollup/plugin-typescript": "^2.0.1",
"@rollup/plugin-virtual": "^2.0.0", "@rollup/plugin-virtual": "^2.0.0",
"@sveltejs/eslint-config": "github:sveltejs/eslint-config#v5.8.0", "@sveltejs/eslint-config": "github:sveltejs/eslint-config#v5.8.0",
"@types/aria-query": "^5.0.0",
"@types/mocha": "^7.0.0", "@types/mocha": "^7.0.0",
"@types/node": "^8.10.53", "@types/node": "^8.10.53",
"@typescript-eslint/eslint-plugin": "^5.22.0", "@typescript-eslint/eslint-plugin": "^5.22.0",
"@typescript-eslint/parser": "^5.22.0", "@typescript-eslint/parser": "^5.22.0",
"acorn": "^8.4.1", "acorn": "^8.4.1",
"agadoo": "^1.1.0", "agadoo": "^1.1.0",
"aria-query": "^5.0.0",
"axobject-query": "^3.0.1",
"code-red": "^0.2.5", "code-red": "^0.2.5",
"css-tree": "^1.1.2", "css-tree": "^1.1.2",
"eslint": "^8.0.0", "eslint": "^8.0.0",
@ -145,19 +148,11 @@
"periscopic": "^3.0.4", "periscopic": "^3.0.4",
"puppeteer": "^2.0.0", "puppeteer": "^2.0.0",
"rollup": "^1.27.14", "rollup": "^1.27.14",
"source-map": "^0.7.3", "source-map": "^0.7.4",
"source-map-support": "^0.5.13", "source-map-support": "^0.5.13",
"sourcemap-codec": "^1.4.8", "sourcemap-codec": "^1.4.8",
"tiny-glob": "^0.2.6", "tiny-glob": "^0.2.6",
"tslib": "^2.0.3", "tslib": "^2.0.3",
"typescript": "^3.7.5" "typescript": "^3.7.5"
},
"nyc": {
"include": [
"compiler/svelte.js",
"shared.js"
],
"sourceMap": true,
"instrument": true
} }
} }

@ -0,0 +1,91 @@
/** ----------------------------------------------------------------------
This script gets a list of global objects/functions of browser.
This process is simple for now, so it is handled without AST parser.
Please run `node scripts/globals-extractor.mjs` at the project root.
see: https://github.com/microsoft/TypeScript/tree/main/lib
---------------------------------------------------------------------- */
import http from 'https';
import fs from 'fs';
const GLOBAL_TS_PATH = './src/compiler/utils/globals.ts';
// MEMO: add additional objects/functions which existed in `src/compiler/utils/names.ts`
// before this script was introduced but could not be retrieved by this process.
const SPECIALS = ['global', 'globalThis', 'InternalError', 'process', 'undefined'];
const get_url = (name) => `https://raw.githubusercontent.com/microsoft/TypeScript/main/lib/lib.${name}.d.ts`;
const extract_name = (split) => split.match(/^[a-zA-Z0-9_$]+/)[0];
const extract_functions_and_references = (name, data) => {
const functions = [];
const references = [];
data.split('\n').forEach(line => {
const trimmed = line.trim();
const split = trimmed.replace(/[\s+]/, ' ').split(' ');
if (split[0] === 'declare' && split[1] !== 'type') {
functions.push(extract_name(split[2]));
} else if (trimmed.startsWith('/// <reference')) {
const matched = trimmed.match(/ lib="(.+)"/);
const reference = matched && matched[1];
if (reference) references.push(reference);
}
});
return { functions, references };
};
const do_get = (url) => new Promise((resolve, reject) => {
http.get(url, (res) => {
let body = '';
res.setEncoding('utf8');
res.on('data', (chunk) => body += chunk);
res.on('end', () => resolve(body));
}).on('error', (e) => {
console.error(e.message);
reject(e);
});
});
const fetched_names = new Set();
const get_functions = async (name) => {
const res = [];
if (fetched_names.has(name)) return res;
fetched_names.add(name);
const body = await do_get(get_url(name));
const { functions, references } = extract_functions_and_references(name, body);
res.push(...functions);
const chile_functions = await Promise.all(references.map(get_functions));
chile_functions.forEach(i => res.push(...i));
return res;
};
const build_output = (functions) => {
const sorted = Array.from(new Set(functions.sort()));
return `\
/** ----------------------------------------------------------------------
This file is automatically generated by \`scripts/globals-extractor.mjs\`.
Generated At: ${new Date().toISOString()}
---------------------------------------------------------------------- */
export default new Set([
${sorted.map((i) => `\t'${i}'`).join(',\n')}
]);
`;
};
const get_exists_globals = () => {
const regexp = /^\s*["'](.+)["'],?\s*$/;
return fs.readFileSync(GLOBAL_TS_PATH, 'utf8')
.split('\n')
.filter(line => line.match(regexp))
.map(line => line.match(regexp)[1]);
};
(async () => {
const globals = get_exists_globals();
const new_globals = await get_functions('es2021.full');
globals.forEach((g) => new_globals.push(g));
SPECIALS.forEach((g) => new_globals.push(g));
fs.writeFileSync(GLOBAL_TS_PATH, build_output(new_globals));
})();

@ -56,36 +56,36 @@ To write code, you need a good editor. The most popular choice is [Visual Studio
## Creating a project ## Creating a project
We're going to follow the instructions in part two of [The easiest way to get started with Svelte](/blog/the-easiest-way-to-get-started). We're going to use the [Svelte + Vite](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-svelte) template. You don't have to use a project template, but it means you have to do a lot less setup work.
First, we'll use npx to run [degit](https://github.com/Rich-Harris/degit), a program for cloning project templates from [GitHub](https://github.com) and other code storage websites. You don't have to use a project template, but it means you have to do a lot less setup work. You will need to have [Git](https://git-scm.com/) installed in order to use degit. (Eventually you'll probably have to learn [Git](https://git-scm.com/) itself, which most programmers use to manage their projects.)
On the command line, navigate to where you want to create a new project, then type the following lines (you can paste the whole lot, but you'll develop better muscle memory if you get into the habit of writing each line out one at a time then running it): On the command line, navigate to where you want to create a new project, then type the following lines (you can paste the whole lot, but you'll develop better muscle memory if you get into the habit of writing each line out one at a time then running it):
```bash ```bash
npx degit sveltejs/template my-svelte-project npm create vite@latest my-svelte-project -- --template svelte
cd my-svelte-project cd my-svelte-project
npm install npm install
``` ```
This creates a new directory, `my-svelte-project`, adds files from the [sveltejs/template](https://github.com/sveltejs/template) code repository, and installs a number of packages from npm. Open the directory in your text editor and take a look around. The app's 'source code' lives in the `src` directory, while the files your app can load are in `public`. > You can replace `--template svelte` with `--template svelte-ts`, if you prefer TypeScript.
This creates a new directory, `my-svelte-project`, adds files from the [create-vite/template-svelte](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-svelte) template, and installs a number of packages from npm. Open the directory in your text editor and take a look around. The app's 'source code' lives in the `src` directory, while the files your app can load are in `public`.
In the `package.json` file, there is a section called `"scripts"`. These scripts define shortcuts for working with your application — `dev`, `build` and `start`. To launch your app in development mode, type the following: In the `package.json` file, there is a section called `"scripts"`. These scripts define shortcuts for working with your application — `dev`, `build` and `preview`. To launch your app in development mode, type the following:
```bash ```bash
npm run dev npm run dev
``` ```
Running the `dev` script starts a program called [Rollup](https://rollupjs.org/guide/en/). Rollup's job is to take your application's source files (so far, just `src/main.js` and `src/App.svelte`), pass them to other programs (including Svelte, in our case) and convert them into the code that will actually run when you open the application in a browser. Running the `dev` script starts a program called [Vite](https://vitejs.dev/). Vite's job is to take your application's source files, pass them to other programs (including Svelte, in our case) and convert them into the code that will actually run when you open the application in a browser.
Speaking of which, open a browser and navigate to http://localhost:8080. This is your application running on a local *web server* (hence 'localhost') on port 8080. Speaking of which, open a browser and navigate to http://localhost:5173. This is your application running on a local *web server* (hence 'localhost') on port 5173.
Try changing `src/App.svelte` and saving it. The application will reload with your changes. Try changing `src/App.svelte` and saving it. The application will update with your changes.
## Building your app ## Building your app
In the last step, we were running the app in 'development mode'. In dev mode, Svelte adds extra code that helps with debugging, and Rollup skips the final step where your app's JavaScript is compressed using [Terser](https://terser.org/). In the last step, we were running the app in 'development mode'. In dev mode, Svelte adds extra code that helps with debugging, and Vite skips the final step where your app's JavaScript is compressed.
When you share your app with the world, you want to build it in 'production mode', so that it's as small and efficient as possible for end users. To do that, use the `build` command: When you share your app with the world, you want to build it in 'production mode', so that it's as small and efficient as possible for end users. To do that, use the `build` command:
@ -93,15 +93,8 @@ When you share your app with the world, you want to build it in 'production mode
npm run build npm run build
``` ```
Your `public` directory now contains a compressed `bundle.js` file containing your app's JavaScript. You can run it like so: Your `dist` directory now contains an optimised version of your app. You can run it like so:
```bash ```bash
npm run start npm run preview
``` ```
This will run the app on http://localhost:8080.
## Next steps
To share your app with the world you'll need to *deploy* it. There are many ways to do so — some are listed in the `README.md` file inside your project.

@ -53,7 +53,7 @@ For all the features and bugfixes see the CHANGELOGs for [Svelte](https://github
**Components, Libraries & Tools** **Components, Libraries & Tools**
- [svelte-crossword](https://russellgoldenberg.github.io/svelte-crossword/) is a customizable crossword puzzle component for Svelte. - [svelte-crossword](https://russellgoldenberg.github.io/svelte-crossword/) is a customizable crossword puzzle component for Svelte.
- [svelte-cloudinary](https://github.com/cupcakearmy/svelte-cloudinary) makes it easy to integrate Cloudinary with Svelte (including Typescript and SSR support) - [svelte-cloudinary](https://github.com/cupcakearmy/svelte-cloudinary) makes it easy to integrate Cloudinary with Svelte (including TypeScript and SSR support)
- [Svelte Nova](https://extensions.panic.com/extensions/sb.lao/sb.lao.svelte-nova/) extends the new Nova editor to support Svelte - [Svelte Nova](https://extensions.panic.com/extensions/sb.lao/sb.lao.svelte-nova/) extends the new Nova editor to support Svelte
- [saos](https://github.com/shiryel/saos) is a small svelte component to animate your elements on scroll. - [saos](https://github.com/shiryel/saos) is a small svelte component to animate your elements on scroll.
- [Svelte-nStore](https://github.com/lacikawiz/svelte-nStore) is a general purpose store replacement that fulfills the Svelte store contract and adds getter and calculation features. - [Svelte-nStore](https://github.com/lacikawiz/svelte-nStore) is a general purpose store replacement that fulfills the Svelte store contract and adds getter and calculation features.

@ -70,7 +70,7 @@ New changes to the Svelte Society website include [a new cheat sheet](https://sv
- [here-maps-svelte](https://github.com/peopledrivemecrazy/here-maps-svelte) makes it easy to include HERE maps in a Svelte app - [here-maps-svelte](https://github.com/peopledrivemecrazy/here-maps-svelte) makes it easy to include HERE maps in a Svelte app
- [p5-svelte](https://github.com/tonyketcham/p5-svelte) is an absolutely dead simple way of tossing the creative coding/sketching tool, p5, into a project - [p5-svelte](https://github.com/tonyketcham/p5-svelte) is an absolutely dead simple way of tossing the creative coding/sketching tool, p5, into a project
- [svelte-windicss-preprocess](https://github.com/voorjaar/svelte-windicss-preprocess) is a Svelte preprocessor to compile tailwindcss at build time based on windicss compiler - [svelte-windicss-preprocess](https://github.com/voorjaar/svelte-windicss-preprocess) is a Svelte preprocessor to compile tailwindcss at build time based on windicss compiler
- [MitzaCoder/svelte-boilerplate](https://github.com/MitzaCoder/svelte-boilerplate) features configurations for Typescript, TailwindCSS, IE11 compatibility (with Babel) and lazy loaded modules. - [MitzaCoder/svelte-boilerplate](https://github.com/MitzaCoder/svelte-boilerplate) features configurations for TypeScript, TailwindCSS, IE11 compatibility (with Babel) and lazy loaded modules.
**Want to share your Svelte Component with the world?** Head over to the [Components](https://sveltesociety.dev/components) page on the Svelte Society site. You can contribute by making [a PR to this file](https://github.com/svelte-society/sveltesociety.dev/blob/master/src/pages/components/components.json). **Want to share your Svelte Component with the world?** Head over to the [Components](https://sveltesociety.dev/components) page on the Svelte Society site. You can contribute by making [a PR to this file](https://github.com/svelte-society/sveltesociety.dev/blob/master/src/pages/components/components.json).

@ -17,7 +17,7 @@ Let's dive into the news 🐬
* Destructured defaults are now allowed to refer to other variables (**3.33.0**, [example](https://svelte.dev/repl/0ee7227e1b45465b9b47d7a5ae2d1252?version=3.33.0)) * Destructured defaults are now allowed to refer to other variables (**3.33.0**, [example](https://svelte.dev/repl/0ee7227e1b45465b9b47d7a5ae2d1252?version=3.33.0))
* Custom elements will now call `onMount` functions when connecting and clean up when disconnecting (**3.33.0**, checkout [this PR](https://github.com/sveltejs/svelte/pull/4522) for an interesting conversation on how folks are using Svelte with Web Components) * Custom elements will now call `onMount` functions when connecting and clean up when disconnecting (**3.33.0**, checkout [this PR](https://github.com/sveltejs/svelte/pull/4522) for an interesting conversation on how folks are using Svelte with Web Components)
* A `cssHash` option has been added to the compiler options to control the classname used for CSS scoping (**3.34.0**, [docs](https://svelte.dev/docs#compile-time-svelte-compile)) * A `cssHash` option has been added to the compiler options to control the classname used for CSS scoping (**3.34.0**, [docs](https://svelte.dev/docs#compile-time-svelte-compile))
* Continued improvement to Typescript definitions * Continued improvement to TypeScript definitions
For a complete list of changes, including bug fixes and links to PRs, check out [the CHANGELOG](https://github.com/sveltejs/svelte/blob/master/CHANGELOG.md) For a complete list of changes, including bug fixes and links to PRs, check out [the CHANGELOG](https://github.com/sveltejs/svelte/blob/master/CHANGELOG.md)
@ -96,7 +96,7 @@ Haven't tried the language-tools yet? Check out [Svelte Extension for VSCode](ht
- [Using Fauna's streaming feature to build a chat with Svelte](https://dev.to/fauna/using-fauna-s-streaming-feature-to-build-a-chat-with-svelte-1gkd) demonstrates how to setup and configure Fauna to build a real-time chat interface with Svelte - [Using Fauna's streaming feature to build a chat with Svelte](https://dev.to/fauna/using-fauna-s-streaming-feature-to-build-a-chat-with-svelte-1gkd) demonstrates how to setup and configure Fauna to build a real-time chat interface with Svelte
- [Using TakeShape with Sapper](https://www.takeshape.io/articles/using-takeshape-with-sapper/) demonstrates how to connect the TakeShape CMS with Sapper - [Using TakeShape with Sapper](https://www.takeshape.io/articles/using-takeshape-with-sapper/) demonstrates how to connect the TakeShape CMS with Sapper
- [YastPack](https://github.com/rodabt/yastpack) is Yet Another Snowpack-Svelte-TailwindCss-Routify Template Pack - [YastPack](https://github.com/rodabt/yastpack) is Yet Another Snowpack-Svelte-TailwindCss-Routify Template Pack
- [S2T2](https://ralphbliu.medium.com/s2t2-snowpack-svelte-tailwindcss-typescript-8928caa5af6c) is a Snowpack + Svelte + TailwindCSS + Typescript template - [S2T2](https://ralphbliu.medium.com/s2t2-snowpack-svelte-tailwindcss-typescript-8928caa5af6c) is a Snowpack + Svelte + TailwindCSS + TypeScript template
- [tonyketcham/sapper-tailwind2-template](https://github.com/tonyketcham/sapper-tailwind2-template) is a Sapper Template w/ Tailwind 2.0, TypeScript, ESLint, and Prettier - [tonyketcham/sapper-tailwind2-template](https://github.com/tonyketcham/sapper-tailwind2-template) is a Sapper Template w/ Tailwind 2.0, TypeScript, ESLint, and Prettier
## See you next month! ## See you next month!

@ -59,7 +59,7 @@ To see all updates to SvelteKit, check out the [SvelteKit changelog](https://git
- [Svelte-Capacitor](https://github.com/drannex42/svelte-capacitor/) just released v2.0.0 - making it even easier to build hybrid mobile apps for iOS and Android using Svelte and Capacitor with near native performance. - [Svelte-Capacitor](https://github.com/drannex42/svelte-capacitor/) just released v2.0.0 - making it even easier to build hybrid mobile apps for iOS and Android using Svelte and Capacitor with near native performance.
- [svelte-remixicon](https://github.com/ABarnob/svelte-remixicon) is an icon library for Svelte based on Remix Icon, consisting of more than 2000 icons. - [svelte-remixicon](https://github.com/ABarnob/svelte-remixicon) is an icon library for Svelte based on Remix Icon, consisting of more than 2000 icons.
- [SveltePress](https://github.com/GeopJr/SveltePress) is a documentation tool built on top of SvelteKit. - [SveltePress](https://github.com/GeopJr/SveltePress) is a documentation tool built on top of SvelteKit.
- [Svelte Starter Kit](https://github.com/one-aalam/svelte-starter-kit/tree/auth-supabase) is a boilerplate to quckly get up and running with Svelte, with Auth and User Profiles powered by Supabase. - [Svelte Starter Kit](https://github.com/one-aalam/svelte-starter-kit/tree/auth-supabase) is a boilerplate to quickly get up and running with Svelte, with Auth and User Profiles powered by Supabase.
- [Kahi UI](https://github.com/novacbn/kahi-ui) is a Svelte-first UI kit with Dark Mode built-in. - [Kahi UI](https://github.com/novacbn/kahi-ui) is a Svelte-first UI kit with Dark Mode built-in.
- [typesafe-i18n](https://github.com/ivanhofer/typesafe-i18n) is an opinionated, fully type-safe, lightweight localization library for TypeScript and JavaScript projects with no external dependencies. - [typesafe-i18n](https://github.com/ivanhofer/typesafe-i18n) is an opinionated, fully type-safe, lightweight localization library for TypeScript and JavaScript projects with no external dependencies.

@ -44,7 +44,7 @@ To see all updates to SvelteKit, check out the [SvelteKit changelog](https://git
- [macos-web](https://github.com/PuruVJ/macos-web) by @puruvjdev has been rebuilt with Svelte from the ground up. Check out all the details in this [Twitter thread](https://twitter.com/puruvjdev/status/1426267327687847939) - [macos-web](https://github.com/PuruVJ/macos-web) by @puruvjdev has been rebuilt with Svelte from the ground up. Check out all the details in this [Twitter thread](https://twitter.com/puruvjdev/status/1426267327687847939)
- [Brave Search](https://search.brave.com/) is using Svelte - [Brave Search](https://search.brave.com/) is using Svelte
- [exatorrent](https://github.com/varbhat/exatorrent) is a self-hostable, easy-to-use, lightweight and feature-rich torrent client written in Go and Svelte - [exatorrent](https://github.com/varbhat/exatorrent) is a self-hostable, easy-to-use, lightweight and feature-rich torrent client written in Go and Svelte
- [json2TsTypes](https://github.com/jatinhemnani01/json2TsTypes) is a simple tool which will convert your JSON to Typescript Types/Interfaces - [json2TsTypes](https://github.com/jatinhemnani01/json2TsTypes) is a simple tool which will convert your JSON to TypeScript Types/Interfaces
- [Histogram.dev](https://histogram.dev/) generates histograms for each feature in a CSV - [Histogram.dev](https://histogram.dev/) generates histograms for each feature in a CSV
- [cybernetic.dev](https://cybernetic.dev/) is a collection of data-centric UI experiments made while learning Svelte - [cybernetic.dev](https://cybernetic.dev/) is a collection of data-centric UI experiments made while learning Svelte
- [LunaNotes](https://chrome.google.com/webstore/detail/lunanotes-youtube-video-n/oehoffnnkgcdacmbkhmlbjedinpampak?hl=en) is a Chrome extension to help with taking YouTube video notes - [LunaNotes](https://chrome.google.com/webstore/detail/lunanotes-youtube-video-n/oehoffnnkgcdacmbkhmlbjedinpampak?hl=en) is a Chrome extension to help with taking YouTube video notes

@ -33,7 +33,7 @@ Notable SvelteKit improvements this month include...
- Svelte libraries should now work out-of-the-box without any Vite configuration ([#2343](https://github.com/sveltejs/kit/pull/2343)) - Svelte libraries should now work out-of-the-box without any Vite configuration ([#2343](https://github.com/sveltejs/kit/pull/2343))
- Improvements to package exports field ([#2345](https://github.com/sveltejs/kit/pull/2345) and [#2327](https://github.com/sveltejs/kit/pull/2327)) - Improvements to package exports field ([#2345](https://github.com/sveltejs/kit/pull/2345) and [#2327](https://github.com/sveltejs/kit/pull/2327))
- [breaking] The `prerender.pages` config option has been renamed to `prerender.entries` ([#2380](https://github.com/sveltejs/kit/pull/2380)) - [breaking] The `prerender.pages` config option has been renamed to `prerender.entries` ([#2380](https://github.com/sveltejs/kit/pull/2380))
- A new generic argument has beend added to allow typing Body from hooks ([#2413](https://github.com/sveltejs/kit/pull/2413)) - A new generic argument has been added to allow typing Body from hooks ([#2413](https://github.com/sveltejs/kit/pull/2413))
- The `svelte` field will be added to package.json when running the package command ([#2431](https://github.com/sveltejs/kit/pull/2431)) - The `svelte` field will be added to package.json when running the package command ([#2431](https://github.com/sveltejs/kit/pull/2431))
- [breaking] The `context` parameter of the load function was renamed to `stuff` ([#2439](https://github.com/sveltejs/kit/pull/2439)) - [breaking] The `context` parameter of the load function was renamed to `stuff` ([#2439](https://github.com/sveltejs/kit/pull/2439))
- Added an `entryPoint` option for building a custom server with `adapter-node` ([#2414](https://github.com/sveltejs/kit/pull/2414)) - Added an `entryPoint` option for building a custom server with `adapter-node` ([#2414](https://github.com/sveltejs/kit/pull/2414))
@ -52,7 +52,7 @@ To see all updates to SvelteKit, check out the [SvelteKit changelog](https://git
- [hirehive](https://www.hirehive.com/) is a candidate and job tracking site - [hirehive](https://www.hirehive.com/) is a candidate and job tracking site
- [Microsocial](https://microsocial.xyz/) is an experimental Peer-to-Peer Social Platform - [Microsocial](https://microsocial.xyz/) is an experimental Peer-to-Peer Social Platform
- [Dylan Ipsum](https://www.dylanlyrics.app/) is a random text generator to replace lorem ipsum with Bob Dylan lyrics - [Dylan Ipsum](https://www.dylanlyrics.app/) is a random text generator to replace lorem ipsum with Bob Dylan lyrics
- [Chip8 Svelte](https://github.com/mikeyhogarth/chip8-svelte) is a CHIP-8 emulator frontend, built on top of CHIP8 Typescript - [Chip8 Svelte](https://github.com/mikeyhogarth/chip8-svelte) is a CHIP-8 emulator frontend, built on top of CHIP8 TypeScript
**Looking for a Svelte project to work on? Interested in helping make Svelte's presence on the web better?** Check out [the list of open issues](https://github.com/svelte-society/sveltesociety-2021/issues) if you'd like to contribute to the Svelte Society rewrite in SvelteKit. **Looking for a Svelte project to work on? Interested in helping make Svelte's presence on the web better?** Check out [the list of open issues](https://github.com/svelte-society/sveltesociety-2021/issues) if you'd like to contribute to the Svelte Society rewrite in SvelteKit.
@ -74,7 +74,7 @@ To see all updates to SvelteKit, check out the [SvelteKit changelog](https://git
**Libraries, Tools & Components** **Libraries, Tools & Components**
- [sveltekit-netlify-cms](https://github.com/buhrmi/sveltekit-netlify-cms) is a SvelteKit skeleton app configured for use with Netlify CMS - [sveltekit-netlify-cms](https://github.com/buhrmi/sveltekit-netlify-cms) is a SvelteKit skeleton app configured for use with Netlify CMS
- [SvelteFireTS](https://github.com/jacobbowdoin/sveltefirets) is a SvelteKit + Typescript + Firebase library inspired by Fireship.io - [SvelteFireTS](https://github.com/jacobbowdoin/sveltefirets) is a SvelteKit + TypeScript + Firebase library inspired by Fireship.io
- [stores-x](https://github.com/Anyass3/stores-x) lets you use Svelte stores just like vueX - [stores-x](https://github.com/Anyass3/stores-x) lets you use Svelte stores just like vueX
- [sveltekit-snippets](https://github.com/stordahl/sveltekit-snippets) is a VSCode extension that provides snippets for common patterns in SvelteKit & Vanilla Svelte - [sveltekit-snippets](https://github.com/stordahl/sveltekit-snippets) is a VSCode extension that provides snippets for common patterns in SvelteKit & Vanilla Svelte
- [svelte-xactor](https://github.com/wobsoriano/svelte-xactor) is a middleware that allows you to easily convert your xactor machines into a global store that implements the store contract - [svelte-xactor](https://github.com/wobsoriano/svelte-xactor) is a middleware that allows you to easily convert your xactor machines into a global store that implements the store contract
@ -92,7 +92,7 @@ Check out the community site [sveltesociety.dev](https://sveltesociety.dev/templ
## Before you go, answer the call for speakers! ## Before you go, answer the call for speakers!
Svelte Summit Fall 2021 (happening 20 November 2021) is looking for speakers. Submit your talk propsoal before 30 October... all are welcome to present and attend. Svelte Summit Fall 2021 (happening 20 November 2021) is looking for speakers. Submit your talk proposal before 30 October... all are welcome to present and attend.
### More info on the [sessionize site](https://sessionize.com/svelte-summit-fall-2021/) ### More info on the [sessionize site](https://sessionize.com/svelte-summit-fall-2021/)

@ -72,7 +72,7 @@ To see all updates to Svelte and SvelteKit, check out the [Svelte](https://githu
- [date-picker-svelte](https://github.com/probablykasper/date-picker-svelte) is a date and time picker for Svelte - [date-picker-svelte](https://github.com/probablykasper/date-picker-svelte) is a date and time picker for Svelte
- [TwelveUI](https://twelveui.readme.io/reference/what-is-twelveui) is a Svelte component library with accessibility built-in - [TwelveUI](https://twelveui.readme.io/reference/what-is-twelveui) is a Svelte component library with accessibility built-in
- [svelte-outclick](https://github.com/babakfp/svelte-outclick/) is a Svelte component that allows you to listen for clicks outside of an element, by providing you an outclick event - [svelte-outclick](https://github.com/babakfp/svelte-outclick/) is a Svelte component that allows you to listen for clicks outside of an element, by providing you an outclick event
- [svelte-zero-api](https://github.com/ymzuiku/svelte-zero-api) lets you use SvelteKit APIs like client functions - with support for Typescript - [svelte-zero-api](https://github.com/ymzuiku/svelte-zero-api) lets you use SvelteKit APIs like client functions - with support for TypeScript
- [svelte-recaptcha-v2](https://github.com/basaran/svelte-recaptcha-v2) is a Google reCAPTCHA v2 implementation for Svelte SPA, SSR and sveltekit static sites. - [svelte-recaptcha-v2](https://github.com/basaran/svelte-recaptcha-v2) is a Google reCAPTCHA v2 implementation for Svelte SPA, SSR and sveltekit static sites.
- [Svelte Body](https://github.com/ghostdevv/svelte-body) lets you apply styles to the body in routes - designed to work with SvelteKit and Routify. - [Svelte Body](https://github.com/ghostdevv/svelte-body) lets you apply styles to the body in routes - designed to work with SvelteKit and Routify.
- [svelte-debug-console](https://github.com/basaran/svelte-debug-console) is a debug.js implementation for Svelte SPA, SSR and sveltekit static sites that lets you see your debug statements in the browser. - [svelte-debug-console](https://github.com/basaran/svelte-debug-console) is a debug.js implementation for Svelte SPA, SSR and sveltekit static sites that lets you see your debug statements in the browser.

@ -41,7 +41,7 @@ More on that, and what else is new in Svelte, as we dive in...
**Apps & Sites built with Svelte** **Apps & Sites built with Svelte**
- [Launcher](https://launcher.team/) is an open-source app launcher powered by SvelteKit, Prisma, and Tailwind - [Launcher](https://launcher.team/) is an open-source app launcher powered by SvelteKit, Prisma, and Tailwind
- [Paaster](https://paaster.io/) is a secure by default end to end encrypted pastebin built with Svelte, Vite, Typescript, Python, Starlette, rclone & Docker. - [Paaster](https://paaster.io/) is a secure by default end to end encrypted pastebin built with Svelte, Vite, TypeScript, Python, Starlette, rclone & Docker.
- [Simple AF Video Converter](https://github.com/berlyozzy/Simple-AF-Video-Converter) is an Electron wrapper around ffmpeg.wasm to make converting videos between formats easier - [Simple AF Video Converter](https://github.com/berlyozzy/Simple-AF-Video-Converter) is an Electron wrapper around ffmpeg.wasm to make converting videos between formats easier
- [Streamchaser](https://github.com/streamchaser/streamchaser) seeks to simplify movie, series and documentary search through a centralized entertainment technology platform - [Streamchaser](https://github.com/streamchaser/streamchaser) seeks to simplify movie, series and documentary search through a centralized entertainment technology platform
- [Svelte Color Picker](https://github.com/V-Py/svelte-material-color-picker) is a simple color picker made with Svelte - [Svelte Color Picker](https://github.com/V-Py/svelte-material-color-picker) is a simple color picker made with Svelte
@ -89,7 +89,7 @@ _To Watch_
**Libraries, Tools & Components** **Libraries, Tools & Components**
- [SvelTable](https://sveltable.io/) is a feature rich, data table component built with Svelte - [SvelTable](https://sveltable.io/) is a feature rich, data table component built with Svelte
- [svelte-cyberComp](https://github.com/Cybersteam00/svelte-cyberComp) is a powerful, lightweight component library written in Svelte and Typescript - [svelte-cyberComp](https://github.com/Cybersteam00/svelte-cyberComp) is a powerful, lightweight component library written in Svelte and TypeScript
- [Flowbite Svelte](https://github.com/shinokada/flowbite-svelte) is an unofficial Flowbite component library for Svelte - [Flowbite Svelte](https://github.com/shinokada/flowbite-svelte) is an unofficial Flowbite component library for Svelte
- [Svelte-Tide-Project](https://github.com/jbertovic/svelte-tide-project) is a starter template for Svelte frontend apps with Rust Tide backend server - [Svelte-Tide-Project](https://github.com/jbertovic/svelte-tide-project) is a starter template for Svelte frontend apps with Rust Tide backend server
- [Fetch Inject](https://github.com/vhscom/fetch-inject#sveltekit) implements a performance optimization technique for managing asynchronous JavaScript dependencies - now with Svelte support - [Fetch Inject](https://github.com/vhscom/fetch-inject#sveltekit) implements a performance optimization technique for managing asynchronous JavaScript dependencies - now with Svelte support

@ -0,0 +1,113 @@
---
title: "What's new in Svelte: June 2022"
description: "Cancellable dispatched events, deeper {@const} declarations and more!"
author: Daniel Sandoval
authorURL: https://desandoval.net
---
With last month's [Svelte Summit](https://www.youtube.com/watch?v=qqj2cBockqE) behind us, we're ready to apply everything we learned in this new month of June! Also new this month are some quality-of-life changes to `createEventDispatcher`, `@const` declarations and tons of progress toward SvelteKit 1.0.
Let's dive in!
## What's new in Svelte
- Custom events can now be cancelled in the `createEventDispatcher` function (**3.48.0**, [Docs](https://svelte.dev/docs#run-time-svelte-createeventdispatcher), [PR](https://github.com/sveltejs/svelte/pull/7064))
- The `{@const}` tag can now be used in `{#if}` blocks to conditionally define variables (**3.48.0**, [Docs](https://svelte.dev/docs#template-syntax-const), [PR](https://github.com/sveltejs/svelte/pull/7451))
- Lots of bug fixes across `<svelte:element>`, animations and various DOM elements. Check out the [CHANGELOG](https://github.com/sveltejs/svelte/blob/master/CHANGELOG.md#3480) for a deeper dive!
## What's new in SvelteKit
- Vite 2.9.9 was released as one of the last Vite 2 releases. The Svelte team has been hard at work contributing to the the Vite 3 release to make the integration between SvelteKit and Vite smoother than ever ([Vite 3.0 Milestone](https://github.com/vitejs/vite/milestone/5))
- `config.kit.alias` lets you more easily declare a custom alias to replace values in `import` statements ([Docs](https://kit.svelte.dev/docs/configuration#alias), [PR](https://github.com/sveltejs/kit/pull/4964))
- Pages marked for prerendering will now fail during SSR at runtime ([PR](https://github.com/sveltejs/kit/pull/4812))
**Breaking Changes**
- Node 14 is no longer supported ([PR](https://github.com/sveltejs/kit/pull/4922))
- Requests to `/favicon.ico` will no longer be suppressed and will instead be handled as a valid route ([PR](https://github.com/sveltejs/kit/pull/5046))
- AMP support has been moved to a separate `@sveltejs/amp` package ([Docs](https://kit.svelte.dev/docs/seo#manual-setup-amp), [PR](https://github.com/sveltejs/kit/pull/4710))
- Generated types are now written to `_types` directories - update your imports accordingly ([PR](https://github.com/sveltejs/kit/pull/4705))
- `%svelte.head%` and `%svelte.body%` are now `%sveltekit.head%` and `%sveltekit.body%` in `app.html` ([Docs](https://kit.svelte.dev/docs/migrating#project-files-src-template-html), [PR](https://github.com/sveltejs/kit/pull/5016/))
- `LoadInput` is now `LoadEvent`
- Dropped support for Wrangler 1 in favor of Wrangler 2 ([PR](https://github.com/sveltejs/kit/pull/4887))
---
## Community Showcase
**Apps & Sites built with Svelte**
- [Plantarium](https://github.com/jim-fx/plantarium) is a tool for the procedural generation of 3D plants.
- [SPATULA](https://github.com/AlexWarnes/lamina-spatula) is a tool for building shading materials that are exportable as code material in any project that uses lamina and threejs
- [Waaard](https://waaard.com/) lets you create and send protected links with a variety of SSO providers
- [Magidoc](https://github.com/magidoc-org/magidoc) is a fast and highly customizable GraphQL documentation generator
- [myMarkmap](https://github.com/eyssette/myMarkmap) is a custom editor for Markmap, built with SvelteKit
- [PassShare](https://passshare.mynt.pw/) is a way for you to share your passwords to your friends, securely and effortlessly
- [DashingOS](https://beta.dashingos.com/) is a tool (like Notion + CodeSandbox) to make it quick and easy to prototype and document your work all in one place
- [worker-kit-email](https://github.com/miunau/worker-kit-email) helps you develop transactional emails quickly using regular SvelteKit routes
- [kaios-weather-svelte](https://github.com/cyan-2048/kaios-weather-svelte) is a very familiar looking weather app for KaiOS
- [svelte-gantt](https://github.com/ANovokmet/svelte-gantt) is a lightweight and fast interactive gantt chart/resource booking component
- [Miru](https://github.com/ThaUnknown/miru) is a BitTorrent streaming software for cats
Looking for a great SvelteKit website to contribute to? [Help build the Svelte Society site](https://github.com/svelte-society/sveltesociety.dev/issues)!
**Learning Resources**
_To Read_
- [Component party](https://component-party.dev/) is a site that compares common patterns in different frameworks
- [Quick tip: style prop defaults](https://geoffrich.net/posts/style-prop-defaults/) by Geoff Rich
- [Working with reduced motion in Svelte](https://ghostdev.xyz/posts/working-with-reduced-motion-in-svelte) by GHOST
- [Building a Musical Instrument with the Web Audio API](https://www.taniarascia.com/musical-instrument-web-audio-api/) by Tania Rascia
- [Svelte-Cubed: Creating an Accessible and Consistent Experience Across Devices](https://dev.to/alexwarnes/svelte-cubed-creating-an-accessible-and-consistent-experience-across-devices-42ae) and [Svelte-Cubed: Loading Your glTF Models](https://dev.to/alexwarnes/svelte-cubed-loading-your-gltf-models-14lf) by Alex Warnes
_To Watch_
From Svelte Society:
- [The Svelte Summit Spring 2022 stream recording](https://www.youtube.com/watch?v=qqj2cBockqE) has been updated with chapter markers to make it easy to watch again and again
- [The full recording of Svelte London, April 2022](https://www.youtube.com/watch?v=zIxzJzTnoxA) is up! Check out the amazing talks from across the Svelte London community
- [Persian Svelte Society](https://www.youtube.com/channel/UCfWH9lCsXN3j8oXq8dru82Q) is making Persian-language videos about Svelte
- Svelte Sirens has been talking monthly to creators and contributors across the Svelte Community:
- [SvelteKit + Sanity.io: a match made in heaven](https://www.youtube.com/watch?v=j0_1hfiEVWA&list=PL8bMgX1kyZThkJ_Rk6AAFI4eY24g5XKwK&index=5) on May 13
- [Slicing up your Svelte Sites with Prismic](https://www.youtube.com/watch?v=FUbHwwMALkk) on May 20
- [Rendering your Svelte apps on Render](https://www.youtube.com/watch?v=SnV_hMLVyqs) on May 24
- [The story behind the (unofficial) Svelte newsletter](https://www.youtube.com/watch?v=aK0xXm3hPxk&list=PL8bMgX1kyZThkJ_Rk6AAFI4eY24g5XKwK&index=7) on May 27
Across the Web:
- [Building vite-plugin-svelte-inspector](https://www.youtube.com/watch?v=udYB24IMtsY), [What is Singleton?](https://www.youtube.com/watch?v=xhi0m1QZue0) and [What is Navigation?](https://www.youtube.com/watch?v=Ym-OnGUps2c) by lihautan
- [Auto Import Components In Svelte Kit - Weekly Svelte](https://www.youtube.com/watch?v=JXvKBtTPr64) by LevelUpTuts
- [🧪 Test SvelteKit with TDD & VITEST 🧪](https://www.youtube.com/watch?v=5bQD3dCoyHA) by Johnny Magrippis
- [Google Analytics With SvelteKit](https://www.youtube.com/watch?v=l-x6H0fnqqQ), [Using WebSockets With SvelteKit](https://www.youtube.com/watch?v=mAcKzdW5fR8), [SvelteKit Authentication Using Cookies](https://www.youtube.com/watch?v=T935Ya4W5X0) and [Svelte Headless UI Component Library](https://www.reddit.com/r/sveltejs/comments/ueu849/svelte_headless_ui_component_library/) by Joy of Code
- [Named Layouts In Nested Routes in SvelteKit](https://www.youtube.com/watch?v=hKg_V3jouLk) by The Svelte Junction
- [SvelteKit Shiki Syntax Highlighting: Markdown Codeblocks](https://rodneylab.com/sveltekit-shiki-syntax-highlighting/) and [Svelte Capsize Styling: Typography Tooling](https://rodneylab.com/svelte-capsize-styling/) by Rodney Lab
_To Hear_
- Svelte Radio has been putting out weekly episodes:
- [The Adventures of Running a Svelte Meetup](https://www.svelteradio.com/episodes/the-adventures-of-running-a-svelte-meetup)
- [The other Rich! Geoff! (feat. Geoff Rich)](https://www.svelteradio.com/episodes/the-other-rich-geoff)
- [Inspecting Svelte Code with Dominik G.](https://www.svelteradio.com/episodes/inspecting-svelte-code-with-dominik-g)
- [Stores Galore](https://www.svelteradio.com/episodes/stores-galore)
- [Svelte and the Future of Frontend Development (feat. Rich Harris)](https://thenewstack.io/svelte-and-the-future-of-front-end-development/) from The New Stack
**Libraries, Tools & Components**
- [vite-plugin-svelte-console-remover](https://github.com/jhubbardsf/vite-plugin-svelte-console-remover) is a Vite plugin that removes all console statements (log, group, dir, error, etc) from Svelte, JS, and TS files during build so they don't leak into production
- [Svelte Headless Tables](https://github.com/bryanmylee/svelte-headless-table) is an unopinionated and extensible data tables for Svelte
- [y-presence](https://github.com/nimeshnayaju/y-presence) is a lightweight set of libraries to easily add presence (live cursors/avatars) to any web application (now with Svelte support!)
- [Svelcro](https://github.com/oslabs-beta/Svelcro) is a component performance tracker for Svelte applications
- [Svelte-Splitpanes](https://github.com/orefalo/svelte-splitpanes) lets you create dynamic and predictable view panels to layout an application
- [svelte-miniplayer](https://github.com/ThaUnknown/svelte-miniplayer) is a lightweight, fast, resizable and draggable miniplayer for media
- [svelte-keybinds](https://github.com/ThaUnknown/svelte-keybinds) is a minimalistic keybinding interface, with rebinding and saving
- [svelte-speech-recognition](https://github.com/jhubbardsf/svelte-speech-recognition) converts speech from the microphone to text and makes it available to your Svelte components
**Special Feature: Svelte Stores**
There were lots of Svelte stores released this month from a number of authors...
- [svelte-mutable-store](https://github.com/feltcoop/svelte-mutable-store) is a Svelte store for mutable values with the `immutable` compiler option
- [svelte-damped-store](https://github.com/aredridel/svelte-damped-store) is a derived writable store that can suspend updates while [svelte-lens-store](https://github.com/aredridel/svelte-lens-store) is a functional lens over Svelte stores
- [svelte-persistent-store](https://github.com/furudean/svelte-persistent-store) is a writable svelte store that saves and loads data from `Window.localStorage` or `Window.sessionStorage`.
Did we miss anything? Join us on [Reddit](https://www.reddit.com/r/sveltejs/) or [Discord](https://discord.com/invite/yy75DKs) to add your voice.
Don't forget that you can also join us in-person at the Svelte Summit in Stockholm! Come join us for two days of awesome Svelte content! [Get your tickets now](https://ti.to/svelte/svelte-summit-fall-edition).
See y'all next month!

@ -0,0 +1,98 @@
---
title: "What's new in Svelte: July 2022"
description: "Faster SSR, language tools improvements and a new paid contributor!"
author: Daniel Sandoval
authorURL: https://desandoval.net
---
From faster SSR to support for Vitest and Storybook in SvelteKit, there's a lot to cover in this month's newsletter...
So let's dive in!
## OpenCollective funding drives Svelte forward
Svelte supporters have donated approximately $80,000 to [the project on OpenCollective](https://opencollective.com/svelte). We're happy to share that the funds are being drawn on to move Svelte forward in a meaningful way. **[@gtm-nayan](https://github.com/gtm-nayan)** has begun triaging and fixing SvelteKit issues this past month as a paid contributor to the project to help us get SvelteKit to a 1.0 level of stability! @gtm-nayan has been an active member of the Svelte community for quite some time and is well known for writing the bot that helps keep our Discord server running. We're happy that this funding has allowed Svelte to get much more of his time.
We will also be utilizing OpenCollective funds to allow Svelte core maintainers to attend [Svelte Summit](https://www.sveltesummit.com/) in person this fall. Thanks to everyone who has donated so far!
## What's new in Svelte & Language Tools
- [learn.svelte.dev](https://learn.svelte.dev/) is a new way to learn Svelte and SvelteKit from the ground up that is currently in development
- Faster SSR is coming in the next Svelte release. A PR two years in the making, resulting in up to 3x faster rendering in some benchmarking tests! ([PR](https://github.com/sveltejs/svelte/pull/5701))
- "Find File References" ([0.14.28](https://github.com/sveltejs/language-tools/releases/tag/language-server-0.14.28)) and "Find Component References" ([0.14.29](https://github.com/sveltejs/language-tools/releases/tag/language-server-0.14.29)) in the latest versions of the Svelte extension shows where Svelte files and components have been imported and used ([Demo](https://twitter.com/dummdidumm_/status/1532459709604716544/photo/1))
- The Svelte extension now supports CSS path completion ([0.14.29](https://github.com/sveltejs/language-tools/releases/tag/language-server-0.14.29))
## What's new in SvelteKit
- Introduced `@sveltejs/kit/experimental/vite` which allows SvelteKit to interoperate with other tools in the Vite ecosystem like Vitest and Storybook ([#5094](https://github.com/sveltejs/kit/pull/5094)). Please [leave feedback](https://github.com/sveltejs/kit/issues/5184) as to whether the feature works and is helpful as we consider taking it out of experimental and making `vite.config.js` required for all users
- Streaming in endpoints is now supported ([#3419](https://github.com/sveltejs/kit/issues/3419)). This was enabled by switching to the Undici `fetch` implementation ([#5117](https://github.com/sveltejs/kit/pull/5117))
- Static assets can now be symlinked in development environments ([#5089](https://github.com/sveltejs/kit/pull/5089))
- `server` and `prod` environment variables are now available as a correlary to `browser` and `dev` ([#5251](https://github.com/sveltejs/kit/pull/5251))
---
## Community Showcase
**Apps & Sites built with Svelte**
- [Virtual Maker](https://www.virtualmaker.net/) lets you make interactive 3D and VR scenes in your browser
- [Apple Beta Music](https://www.reddit.com/r/sveltejs/comments/v7ic2s/apple_beta_music_uses_svelte/) appears to have been written in some combination of Svelte and web components
- [Itatiaia](https://www.itatiaia.com.br/), the largest radio station in the country of Brazil just relaunched its news portal in SvelteKit
- [Pronauns](https://www.pronauns.com) helps you learn pronunciation online with IPA to speak better and sound more native
- [Immich](https://www.immich.app/) is an open source, high performance self-hosted backup solution for videos and photos on your mobile phone
- [Pendek](https://github.com/leovoon/link-shortener) is a link shortener built with SvelteKit, Prisma and PlanetScale
- [Grunfy](https://grunfy.com/tools) is a set of guitar tools - recently migrated to SvelteKit
- [Radiant: The Future of Radio](https://play.google.com/store/apps/details?id=co.broadcastapp.Radiant) is a personal radio station app built with Svelte and Capacitor
- [Imperfect Reminders](https://imperfectreminders.mildlyupset.com/) is a todo list for things that are only sort of time sensitive
- [Periodic Table](https://github.com/janosh/periodic-table) is a dynamic Periodic Table component written in Svelte
- [Svelvet](https://github.com/open-source-labs/Svelvet) is a lightweight Svelte component library for building interactive node-based diagrams
- [publint](https://github.com/bluwy/publint) lints for packaging errors to ensure compatibility across environments
- [Playlistr](https://github.com/alextana/spotify-playlist-creator) helps manage and create Spotify playlists
- [Geoff Rich's page transitions demo](https://twitter.com/geoffrich_/status/1534980702785003520) shows how SvelteKit's `beforeNavigate`/`afterNavigate` hooks can make smooth document transitions in the latest Chrome Canary
- [Menger Sponge](https://twitter.com/a_warnes/status/1536215896078811137) is a fractal built with Threlte
Want to contribute to a site using the latest SvelteKit features? [Help build the Svelte Society site](https://github.com/svelte-society/sveltesociety.dev/issues)!
**Learning Resources**
_Starring the Svelte team_
- [Svelte Origins: A JavaScript Documentary](https://www.youtube.com/watch?v=kMlkCYL9qo0) by OfferZen Origins
- [Full Stack Documentation (announcing learn.svelte.dev)](https://portal.gitnation.org/contents/full-stack-documentation) by Rich Harris @ JSNation 2022
- [All About the Sirens](https://www.svelteradio.com/episodes/all-about-the-sirens) by Svelte Radio
_To Watch_
- [SvelteKit Page Endpoints](https://www.youtube.com/watch?v=yQRf2wmTu5w), [Named Layouts](https://www.youtube.com/watch?v=UHX9TJ0BxZY) and [Passing data from page component to layout component with $page.stuff](https://www.youtube.com/watch?v=CXaCstU5pcw) by lihautan
- [🍞 & 🧈: Magically load data with SvelteKit Endpoints](https://www.youtube.com/watch?v=f6prqYlbTE4) by Johnny Magrippis
- [Svelte for React developers](https://www.youtube.com/watch?v=7tsrwrx5HtQ) by frontendtier
- [Learn Svelte JS || Javascript Compiler for Building Front end Applications](https://www.youtube.com/watch?v=1rKRarJJFrY&list=PLIGDNOJWiL1-7zCgdR7MKuho-tPC6Ra6C&index=1) by Code with tsksharma
- [SvelteKit Authentication](https://www.youtube.com/watch?v=T935Ya4W5X0&list=PLA9WiRZ-IS_zKrDzhOhV5RGKKTHNIyTDO&index=1) by Joy of Code
- [Svelte + websockets: Build a real-time Auction app](https://www.youtube.com/watch?v=CqgsWFrwQIU) by Evgeny Maksimov
_To Read_
- [Up-To-Date Analytics on a Static Website](https://paullj.github.io/posts/up-to-date-analytics-on-a-static-website) and [Fast, Lightweight Fuzzy Search using Fuse.js](https://paullj.github.io/posts/fast-lightweight-fuzzy-search-using-fuse.js) by paullj
- [Use SvelteKit as a handler in the ExpressJs project](https://chientrm.medium.com/use-sveltekit-as-a-handler-in-the-expressjs-project-15524b01128f) by Tran Chien
- [Creating a desktop application with Tauri and SvelteKit](https://github.com/Stijn-B/tauri-sveltekit-example) by Stijn-B
- [List of awesome Svelte stores](https://github.com/samuba/awesome-svelte-stores) by samuba
- [SvelteKit Content Security Policy: CSP for XSS Protection](https://rodneylab.com/sveltekit-content-security-policy/) by Rodney Lab
- [SvelteKit Hooks. Everything You Need To Know](https://kudadam.com/blog/understanding-sveltekit-hooks) by Lucretius K. Biah
- [3 tips for upgrading the performance of your Svelte stores](https://www.mathiaspicker.com/posts/3-tips-for-upgrading-the-performance-of-your-svelte-stores) by Mathias Picker
**Libraries, Tools & Components**
- [Svend3r](https://github.com/oslabs-beta/svend3r) is a plug and play D3 charting library for Svelte
- [Svelte Hover Draw SVG](https://github.com/davipon/svelte-hover-draw-svg) is a lightweight Svelte component to draw SVG on hover
- [Svelte French Toast](https://svelte-french-toast.com/) provides buttery smooth toast notifications that are lightweight, customizable, and beautiful by default
- [SVooltip](https://svooltip.vercel.app/) is a basic Svelte tooltip directive, powered by Floating UI
- [Svelte Brick Gallery](https://github.com/anotherempty/svelte-brick-gallery) is a masonry-like image gallery component for Svelte
- [use-vest](https://github.com/enyo/use-vest) is a Svelte action for Vest - a library that makes it easy to validate forms and show errors when necessary
- [Svelidate](https://github.com/svelidate/svelidate) is a simple and lightweight form validation library for Svelte with no dependencies
- [Svve11](https://github.com/oslabs-beta/Svve11) is an "accessbility-first" component library for Svelte
- [Slidy](https://github.com/Valexr/Slidy) is a simple, configurable & reusable carousel sliding action script with templates & some useful plugins
- [Svelte Component Snippets](https://marketplace.visualstudio.com/items?itemName=brysonbw.svelte-component-snippets) is a VS Code extension with access to common Svelte snippets
- [Svelte Confetti](https://github.com/Mitcheljager/svelte-confetti) adds a little bit of flair to your app with some confetti 🎊
What did we miss? Let us know on [Reddit](https://www.reddit.com/r/sveltejs/) or [Discord](https://discord.com/invite/yy75DKs) to add your voice.
Don't forget that you can also join us in-person at the Svelte Summit in Stockholm! Come join us for two days of awesome Svelte content! [Get your tickets now](https://www.sveltesummit.com/).
See y'all next month!

@ -0,0 +1,119 @@
---
title: "What's new in Svelte: August 2022"
description: "Changes to SvelteKit's `load` before 1.0 plus support for Vite 3 and `vite.config.js`!"
author: Daniel Sandoval
authorURL: https://desandoval.net
---
There's a lot to cover this month... big changes are coming to SvelteKit's design before 1.0 can be completed. If you haven't already, check out Rich's Discussion, [Fixing `load`, and tightening up SvelteKit's design before 1.0 #5748](https://github.com/sveltejs/kit/discussions/5748).
Also, [@dummdidumm](https://github.com/dummdidumm) (Simon H) [has joined Vercel to work on Svelte full-time](https://twitter.com/dummdidumm_/status/1549041206348222464) and [@tcc-sejohnson](https://github.com/tcc-sejohnson) has joined the group of SvelteKit maintainers! We're super excited to have additional maintainers now dedicated to working on Svelte and SvelteKit and have already been noticing their impact. July was the third largest month for SvelteKit changes since its inception!
Now onto the rest of the updates...
## What's new in SvelteKit
- Dynamically imported styles are now included during SSR ([#5138](https://github.com/sveltejs/kit/pull/5138))
- Improvements to routes and prop updates to prevent unnecessary rerendering ([#5654](https://github.com/sveltejs/kit/pull/5654), [#5671](https://github.com/sveltejs/kit/pull/5671))
- Lots of improvements to error handling ([#4665](https://github.com/sveltejs/kit/pull/4665), [#5622](https://github.com/sveltejs/kit/pull/5622), [#5619](https://github.com/sveltejs/kit/pull/5619), [#5616](https://github.com/sveltejs/kit/pull/5616))
- Custom Vite modes are now respected in SSR builds ([#5602](https://github.com/sveltejs/kit/pull/5602))
- Custom Vite config locations are now supported ([#5705](https://github.com/sveltejs/kit/pull/5705))
- Private environment variables (aka "secrets") are now much more secure. Now if you accidentally import them to client-side code, you'll see an error ([#5663](https://github.com/sveltejs/kit/pull/5663), [Docs](https://kit.svelte.dev/docs/configuration#env))
- Vercel's v3 build output API is now being used in `adapter-vercel` ([#5514](https://github.com/sveltejs/kit/pull/5514))
- `vite-plugin-svelte` has reached 1.0 and now supports Vite 3. You'll notice new default ports for `dev` (port 5173) and `preview` (port 4173) ([#5005](https://github.com/sveltejs/kit/pull/5005), [vite-plugin-svelte CHANGELOG](https://github.com/sveltejs/vite-plugin-svelte/blob/main/packages/vite-plugin-svelte/CHANGELOG.md))
**Breaking changes:**
- `mode`, `prod` and `server` are no longer available in `$app/env` ([#5602](https://github.com/sveltejs/kit/pull/5602))
- `svelte-kit` CLI commands are now run using the `vite` command and `vite.config.js` is required. This will allow first-class support with other projects in the Vite ecosystem like Vitest and Storybook ([#5332](https://github.com/sveltejs/kit/pull/5332), [Docs](https://kit.svelte.dev/docs/project-structure#project-files-vite-config-js))
- `endpointExtensions` is now `moduleExtensions` and can be used to filter param matchers ([#5085](https://github.com/sveltejs/kit/pull/5085), [Docs](https://kit.svelte.dev/docs/configuration#moduleextensions))
- Node 16.9 is now the minimum version for SvelteKit ([#5395](https://github.com/sveltejs/kit/pull/5395))
- %-encoded filenames are now allowed. If you had a `%` in your route, you must now encode it with `%25` ([#5056](https://github.com/sveltejs/kit/pull/5056))
- Endpoint method names are now uppercased to match HTTP specifications ([#5513](https://github.com/sveltejs/kit/pull/5513), [Docs](https://kit.svelte.dev/docs/routing#endpoints))
- `writeStatic` has been removed to align with Vite's config ([#5618](https://github.com/sveltejs/kit/pull/5618))
- `transformPage` is now `transformPageChunk` ([#5657](https://github.com/sveltejs/kit/pull/5657), [Docs](https://kit.svelte.dev/docs/hooks#handle))
- The `prepare` script is no longer needed in `package.json` ([#5760](https://github.com/sveltejs/kit/pull/5760))
- `adapter-node` no longer does any compression while we wait for a [bug fix in the `compression` library](https://github.com/expressjs/compression/pull/183) ([#5560](https://github.com/sveltejs/kit/pull/5506))
For a full list of changes, check out kit's [CHANGELOG](https://github.com/sveltejs/kit/blob/master/packages/kit/CHANGELOG.md).
## What's new in Svelte & Language Tools
- The `@layer` [CSS at-rule](https://developer.mozilla.org/en-US/docs/Web/CSS/@layer) is now supported in Svelte components (**3.49.0**, [PR](https://github.com/sveltejs/svelte/issues/7504))
- The `inert` [HTML attribute](https://html.spec.whatwg.org/multipage/interaction.html#the-inert-attribute) is now supported in Svelte's language tools and plugins (**105.20.0**, [PR](https://github.com/sveltejs/language-tools/pull/1565))
- The Svelte plugin will now use `SvelteComponentTyped` typings, if available (**105.19.0**, [PR](https://github.com/sveltejs/language-tools/pull/1548))
---
## Community Showcase
**Apps & Sites built with Svelte**
- [PocketBase](https://github.com/pocketbase/pocketbase) is an open source Go backend with a single file and an admin dashboard built with Svelte
- [Hondo](https://www.playhondo.com/how-to-play) is a word guessing game with multiple rounds
- [Hexapipes](https://github.com/gereleth/hexapipes) is a site for playing hexagonal pipes puzzle
- [Mail Must Move](https://www.mordon.app/) is an email made for those who want to get more done
- [Jot Down](https://github.com/brysonbw/vscode-jot-down) is a Visual Studio Code extension for quick and simple note taking
- [Kadium](https://kadium.kasper.space/) is an app for staying on top of YouTube channels' uploads
- [Samen zjin we #1metS10](https://1mets10.avrotros.nl/) is a campaign website to support S10, the dutch Eurovision finalist, by sending a drawing or a wish
- [On Writing Code](https://onwritingcode.com/) is an interactive website to learn programming design patterns
- [Svelte-In-Motion](https://github.com/novacbn/svelte-in-motion) lets you create Svelte-animated videos in your browser
- [Svelte Terminal](https://github.com/Nico-Mayer/svelte-terminal) is a terminal-like website
- [Bulletlist](https://bulletlist.com/) is a simple tool with a single purpose: making lists
- [Remind Me Again](https://github.com/probablykasper/remind-me-again) is an app for toggleable reminders on Mac, Linux and Windows
- [Heyweek](https://heyweek.com/) is a timetracking app built for freelancers craving that extra pizzazz
**Learning Resources**
_Starring the Svelte team_
- [The Svelte Documentary is out!](https://www.svelteradio.com/episodes/the-svelte-documentary-is-out) on Svelte Radio
- [Beginner SvelteKit](https://vercel.com/docs/beginner-sveltekit) by Vercel
- [Challenge: Explore Svelte by Building a Bubble Popping Game](https://prismic.io/blog/try-svelte-build-game) by Brittney Postma
- [Let's write a Client-side Routing Library with Svelte](https://www.youtube.com/watch?v=3foVDSknGEY) by lihautan
- [Svelte Sirens July Talk - Testing in Svelte with Jess Sachs](https://sveltesirens.dev/event/testing-in-svelte)
_To Watch_
- [10 Awesome Svelte UI Component Libraries](https://www.youtube.com/watch?v=RkD88ARvucM) by LevelUpTuts
- [Learn How SvelteKit Works](https://www.youtube.com/watch?v=VizuTy3uSNE) and [SvelteKit Endpoints](https://www.youtube.com/watch?v=XnVxDLTgCgo) by Joy of Code
- [SvelteKit using TS, and Storybook setup](https://www.youtube.com/watch?v=L4F5dSu0FcQ) by Jarrod Kane
- [Building Apps with Svelte!](https://www.youtube.com/watch?v=prsXVk1fdW4) by Simon Grimm
- [SvelteKit authentication, the better way - Tutorial](https://www.youtube.com/watch?v=Y98KipzwVdM) by Pilcrow
_To Read_
- [Some assorted Svelte demos](https://geoffrich.net/posts/assorted-svelte-demos/) by Geoff Rich
- [Three ways to bootstrap a Svelte project](https://maier.tech/posts/three-ways-to-bootstrap-a-svelte-project) by Thilo Maier
- [Design & build an app with Svelte](https://bootcamp.uxdesign.cc/design-build-an-app-with-svelte-ecd7ed0729da) by Hugo
- [Define routes via JS in SvelteKit](https://dev.to/maxcore/define-routes-via-js-in-sveltekit-27e9) by Max Core
- [Integrating Telegram api with SvelteKit](https://dev.to/theether0/integrating-telegram-api-with-sveltekit-5gb) by Shivam Meena
- [SvelteKit SSG: how to Prerender your SvelteKit Site](https://rodneylab.com/sveltekit-ssg/) by Rodney Lab
- [ADEO Design System: Building a Web Component library with Svelte and Rollup](https://medium.com/adeo-tech/adeo-design-system-building-a-web-component-library-with-svelte-and-rollup-72d65de50163) by Mohamed Mokhtari
- [The Svelte Handbook](https://thevalleyofcode.com/svelte/) by The Valley of Code
- [Test Svelte Component Using Vitest & Playwright](https://davipon.hashnode.dev/test-svelte-component-using-vitest-playwright) by David Peng
- [Transitional Apps with Phoenix and Svelte](https://nathancahill.com/phoenix-svelte) by Nathan Cahill
_Tech Demos_
- [Bringing the best GraphQL experience to Svelte](https://www.the-guild.dev/blog/houdini-and-kitql) by The Guild
- [Style your Svelte website faster with Stylify CSS](https://stylifycss.com/blog/style-your-svelte-website-faster-with-stylify-css/) by Stylify
- [Revamped Auth Helpers for Supabase (with SvelteKit support)](https://supabase.com/blog/2022/07/13/supabase-auth-helpers-with-sveltekit-support) by Supabase
**Libraries, Tools & Components**
- [Lucia](https://github.com/pilcrowOnPaper/lucia-sveltekit) is a simple, JWT based authentication library for SvelteKit that connects your SvelteKit app with your database
- [Skeleton](https://github.com/Brain-Bones/skeleton) is a UI component library for use with Svelte + Tailwind
- [pass-composer](https://pass-composer.vercel.app/) helps you compose your postprocessing passes for threlte scenes
- [@crikey/stores-*](https://whenderson.github.io/stores-mono/) is a collection of libraries to extend Svelte stores for common use-cases
- [Svelte Chrome Storage](https://github.com/shaun-wild/svelte-chrome-storage) is a lightweight abstraction between Svelte stores and Chrome extension storage
- [Svelte Schema Form](https://github.com/restspace/svelte-schema-form) is a form generator for JSON schema
- [svelte-gesture](https://github.com/wobsoriano/svelte-gesture) is a library that lets you bind richer mouse and touch events to any component or view
- [Snap Layout](https://github.com/ThaUnknown/snap-layout) and [universal-title-bar](https://github.com/ThaUnknown/universal-title-bar) bring Windows 11 snap layout and title features to webapps and PWAs. Both can be imported as a `.svelte` module or as a web component
- [svelte-adapter-bun](https://github.com/gornostay25/svelte-adapter-bun) is an adapter for SvelteKit apps that generates a standalone Bun server
- [json2dir](https://www.npmjs.com/package/json2dir) converts JSON objects into directory trees
- [Svelte Command Palette](https://github.com/rohitpotato/svelte-command-palette) is a drop-in command palette component
- [svelte-use-drop-outside](https://github.com/untemps/svelte-use-drop-outside) is a Svelte action to drop an element outside an area
- [PowerTable](https://github.com/muonw/powertable) is a JavaScript component that turns JSON data into an interactive HTML table
- [svelte-slides](https://github.com/rajasegar/svelte-slides) is a slide show template for Svelte using Reveal.js
- [Svelte Theme Light](https://marketplace.visualstudio.com/items?itemName=webmaek.svelte-theme-light) is a Visual Studio Code theme based on the Svelte REPL
Did we miss anything? Let us know on [Reddit](https://www.reddit.com/r/sveltejs/) or [Discord](https://discord.com/invite/yy75DKs)!
Still looking for something to do in September? Come join us at the Svelte Summit in Stockholm! [Get your tickets now](https://www.sveltesummit.com/).
See ya next month!

@ -0,0 +1,105 @@
---
title: "What's new in Svelte: September 2022"
description: "Migrating to SvelteKit's new filesystem-based router"
author: Daniel Sandoval
authorURL: https://desandoval.net
---
Still looking for something to do this month? It's your last chance to get tickets to Svelte Summit, Stockholm! [Join us on Sept 8-9th](https://www.sveltesummit.com/) 🎉
With the redesign of SvelteKit's filesystem-based router merging early last month, there's lots to cover this month - from the [migration script](https://github.com/sveltejs/kit/discussions/5774) to a number of new blog posts, videos and tutorials.
But the new routing isn't the only new feature in SvelteKit...
## What's new in SvelteKit
- `Link` is now supported as an HTTP header and works out of the box with Cloudflare's [Automatic Early Hints](https://github.com/sveltejs/kit/issues/5455) (**1.0.0-next.405**, [PR](https://github.com/sveltejs/kit/pull/5735))
- `$env/static/*` are now virtual to prevent writing sensitive values to disk (**1.0.0-next.413**, [PR](https://github.com/sveltejs/kit/pull/5825))
- `$app/stores` can now be used from anywhere on the browser (**1.0.0-next.428**, [PR](https://github.com/sveltejs/kit/pull/6100))
- `config.kit.env.dir` is a new config that sets the directory to search for `.env` files (**1.0.0-next.430**, [PR](https://github.com/sveltejs/kit/pull/6175))
**Breaking changes:**
- The filesystem-based router and `load` API improves the way routes are managed. **Before installing version `@sveltejs/kit@1.0.0-next.406` or later, [follow this migration guide](https://github.com/sveltejs/kit/discussions/5774)** ([PR](https://github.com/sveltejs/kit/pull/5778), [Issue](https://github.com/sveltejs/kit/discussions/5748))
- `event.session` has been removed from `load` along with the `session` store and `getSession`. Use `event.locals` instead (**1.0.0-next.415**, [PR](https://github.com/sveltejs/kit/pull/5946))
- Named layouts have been removed in favor of `(groups)` (**1.0.0-next.432**, [Docs](https://kit.svelte.dev/docs/advanced-routing#advanced-layouts), [PR & Migration Instructions](https://github.com/sveltejs/kit/pull/6174))
- `event.clientAddress` is now `event.getClientAddress()` (**1.0.0-next.438**, [PR](https://github.com/sveltejs/kit/pull/6237))
- `$app/env` has been renamed to `$app/environment`, to disambiguate with `$env/...` (**1.0.0-next.445**, [PR](https://github.com/sveltejs/kit/pull/6334))
For a full list of changes, check out kit's [CHANGELOG](https://github.com/sveltejs/kit/blob/master/packages/kit/CHANGELOG.md).
**Updates to language tools**
- TypeScript doesn't resolve imports to SvelteKit's $types very well, the latest version of Svelte's language tools makes it better (**105.21.0**, [#1592](https://github.com/sveltejs/language-tools/pull/1592))
---
## Community Showcase
**Apps & Sites built with Svelte**
- [canno](https://twitter.com/a_warnes/status/1556724034959818754?s=20&t=RyKWALPByqMT5A_PkLtUew) is a simple interactive 3d physics game with adjustable gravity, cannon power, and debug visualizer - made with threlte
- [straw.page](https://straw.page/) is an extremely simple website builder that lets you create unique websites straight from your phone
- [Patra](https://patra.webjeda.com/) lets you share short notes just with a link. No database. No storage
- [promptoMANIA](https://promptomania.com/) is an AI art community with an online prompt builder
- [Album by Mood](https://www.albumbymood.com/) lets you listen to music based on your mood
- [Daily Sumeiro](https://digivaux.com/sumeiro/daily/) is a daily game to test your math and logic skills
- [Lofi and Games](https://www.lofiandgames.com/) - play relaxing, casual games right from your browser
- [Pitch Pipe](https://github.com/joelgibson/pitch-pipe) is a digital pitch pipe with a frequency analyser and just-intonation intervals
- [classes.wtf](https://github.com/ekzhang/classes.wtf) is a custom, distributed search engine written in Go and Svelte to make searching for Harvard courses much quicker than the standard course catalog
- [Scrumpack](https://scrumpack.io/) is a set of tools to help agile/scrum teams with their ceremonies like Planning Poker and Retrospectives
**Learning Resources**
_Starring the Svelte team_
- [Supper Club × Rich Harris, Author of Svelte — Syntax Podcast 499](https://syntax.fm/show/499/supper-club-rich-harris-author-of-svelte)
- [Let's talk routing with Rich Harris on Svelte Radio](https://www.svelteradio.com/episodes/lets-talk-routing-with-rich-harris)
- [2.17 - Building the Future of Svelte at Vercel with Rich Harris](https://www.youtube.com/watch?v=F1sSUDVoij4)
- [1.15 - What's Up With SvelteKit with Shawn Wang (swyx)](https://www.youtube.com/watch?v=xLhuUShkYkM)
- [Adding Notion Tailwindcss and DaisyUI to Svelte App](https://www.youtube.com/watch?v=l4sbqrY0XGk)
- [Svelte 101 Session](https://www.youtube.com/watch?v=IIeBERpyxx4)
- [Astro and Svelte](https://www.youtube.com/watch?v=iYKKg-50Gm4)
- [Storyblok in Svelte](https://www.youtube.com/watch?v=xXHFRzqUxoE)
- [Svelte London August Recording](https://www.youtube.com/watch?v=ua6gE2zPulw)
_Learning the new SvelteKit routing_
- [Migrating Breaking Changes in SvelteKit](https://www.netlify.com/blog/migrating-breaking-changes-in-sveltekit/) by Brittney Postma (Netlify)
- [Major Svelte Kit API Change - Fixing `load`, and tightening up SvelteKit's design before 1.0](https://www.youtube.com/watch?v=OUGn7VifUCg) - Video by LevelUpTuts
- [SvelteKit Is Never Going To Be The Same](https://www.youtube.com/watch?v=eVFcGA-15LA) - Video by Joy of Code
- [Let's learn SvelteKit by building a static Markdown blog from scratch](https://joshcollinsworth.com/blog/build-static-sveltekit-markdown-blog) by Josh Collinsworth (updated Aug 26th to keep up with the new changes)
_To Watch_
- [Svelte Guide For React Developers](https://www.youtube.com/watch?v=uWDBEUkTRGk) and [Svelte State Management Guide](https://www.youtube.com/watch?v=4dDjQiOVrOo) by Joy of Code
- [What Is Bookit? The Svelte Kit Storybook Killer](https://www.youtube.com/watch?v=aOBGhvggsq0) and [What Is @type{import In Svelte Kit - JSDoc Syntax](https://www.youtube.com/watch?v=y0DvJTVO65M) by LevelUpTuts
- [TWF Yet another JS Framework... or not? Svelte!](https://www.youtube.com/watch?app=desktop&v=nT8QtDBIKZA) by TWF meetup
_To Read_
- [Creating a Figma Plugin with Svelte](https://www.lekoarts.de/javascript/creating-a-figma-plugin-with-svelte) by Lennart
- [Svelte Video Blog: Vlog with Mux from your own SvelteKit Site](https://plus.rodneylab.com/tutorials/svelte-video-blog) and [Svelte Shy Header: Peekaboo Sticky Header with CSS](https://rodneylab.com/svelte-shy-header/) by Rodney Lab
**Libraries, Tools & Components**
- [@svelte-plugins/tooltips](https://github.com/svelte-plugins/tooltips) is a simple tooltip action and component designed for Svelte
- [Lucia](https://github.com/pilcrowOnPaper/lucia-sveltekit) is a simple authentication library for SvelteKit that connects your SvelteKit app to your database
- [remix-router-svelte](https://github.com/brophdawg11/remix-routers/tree/main/packages/svelte) is a Svelte implementation of the `react-router-dom` API (driven by `@remix-run/router`)
- [MKRT](https://github.com/j4w8n/mkrt) is a CLI to help you create SvelteKit routes, fast
- [Histoire](https://histoire.dev/guide/) is a tool to generate stories applications - scenarios where you showcase components for specific use cases
- [sveltekit-flash-message](https://www.npmjs.com/package/sveltekit-flash-message) is a Sveltekit library that passes temporary data to the next request, usually from endpoints
- [svelte-particles](https://github.com/matteobruni/tsparticles#svelte) is a lightweight TypeScript library for creating particles
- [svelte-claps](https://github.com/bufgix/svelte-claps) adds clap button (like Medium) to any page for your SvelteKit apps
- [Neon Flicker](https://svelte.dev/repl/fd5e3b2be7da42fe8afddf89661af7d7?version=3.49.0) is a Svelte component to make your text flicker in a cyberpunk style
- [ComboBox](https://svelte.dev/repl/144f22d18c6943abb1fdd00f13e23fde?version=3.49.0) is a search input to help users select from a large list of items
- [@svelte-put](https://github.com/vnphanquang/svelte-put) is useful svelte stuff to put in your projects
- [vite-plugin-svelte-bridge](https://github.com/joshnuss/vite-plugin-svelte-bridge) lets you write Svelte components and use them from React & Vue
_UI Kits and Starters_
- [Svelte-spectre](https://github.com/basf/svelte-spectre) is a UI-kit based on spectre.css and powered by Svelte
- [Skeleton](https://skeleton.brainandbonesllc.com/) allows you to build fast and reactive web UI using the power of Svelte + Tailwind
- [iconsax-svelte](https://www.npmjs.com/package/iconsax-svelte) brings the popular icon kit to Svelte
- [laravel-vite-svelte-spa-template](https://github.com/NukeJS/laravel-vite-svelte-spa-template) is a Laravel 9, Vite, Svelte SPA, Tailwind CSS (w/ Forms Plugin & Aspect Ratio Plugin), Axios, & TypeScript starter template
- [neutralino-svelte-boilerplate-js](https://github.com/Raffaele/neutralino-svelte-boilerplate-js) is a cross platform desktop template for Neutralino and Svelte
- [figma-plugin-svelte-vite](https://github.com/candidosales/figma-plugin-svelte-vite) is a boilerplate for creating Figma plugins using Svelte, Vite and Typescript
- [Urara](https://github.com/importantimport/urara) is a sweet & powerful SvelteKit blog starter
- [SvelteKit Commerce](https://vercel.com/templates/svelte/sveltekit-commerce) is an all-in-one starter kit for high-performance e-commerce sites built with SvelteKit by Vercel
Did we miss anything? Let us know on [Reddit](https://www.reddit.com/r/sveltejs/) or [Discord](https://discord.com/invite/yy75DKs)!
See ya next month!

@ -55,9 +55,7 @@ In development mode (see the [compiler options](/docs#compile-time-svelte-compil
--- ---
If you export a `const`, `class` or `function`, it is readonly from outside the component. Function *expressions* are valid props, however. If you export a `const`, `class` or `function`, it is readonly from outside the component. Functions are valid prop values, however, as shown below.
Readonly props can be accessed as properties on the element, tied to the component using [`bind:this` syntax](/docs#template-syntax-component-directives-bind-this).
```sv ```sv
<script> <script>
@ -73,6 +71,8 @@ Readonly props can be accessed as properties on the element, tied to the compone
</script> </script>
``` ```
Readonly props can be accessed as properties on the element, tied to the component using [`bind:this` syntax](/docs#template-syntax-component-directives-bind-this).
--- ---
You can use reserved words as prop names. You can use reserved words as prop names.
@ -125,15 +125,29 @@ Because Svelte's reactivity is based on assignments, using array methods like `.
</script> </script>
``` ```
---
Svelte's `<script>` blocks are run only when the component is created, so assignments within a `<script>` block are not automatically run again when a prop updates. If you'd like to track changes to a prop, see the next example in the following section.
```sv
<script>
export let person;
// this will only set `name` on component creation
// it will not update when `person` does
let { name } = person;
</script>
```
#### 3. `$:` marks a statement as reactive #### 3. `$:` marks a statement as reactive
--- ---
Any top-level statement (i.e. not inside a block or a function) can be made reactive by prefixing it with the `$:` [JS label syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label). Reactive statements run immediately before the component updates, whenever the values that they depend on have changed. Any top-level statement (i.e. not inside a block or a function) can be made reactive by prefixing it with the `$:` [JS label syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label). Reactive statements run after other script code and before the component markup is rendered, whenever the values that they depend on have changed.
```sv ```sv
<script> <script>
export let title; export let title;
export let person
// this will update `document.title` whenever // this will update `document.title` whenever
// the `title` prop changes // the `title` prop changes
@ -143,6 +157,12 @@ Any top-level statement (i.e. not inside a block or a function) can be made reac
console.log(`multiple statements can be combined`); console.log(`multiple statements can be combined`);
console.log(`the current title is ${title}`); console.log(`the current title is ${title}`);
} }
// this will update `name` when 'person' changes
$: ({ name } = person);
// don't do this. it will run before the previous line
let name2 = name;
</script> </script>
``` ```

@ -1006,7 +1006,7 @@ Like actions, transitions can have parameters.
```sv ```sv
{#if visible} {#if visible}
<div transition:fade="{{ duration: 2000 }}"> <div transition:fade="{{ duration: 2000 }}">
flies in, fades out over two seconds fades in and out over two seconds
</div> </div>
{/if} {/if}
``` ```
@ -1666,7 +1666,7 @@ If `this` is the name of a void tag (e.g., `br`) and `<svelte:element>` has chil
The `<svelte:window>` element allows you to add event listeners to the `window` object without worrying about removing them when the component is destroyed, or checking for the existence of `window` when server-side rendering. The `<svelte:window>` element allows you to add event listeners to the `window` object without worrying about removing them when the component is destroyed, or checking for the existence of `window` when server-side rendering.
Unlike `<svelte:self>`, this element may only appear the top level of your component and must never be inside a block or element. Unlike `<svelte:self>`, this element may only appear at the top level of your component and must never be inside a block or element.
```sv ```sv
<script> <script>

@ -41,6 +41,19 @@ Enforce that `autofocus` is not used on elements. Autofocusing elements can caus
--- ---
### `a11y-click-events-have-key-events`
Enforce `on:click` is accompanied by at least one of the following: `onKeyUp`, `onKeyDown`, `onKeyPress`. Coding for the keyboard is important for users with physical disabilities who cannot use a mouse, AT compatibility, and screenreader users.
This does not apply for interactive or hidden elements.
```sv
<!-- A11y: visible, non-interactive elements with an on:click event must be accompanied by an on:keydown, on:keyup, or on:keypress event. -->
<div on:click={() => {}} />
```
---
### `a11y-distracting-elements` ### `a11y-distracting-elements`
Enforces that no distracting elements are used. Elements that can be visually distracting can cause accessibility issues with visually impaired users. Such elements are most likely deprecated, and should be avoided. Enforces that no distracting elements are used. Elements that can be visually distracting can cause accessibility issues with visually impaired users. Such elements are most likely deprecated, and should be avoided.
@ -87,6 +100,18 @@ Enforce img alt attribute does not contain the word image, picture, or photo. Sc
--- ---
### `a11y-incorrect-aria-attribute-type`
Enforce that only the correct type of value is used for aria attributes. For example, `aria-hidden`
should only receive a boolean.
```sv
<!-- A11y: The value of 'aria-hidden' must be exactly one of true or false -->
<div aria-hidden="yes"/>
```
---
### `a11y-invalid-attribute` ### `a11y-invalid-attribute`
Enforce that attributes important for accessibility have a valid value. For example, `href` should not be empty, `'#'`, or `javascript:`. Enforce that attributes important for accessibility have a valid value. For example, `href` should not be empty, `'#'`, or `javascript:`.
@ -227,6 +252,28 @@ Some HTML elements have default ARIA roles. Giving these elements an ARIA role t
--- ---
### `a11y-no-interactive-element-to-noninteractive-role`
[WAI-ARIA](https://www.w3.org/TR/wai-aria-1.1/#usage_intro) roles should not be used to convert an interactive element to a non-interactive element. Non-interactive ARIA roles include `article`, `banner`, `complementary`, `img`, `listitem`, `main`, `region` and `tooltip`.
```sv
<!-- A11y: <textarea> cannot have role 'listitem' -->
<textarea role="listitem" />
```
---
### `a11y-no-noninteractive-tabindex`
Tab key navigation should be limited to elements on the page that can be interacted with.
```sv
<!-- A11y: not interactive element cannot have positive tabIndex value -->
<div tabindex='0' />
```
---
### `a11y-positive-tabindex` ### `a11y-positive-tabindex`
Avoid positive `tabindex` property values. This will move elements out of the expected tab order, creating a confusing experience for keyboard users. Avoid positive `tabindex` property values. This will move elements out of the expected tab order, creating a confusing experience for keyboard users.
@ -238,6 +285,17 @@ Avoid positive `tabindex` property values. This will move elements out of the ex
--- ---
### `a11y-role-has-required-aria-props`
Elements with ARIA roles must have all required attributes for that role.
```sv
<!-- A11y: A11y: Elements with the ARIA role "checkbox" must have the following attributes defined: "aria-checked" -->
<span role="checkbox" aria-labelledby="foo" tabindex="0"></span>
```
---
### `a11y-structure` ### `a11y-structure`
Enforce that certain DOM elements have the correct structure. Enforce that certain DOM elements have the correct structure.

@ -1,5 +0,0 @@
---
question: How can I update my components written in Svelte v2?
---
svelte-upgrade isn't fully working for v2->v3 yet, [but it's close](https://github.com/sveltejs/svelte-upgrade/pull/12).

@ -2,7 +2,7 @@
question: Is there a router? question: Is there a router?
--- ---
The official routing library is [SvelteKit](https://kit.svelte.dev/), which is currently in beta. SvelteKit provides a filesystem router, server-side rendering (SSR), and hot module reloading (HMR) in one easy-to-use package. It shares similarities with Next.js for React. The official routing library is [SvelteKit](https://kit.svelte.dev/). SvelteKit provides a filesystem router, server-side rendering (SSR), and hot module reloading (HMR) in one easy-to-use package. It shares similarities with Next.js for React.
However, you can use any router lib you want. A lot of people use [page.js](https://github.com/visionmedia/page.js). There's also [navaid](https://github.com/lukeed/navaid), which is very similar. And [universal-router](https://github.com/kriasoft/universal-router), which is isomorphic with child routes, but without built-in history support. However, you can use any router lib you want. A lot of people use [page.js](https://github.com/visionmedia/page.js). There's also [navaid](https://github.com/lukeed/navaid), which is very similar. And [universal-router](https://github.com/kriasoft/universal-router), which is isomorphic with child routes, but without built-in history support.

@ -4,13 +4,15 @@ title: Making an app
This tutorial is designed to get you familiar with the process of writing components. But at some point, you'll want to start writing components in the comfort of your own text editor. This tutorial is designed to get you familiar with the process of writing components. But at some point, you'll want to start writing components in the comfort of your own text editor.
First, you'll need to integrate Svelte with a build tool. There are officially maintained plugins for [Vite](https://vitejs.dev/), [Rollup](https://rollupjs.org) and [webpack](https://webpack.js.org/)... First, you'll need to integrate Svelte with a build tool. We recommend using [Vite](https://vitejs.dev/) with [vite-plugin-svelte](https://github.com/sveltejs/vite-plugin-svelte/)...
* [vite-plugin-svelte](https://github.com/sveltejs/vite-plugin-svelte) ```bash
* [rollup-plugin-svelte](https://github.com/sveltejs/rollup-plugin-svelte) npm create vite@latest my-app -- --template svelte
* [svelte-loader](https://github.com/sveltejs/svelte-loader) ```
...or one of the [community-maintained integrations](https://sveltesociety.dev/tools).
...and a variety of [community-maintained ones](https://sveltesociety.dev/tools). > [SvelteKit](https://kit.svelte.dev) is the official application framework from the Svelte team. It's currently in development, but if you don't mind using pre-1.0 software then it's the recommended way to build Svelte apps.
Don't worry if you're relatively new to web development and haven't used these tools before. We've prepared a simple step-by-step guide, [Svelte for new developers](/blog/svelte-for-new-developers), which walks you through the process. Don't worry if you're relatively new to web development and haven't used these tools before. We've prepared a simple step-by-step guide, [Svelte for new developers](/blog/svelte-for-new-developers), which walks you through the process.

@ -2,9 +2,7 @@
title: Declarations title: Declarations
--- ---
Svelte automatically updates the DOM when your component's state changes. Often, some parts of a component's state need to be computed from *other* parts (such as a `fullname` derived from a `firstname` and a `lastname`), and recomputed whenever they change. Svelte's reactivity not only keeps the DOM in sync with your application's variables as shown in the previous section, it can also keep variables in sync with each other using reactive declarations. They look like this:
For these, we have *reactive declarations*. They look like this:
```js ```js
let count = 0; let count = 0;

@ -10,7 +10,7 @@
<ul> <ul>
<li> <li>
<Project <Project
title="Add Typescript support" title="Add TypeScript support"
tasksCompleted={25} tasksCompleted={25}
totalTasks={57} totalTasks={57}
> >

@ -10,7 +10,7 @@
<ul> <ul>
<li> <li>
<Project <Project
title="Add Typescript support" title="Add TypeScript support"
tasksCompleted={25} tasksCompleted={25}
totalTasks={57} totalTasks={57}
> >

@ -1,10 +1,10 @@
<script> <script>
let key; let key;
let keyCode; let code;
function handleKeydown(event) { function handleKeydown(event) {
key = event.key; key = event.key;
keyCode = event.keyCode; code = event.code;
} }
</script> </script>
@ -13,7 +13,7 @@
<div style="text-align: center"> <div style="text-align: center">
{#if key} {#if key}
<kbd>{key === ' ' ? 'Space' : key}</kbd> <kbd>{key === ' ' ? 'Space' : key}</kbd>
<p>{keyCode}</p> <p>{code}</p>
{:else} {:else}
<p>Focus this window and press any key</p> <p>Focus this window and press any key</p>
{/if} {/if}
@ -39,4 +39,4 @@
border-bottom: 5px solid rgba(0, 0, 0, 0.2); border-bottom: 5px solid rgba(0, 0, 0, 0.2);
color: #555; color: #555;
} }
</style> </style>

@ -1,10 +1,10 @@
<script> <script>
let key; let key;
let keyCode; let code;
function handleKeydown(event) { function handleKeydown(event) {
key = event.key; key = event.key;
keyCode = event.keyCode; code = event.code;
} }
</script> </script>
@ -13,7 +13,7 @@
<div style="text-align: center"> <div style="text-align: center">
{#if key} {#if key}
<kbd>{key === ' ' ? 'Space' : key}</kbd> <kbd>{key === ' ' ? 'Space' : key}</kbd>
<p>{keyCode}</p> <p>{code}</p>
{:else} {:else}
<p>Focus this window and press any key</p> <p>Focus this window and press any key</p>
{/if} {/if}

@ -1,7 +1,8 @@
import { walk } from 'estree-walker'; import { walk } from 'estree-walker';
import { getLocator } from 'locate-character'; import { getLocator } from 'locate-character';
import Stats from '../Stats'; import Stats from '../Stats';
import { globals, reserved, is_valid } from '../utils/names'; import { reserved, is_valid } from '../utils/names';
import globals from '../utils/globals';
import { namespaces, valid_namespaces } from '../utils/namespaces'; import { namespaces, valid_namespaces } from '../utils/namespaces';
import create_module from './create_module'; import create_module from './create_module';
import { import {

@ -234,6 +234,10 @@ export default {
code: 'css-invalid-global-selector', code: 'css-invalid-global-selector',
message: ':global(...) must contain a single selector' message: ':global(...) must contain a single selector'
}, },
css_invalid_selector: (selector: string) => ({
code: 'css-invalid-selector',
message: `Invalid selector "${selector}"`
}),
duplicate_animation: { duplicate_animation: {
code: 'duplicate-animation', code: 'duplicate-animation',
message: "An element can only have one 'animate' directive" message: "An element can only have one 'animate' directive"

@ -1,12 +1,14 @@
// All compiler warnings should be listed and accessed from here // All compiler warnings should be listed and accessed from here
import { ARIAPropertyDefinition } from 'aria-query';
/** /**
* @internal * @internal
*/ */
export default { export default {
custom_element_no_tag: { custom_element_no_tag: {
code: 'custom-element-no-tag', code: 'custom-element-no-tag',
message: 'No custom element \'tag\' option was specified. To automatically register a custom element, specify a name with a hyphen in it, e.g. <svelte:options tag="my-thing"/>. To hide this warning, use <svelte:options tag={null}/>' message: 'No custom element \'tag\' option was specified. To automatically register a custom element, specify a name with a hyphen in it, e.g. <svelte:options tag="my-thing"/>. To hide this warning, use <svelte:options tag={null}/>'
}, },
unused_export_let: (component: string, property: string) => ({ unused_export_let: (component: string, property: string) => ({
code: 'unused-export-let', code: 'unused-export-let',
@ -60,6 +62,35 @@ export default {
code: 'a11y-aria-attributes', code: 'a11y-aria-attributes',
message: `A11y: <${name}> should not have aria-* attributes` message: `A11y: <${name}> should not have aria-* attributes`
}), }),
a11y_incorrect_attribute_type: (schema: ARIAPropertyDefinition, attribute: string) => {
let message;
switch (schema.type) {
case 'boolean':
message = `The value of '${attribute}' must be exactly one of true or false`;
break;
case 'id':
message = `The value of '${attribute}' must be a string that represents a DOM element ID`;
break;
case 'idlist':
message = `The value of '${attribute}' must be a space-separated list of strings that represent DOM element IDs`;
break;
case 'tristate':
message = `The value of '${attribute}' must be exactly one of true, false, or mixed`;
break;
case 'token':
message = `The value of '${attribute}' must be exactly one of ${(schema.values || []).join(', ')}`;
break;
case 'tokenlist':
message = `The value of '${attribute}' must be a space-separated list of one or more of ${(schema.values || []).join(', ')}`;
break;
default:
message = `The value of '${attribute}' must be of type ${schema.type}`;
}
return {
code: 'a11y-incorrect-aria-attribute-type',
message: `A11y: ${message}`
};
},
a11y_unknown_aria_attribute: (attribute: string, suggestion?: string) => ({ a11y_unknown_aria_attribute: (attribute: string, suggestion?: string) => ({
code: 'a11y-unknown-aria-attribute', code: 'a11y-unknown-aria-attribute',
message: `A11y: Unknown aria attribute 'aria-${attribute}'` + (suggestion ? ` (did you mean '${suggestion}'?)` : '') message: `A11y: Unknown aria attribute 'aria-${attribute}'` + (suggestion ? ` (did you mean '${suggestion}'?)` : '')
@ -76,10 +107,22 @@ export default {
code: 'a11y-unknown-role', code: 'a11y-unknown-role',
message: `A11y: Unknown role '${role}'` + (suggestion ? ` (did you mean '${suggestion}'?)` : '') message: `A11y: Unknown role '${role}'` + (suggestion ? ` (did you mean '${suggestion}'?)` : '')
}), }),
a11y_no_abstract_role: (role: string | boolean) => ({
code: 'a11y-no-abstract-role',
message: `A11y: Abstract role '${role}' is forbidden`
}),
a11y_no_redundant_roles: (role: string | boolean) => ({ a11y_no_redundant_roles: (role: string | boolean) => ({
code: 'a11y-no-redundant-roles', code: 'a11y-no-redundant-roles',
message: `A11y: Redundant role '${role}'` message: `A11y: Redundant role '${role}'`
}), }),
a11y_no_interactive_element_to_noninteractive_role: (role: string | boolean, element: string) => ({
code: 'a11y-no-interactive-element-to-noninteractive-role',
message: `A11y: <${element}> cannot have role '${role}'`
}),
a11y_role_has_required_aria_props: (role: string, props: string[]) => ({
code: 'a11y-role-has-required-aria-props',
message: `A11y: Elements with the ARIA role "${role}" must have the following attributes defined: ${props.map(name => `"${name}"`).join(', ')}`
}),
a11y_accesskey: { a11y_accesskey: {
code: 'a11y-accesskey', code: 'a11y-accesskey',
message: 'A11y: Avoid using accesskey' message: 'A11y: Avoid using accesskey'
@ -132,10 +175,18 @@ export default {
code: 'a11y-mouse-events-have-key-events', code: 'a11y-mouse-events-have-key-events',
message: `A11y: on:${event} must be accompanied by on:${accompanied_by}` message: `A11y: on:${event} must be accompanied by on:${accompanied_by}`
}), }),
a11y_click_events_have_key_events: () => ({
code: 'a11y-click-events-have-key-events',
message: 'A11y: visible, non-interactive elements with an on:click event must be accompanied by an on:keydown, on:keyup, or on:keypress event.'
}),
a11y_missing_content: (name: string) => ({ a11y_missing_content: (name: string) => ({
code: 'a11y-missing-content', code: 'a11y-missing-content',
message: `A11y: <${name}> element should have child content` message: `A11y: <${name}> element should have child content`
}), }),
a11y_no_noninteractive_tabindex: {
code: 'a11y-no-noninteractive-tabindex',
message: 'A11y: not interactive element cannot have positive tabIndex value'
},
redundant_event_modifier_for_touch: { redundant_event_modifier_for_touch: {
code: 'redundant-event-modifier', code: 'redundant-event-modifier',
message: 'Touch event handlers that don\'t use the \'event\' object are passive by default' message: 'Touch event handlers that don\'t use the \'event\' object are passive by default'
@ -143,5 +194,9 @@ export default {
redundant_event_modifier_passive: { redundant_event_modifier_passive: {
code: 'redundant-event-modifier', code: 'redundant-event-modifier',
message: 'The passive modifier only works with wheel and touch events' message: 'The passive modifier only works with wheel and touch events'
} },
invalid_rest_eachblock_binding: (rest_element_name: string) => ({
code: 'invalid-rest-eachblock-binding',
message: `...${rest_element_name} operator will create a new object and binding propogation with original object will not work`
})
}; };

@ -145,6 +145,7 @@ export default class Selector {
} }
this.validate_global_with_multiple_selectors(component); this.validate_global_with_multiple_selectors(component);
this.validate_invalid_combinator_without_selector(component);
} }
validate_global_with_multiple_selectors(component: Component) { validate_global_with_multiple_selectors(component: Component) {
@ -163,6 +164,17 @@ export default class Selector {
} }
} }
} }
validate_invalid_combinator_without_selector(component: Component) {
for (let i = 0; i < this.blocks.length; i++) {
const block = this.blocks[i];
if (block.combinator && block.selectors.length === 0) {
component.error(this.node, compiler_errors.css_invalid_selector(component.source.slice(this.node.start, this.node.end)));
}
if (!block.combinator && block.selectors.length === 0) {
component.error(this.node, compiler_errors.css_invalid_selector(component.source.slice(this.node.start, this.node.end)));
}
}
}
get_amount_class_specificity_increased() { get_amount_class_specificity_increased() {
let count = 0; let count = 0;
@ -299,7 +311,7 @@ function block_might_apply_to_node(block: Block, node: Element): BlockAppliesToN
return BlockAppliesToNode.NotPossible; return BlockAppliesToNode.NotPossible;
} }
} else if (selector.type === 'TypeSelector') { } else if (selector.type === 'TypeSelector') {
if (node.name.toLowerCase() !== name.toLowerCase() && name !== '*') return BlockAppliesToNode.NotPossible; if (node.name.toLowerCase() !== name.toLowerCase() && name !== '*' && !node.is_dynamic_element) return BlockAppliesToNode.NotPossible;
} else { } else {
return BlockAppliesToNode.UnknownSelectorType; return BlockAppliesToNode.UnknownSelectorType;
} }

@ -170,7 +170,7 @@ class Atrule {
} }
apply(node: Element) { apply(node: Element) {
if (this.node.name === 'media' || this.node.name === 'supports') { if (this.node.name === 'media' || this.node.name === 'supports' || this.node.name === 'layer') {
this.children.forEach(child => { this.children.forEach(child => {
child.apply(node); child.apply(node);
}); });

@ -23,6 +23,8 @@ export default class AwaitBlock extends Node {
then: ThenBlock; then: ThenBlock;
catch: CatchBlock; catch: CatchBlock;
context_rest_properties: Map<string, ESTreeNode> = new Map();
constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) { constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info); super(component, parent, scope, info);
@ -33,12 +35,12 @@ export default class AwaitBlock extends Node {
if (this.then_node) { if (this.then_node) {
this.then_contexts = []; this.then_contexts = [];
unpack_destructuring({ contexts: this.then_contexts, node: info.value, scope, component }); unpack_destructuring({ contexts: this.then_contexts, node: info.value, scope, component, context_rest_properties: this.context_rest_properties });
} }
if (this.catch_node) { if (this.catch_node) {
this.catch_contexts = []; this.catch_contexts = [];
unpack_destructuring({ contexts: this.catch_contexts, node: info.error, scope, component }); unpack_destructuring({ contexts: this.catch_contexts, node: info.error, scope, component, context_rest_properties: this.context_rest_properties });
} }
this.pending = new PendingBlock(component, this, scope, info.pending); this.pending = new PendingBlock(component, this, scope, info.pending);

@ -11,6 +11,7 @@ import InlineComponent from './InlineComponent';
import Window from './Window'; import Window from './Window';
import { clone } from '../../utils/clone'; import { clone } from '../../utils/clone';
import compiler_errors from '../compiler_errors'; import compiler_errors from '../compiler_errors';
import compiler_warnings from '../compiler_warnings';
// TODO this should live in a specific binding // TODO this should live in a specific binding
const read_only_media_attributes = new Set([ const read_only_media_attributes = new Set([
@ -47,6 +48,7 @@ export default class Binding extends Node {
const { name } = get_object(this.expression.node); const { name } = get_object(this.expression.node);
this.is_contextual = Array.from(this.expression.references).some(name => scope.names.has(name)); this.is_contextual = Array.from(this.expression.references).some(name => scope.names.has(name));
if (this.is_contextual) this.validate_binding_rest_properties(scope);
// make sure we track this as a mutable ref // make sure we track this as a mutable ref
if (scope.is_let(name)) { if (scope.is_let(name)) {
@ -95,6 +97,18 @@ export default class Binding extends Node {
is_readonly_media_attribute() { is_readonly_media_attribute() {
return read_only_media_attributes.has(this.name); return read_only_media_attributes.has(this.name);
} }
validate_binding_rest_properties(scope: TemplateScope) {
this.expression.references.forEach(name => {
const each_block = scope.get_owner(name);
if (each_block && each_block.type === 'EachBlock') {
const rest_node = each_block.context_rest_properties.get(name);
if (rest_node) {
this.component.warn(rest_node as any, compiler_warnings.invalid_rest_eachblock_binding(name));
}
}
});
}
} }
function isElement(node: Node): node is Element { function isElement(node: Node): node is Element {

@ -10,6 +10,7 @@ import { extract_identifiers } from 'periscopic';
import is_reference, { NodeWithPropertyDefinition } from 'is-reference'; import is_reference, { NodeWithPropertyDefinition } from 'is-reference';
import get_object from '../utils/get_object'; import get_object from '../utils/get_object';
import compiler_errors from '../compiler_errors'; import compiler_errors from '../compiler_errors';
import { Node as ESTreeNode } from 'estree';
const allowed_parents = new Set(['EachBlock', 'CatchBlock', 'ThenBlock', 'InlineComponent', 'SlotTemplate', 'IfBlock', 'ElseBlock']); const allowed_parents = new Set(['EachBlock', 'CatchBlock', 'ThenBlock', 'InlineComponent', 'SlotTemplate', 'IfBlock', 'ElseBlock']);
@ -19,6 +20,7 @@ export default class ConstTag extends Node {
contexts: Context[] = []; contexts: Context[] = [];
node: ConstTagType; node: ConstTagType;
scope: TemplateScope; scope: TemplateScope;
context_rest_properties: Map<string, ESTreeNode> = new Map();
assignees: Set<string> = new Set(); assignees: Set<string> = new Set();
dependencies: Set<string> = new Set(); dependencies: Set<string> = new Set();
@ -58,7 +60,8 @@ export default class ConstTag extends Node {
contexts: this.contexts, contexts: this.contexts,
node: this.node.expression.left, node: this.node.expression.left,
scope: this.scope, scope: this.scope,
component: this.component component: this.component,
context_rest_properties: this.context_rest_properties
}); });
this.expression = new Expression(this.component, this, this.scope, this.node.expression.right); this.expression = new Expression(this.component, this, this.scope, this.node.expression.right);
this.contexts.forEach(context => { this.contexts.forEach(context => {

@ -28,7 +28,7 @@ export default class EachBlock extends AbstractBlock {
has_animation: boolean; has_animation: boolean;
has_binding = false; has_binding = false;
has_index_binding = false; has_index_binding = false;
context_rest_properties: Map<string, Node>;
else?: ElseBlock; else?: ElseBlock;
constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) { constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) {
@ -40,9 +40,9 @@ export default class EachBlock extends AbstractBlock {
this.index = info.index; this.index = info.index;
this.scope = scope.child(); this.scope = scope.child();
this.context_rest_properties = new Map();
this.contexts = []; this.contexts = [];
unpack_destructuring({ contexts: this.contexts, node: info.context, scope, component }); unpack_destructuring({ contexts: this.contexts, node: info.context, scope, component, context_rest_properties: this.context_rest_properties });
this.contexts.forEach(context => { this.contexts.forEach(context => {
this.scope.add(context.key.name, this.expression.dependencies, this); this.scope.add(context.key.name, this.expression.dependencies, this);

@ -1,4 +1,4 @@
import { is_void } from '../../../shared/utils/names'; import { is_html, is_svg, is_void } from '../../../shared/utils/names';
import Node from './shared/Node'; import Node from './shared/Node';
import Attribute from './Attribute'; import Attribute from './Attribute';
import Binding from './Binding'; import Binding from './Binding';
@ -23,14 +23,15 @@ import { string_literal } from '../utils/stringify';
import { Literal } from 'estree'; import { Literal } from 'estree';
import compiler_warnings from '../compiler_warnings'; import compiler_warnings from '../compiler_warnings';
import compiler_errors from '../compiler_errors'; import compiler_errors from '../compiler_errors';
import { ARIARoleDefintionKey, roles, aria, ARIAPropertyDefinition, ARIAProperty } from 'aria-query';
const svg = /^(?:altGlyph|altGlyphDef|altGlyphItem|animate|animateColor|animateMotion|animateTransform|circle|clipPath|color-profile|cursor|defs|desc|discard|ellipse|feBlend|feColorMatrix|feComponentTransfer|feComposite|feConvolveMatrix|feDiffuseLighting|feDisplacementMap|feDistantLight|feDropShadow|feFlood|feFuncA|feFuncB|feFuncG|feFuncR|feGaussianBlur|feImage|feMerge|feMergeNode|feMorphology|feOffset|fePointLight|feSpecularLighting|feSpotLight|feTile|feTurbulence|filter|font|font-face|font-face-format|font-face-name|font-face-src|font-face-uri|foreignObject|g|glyph|glyphRef|hatch|hatchpath|hkern|image|line|linearGradient|marker|mask|mesh|meshgradient|meshpatch|meshrow|metadata|missing-glyph|mpath|path|pattern|polygon|polyline|radialGradient|rect|set|solidcolor|stop|svg|switch|symbol|text|textPath|tref|tspan|unknown|use|view|vkern)$/; import { is_interactive_element, is_non_interactive_roles, is_presentation_role, is_interactive_roles, is_hidden_from_screen_reader } from '../utils/a11y';
const aria_attributes = 'activedescendant atomic autocomplete busy checked colcount colindex colspan controls current describedby description details disabled dropeffect errormessage expanded flowto grabbed haspopup hidden invalid keyshortcuts label labelledby level live modal multiline multiselectable orientation owns placeholder posinset pressed readonly relevant required roledescription rowcount rowindex rowspan selected setsize sort valuemax valuemin valuenow valuetext'.split(' '); const aria_attributes = 'activedescendant atomic autocomplete busy checked colcount colindex colspan controls current describedby description details disabled dropeffect errormessage expanded flowto grabbed haspopup hidden invalid keyshortcuts label labelledby level live modal multiline multiselectable orientation owns placeholder posinset pressed readonly relevant required roledescription rowcount rowindex rowspan selected setsize sort valuemax valuemin valuenow valuetext'.split(' ');
const aria_attribute_set = new Set(aria_attributes); const aria_attribute_set = new Set(aria_attributes);
const aria_roles = 'alert alertdialog application article banner blockquote button caption cell checkbox code columnheader combobox complementary contentinfo definition deletion dialog directory document emphasis feed figure form generic graphics-document graphics-object graphics-symbol grid gridcell group heading img link list listbox listitem log main marquee math meter menu menubar menuitem menuitemcheckbox menuitemradio navigation none note option paragraph presentation progressbar radio radiogroup region row rowgroup rowheader scrollbar search searchbox separator slider spinbutton status strong subscript superscript switch tab table tablist tabpanel term textbox time timer toolbar tooltip tree treegrid treeitem'.split(' '); const aria_roles = roles.keys();
const aria_role_set = new Set(aria_roles); const aria_role_set = new Set(aria_roles);
const aria_role_abstract_set = new Set(roles.keys().filter(role => roles.get(role).abstract));
const a11y_required_attributes = { const a11y_required_attributes = {
a: ['href'], a: ['href'],
@ -163,19 +164,45 @@ function get_namespace(parent: Element, element: Element, explicit_namespace: st
const parent_element = parent.find_nearest(/^Element/); const parent_element = parent.find_nearest(/^Element/);
if (!parent_element) { if (!parent_element) {
return explicit_namespace || (svg.test(element.name) return explicit_namespace || (is_svg(element.name)
? namespaces.svg ? namespaces.svg
: null); : null);
} }
if (parent_element.namespace !== namespaces.foreign) { if (parent_element.namespace !== namespaces.foreign) {
if (svg.test(element.name.toLowerCase())) return namespaces.svg; if (is_svg(element.name.toLowerCase())) return namespaces.svg;
if (parent_element.name.toLowerCase() === 'foreignobject') return null; if (parent_element.name.toLowerCase() === 'foreignobject') return null;
} }
return parent_element.namespace; return parent_element.namespace;
} }
function is_valid_aria_attribute_value(schema: ARIAPropertyDefinition, value: string | boolean): boolean {
switch (schema.type) {
case 'boolean':
return typeof value === 'boolean';
case 'string':
case 'id':
return typeof value === 'string';
case 'tristate':
return typeof value === 'boolean' || value === 'mixed';
case 'integer':
case 'number':
return typeof value !== 'boolean' && isNaN(Number(value)) === false;
case 'token': // single token
return (schema.values || [])
.indexOf(typeof value === 'string' ? value.toLowerCase() : value) > -1;
case 'idlist': // if list of ids, split each
return typeof value === 'string'
&& value.split(' ').every((id) => typeof id === 'string');
case 'tokenlist': // if list of tokens, split each
return typeof value === 'string'
&& value.split(' ').every((token) => (schema.values || []).indexOf(token.toLowerCase()) > -1);
default:
return false;
}
}
export default class Element extends Node { export default class Element extends Node {
type: 'Element'; type: 'Element';
name: string; name: string;
@ -344,7 +371,7 @@ export default class Element extends Node {
} }
validate() { validate() {
if (this.component.var_lookup.has(this.name) && this.component.var_lookup.get(this.name).imported) { if (this.component.var_lookup.has(this.name) && this.component.var_lookup.get(this.name).imported && !is_svg(this.name) && !is_html(this.name)) {
this.component.warn(this, compiler_warnings.component_name_lowercase(this.name)); this.component.warn(this, compiler_warnings.component_name_lowercase(this.name));
} }
@ -407,9 +434,19 @@ export default class Element extends Node {
} }
validate_attributes_a11y() { validate_attributes_a11y() {
const { component } = this; const { component, attributes, handlers } = this;
this.attributes.forEach(attribute => { const attribute_map = new Map<string, Attribute>();
const handlers_map = new Map();
attributes.forEach(attribute => (
attribute_map.set(attribute.name, attribute)
));
handlers.forEach(handler => (
handlers_map.set(handler.name, handler)
));
attributes.forEach(attribute => {
if (attribute.is_spread) return; if (attribute.is_spread) return;
const name = attribute.name.toLowerCase(); const name = attribute.name.toLowerCase();
@ -430,6 +467,18 @@ export default class Element extends Node {
if (name === 'aria-hidden' && /^h[1-6]$/.test(this.name)) { if (name === 'aria-hidden' && /^h[1-6]$/.test(this.name)) {
component.warn(attribute, compiler_warnings.a11y_hidden(this.name)); component.warn(attribute, compiler_warnings.a11y_hidden(this.name));
} }
// aria-proptypes
let value = attribute.get_static_value();
if (value === 'true') value = true;
if (value === 'false') value = false;
if (value !== null && value !== undefined && aria.has(name as ARIAProperty)) {
const schema = aria.get(name as ARIAProperty);
if (!is_valid_aria_attribute_value(schema, value)) {
component.warn(attribute, compiler_warnings.a11y_incorrect_attribute_type(schema, name));
}
}
} }
// aria-role // aria-role
@ -439,10 +488,11 @@ export default class Element extends Node {
component.warn(attribute, compiler_warnings.a11y_misplaced_role(this.name)); component.warn(attribute, compiler_warnings.a11y_misplaced_role(this.name));
} }
const value = attribute.get_static_value(); const value = attribute.get_static_value() as ARIARoleDefintionKey;
// @ts-ignore
if (value && !aria_role_set.has(value)) { if (value && aria_role_abstract_set.has(value)) {
// @ts-ignore component.warn(attribute, compiler_warnings.a11y_no_abstract_role(value));
} else if (value && !aria_role_set.has(value)) {
const match = fuzzymatch(value, aria_roles); const match = fuzzymatch(value, aria_roles);
component.warn(attribute, compiler_warnings.a11y_unknown_role(value, match)); component.warn(attribute, compiler_warnings.a11y_unknown_role(value, match));
} }
@ -462,6 +512,22 @@ export default class Element extends Node {
component.warn(attribute, compiler_warnings.a11y_no_redundant_roles(value)); component.warn(attribute, compiler_warnings.a11y_no_redundant_roles(value));
} }
} }
// role-has-required-aria-props
const role = roles.get(value);
if (role) {
const required_role_props = Object.keys(role.requiredProps);
const has_missing_props = required_role_props.some(prop => !attributes.find(a => a.name === prop));
if (has_missing_props) {
component.warn(attribute, compiler_warnings.a11y_role_has_required_aria_props(value as string, required_role_props));
}
}
// no-interactive-element-to-noninteractive-role
if (is_interactive_element(this.name, attribute_map) && (is_non_interactive_roles(value) || is_presentation_role(value))) {
component.warn(this, compiler_warnings.a11y_no_interactive_element_to_noninteractive_role(value, this.name));
}
} }
// no-access-key // no-access-key
@ -488,8 +554,40 @@ export default class Element extends Node {
} }
} }
}); });
}
// click-events-have-key-events
if (handlers_map.has('click')) {
const role = attribute_map.get('role');
const is_non_presentation_role = role?.is_static && !is_presentation_role(role.get_static_value() as ARIARoleDefintionKey);
if (
!is_hidden_from_screen_reader(this.name, attribute_map) &&
(!role || is_non_presentation_role) &&
!is_interactive_element(this.name, attribute_map) &&
!this.attributes.find(attr => attr.is_spread)
) {
const has_key_event =
handlers_map.has('keydown') ||
handlers_map.has('keyup') ||
handlers_map.has('keypress');
if (!has_key_event) {
component.warn(
this,
compiler_warnings.a11y_click_events_have_key_events()
);
}
}
}
// no-noninteractive-tabindex
if (!is_interactive_element(this.name, attribute_map) && !is_interactive_roles(attribute_map.get('role')?.get_static_value() as ARIARoleDefintionKey)) {
const tab_index = attribute_map.get('tabindex');
if (tab_index && (!tab_index.is_static || Number(tab_index.get_static_value()) >= 0)) {
component.warn(this, compiler_warnings.a11y_no_noninteractive_tabindex);
}
}
}
validate_special_cases() { validate_special_cases() {
const { component, attributes, handlers } = this; const { component, attributes, handlers } = this;
@ -563,8 +661,24 @@ export default class Element extends Node {
} }
if (this.name === 'label') { if (this.name === 'label') {
const has_input_child = this.children.some(i => (i instanceof Element && a11y_labelable.has(i.name) )); const has_input_child = (children: INode[]) => {
if (!attribute_map.has('for') && !has_input_child) { if (children.some(child => (child instanceof Element && (a11y_labelable.has(child.name) || child.name === 'slot')))) {
return true;
}
for (const child of children) {
if (!('children' in child) || child.children.length === 0) {
continue;
}
if (has_input_child(child.children)) {
return true;
}
}
return false;
};
if (!attribute_map.has('for') && !has_input_child(this.children)) {
component.warn(this, compiler_warnings.a11y_label_has_associated_control); component.warn(this, compiler_warnings.a11y_label_has_associated_control);
} }
} }
@ -748,7 +862,7 @@ export default class Element extends Node {
} else if (dimensions.test(name)) { } else if (dimensions.test(name)) {
if (this.name === 'svg' && (name === 'offsetWidth' || name === 'offsetHeight')) { if (this.name === 'svg' && (name === 'offsetWidth' || name === 'offsetHeight')) {
return 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)) { } else if (is_svg(this.name)) {
return 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)) { } else if (is_void(this.name)) {
return 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`));

@ -20,7 +20,8 @@ export function unpack_destructuring({
modifier = (node) => node, modifier = (node) => node,
default_modifier = (node) => node, default_modifier = (node) => node,
scope, scope,
component component,
context_rest_properties
}: { }: {
contexts: Context[]; contexts: Context[];
node: Node; node: Node;
@ -28,6 +29,7 @@ export function unpack_destructuring({
default_modifier?: Context['default_modifier']; default_modifier?: Context['default_modifier'];
scope: TemplateScope; scope: TemplateScope;
component: Component; component: Component;
context_rest_properties: Map<string, Node>;
}) { }) {
if (!node) return; if (!node) return;
@ -43,6 +45,7 @@ export function unpack_destructuring({
modifier, modifier,
default_modifier default_modifier
}); });
context_rest_properties.set((node.argument as Identifier).name, node);
} else if (node.type === 'ArrayPattern') { } else if (node.type === 'ArrayPattern') {
node.elements.forEach((element, i) => { node.elements.forEach((element, i) => {
if (element && element.type === 'RestElement') { if (element && element.type === 'RestElement') {
@ -52,8 +55,10 @@ export function unpack_destructuring({
modifier: (node) => x`${modifier(node)}.slice(${i})` as Node, modifier: (node) => x`${modifier(node)}.slice(${i})` as Node,
default_modifier, default_modifier,
scope, scope,
component component,
context_rest_properties
}); });
context_rest_properties.set((element.argument as Identifier).name, element);
} else if (element && element.type === 'AssignmentPattern') { } else if (element && element.type === 'AssignmentPattern') {
const n = contexts.length; const n = contexts.length;
mark_referenced(element.right, scope, component); mark_referenced(element.right, scope, component);
@ -70,7 +75,8 @@ export function unpack_destructuring({
to_ctx to_ctx
)}` as Node, )}` as Node,
scope, scope,
component component,
context_rest_properties
}); });
} else { } else {
unpack_destructuring({ unpack_destructuring({
@ -79,7 +85,8 @@ export function unpack_destructuring({
modifier: (node) => x`${modifier(node)}[${i}]` as Node, modifier: (node) => x`${modifier(node)}[${i}]` as Node,
default_modifier, default_modifier,
scope, scope,
component component,
context_rest_properties
}); });
} }
}); });
@ -97,8 +104,10 @@ export function unpack_destructuring({
)}, [${used_properties}])` as Node, )}, [${used_properties}])` as Node,
default_modifier, default_modifier,
scope, scope,
component component,
context_rest_properties
}); });
context_rest_properties.set((property.argument as Identifier).name, property);
} else { } else {
const key = property.key as Identifier; const key = property.key as Identifier;
const value = property.value; const value = property.value;
@ -121,7 +130,8 @@ export function unpack_destructuring({
to_ctx to_ctx
)}` as Node, )}` as Node,
scope, scope,
component component,
context_rest_properties
}); });
} else { } else {
unpack_destructuring({ unpack_destructuring({
@ -130,7 +140,8 @@ export function unpack_destructuring({
modifier: (node) => x`${modifier(node)}.${key.name}` as Node, modifier: (node) => x`${modifier(node)}.${key.name}` as Node,
default_modifier, default_modifier,
scope, scope,
component component,
context_rest_properties
}); });
} }
} }

@ -323,7 +323,7 @@ export default class Expression {
const func_expression = func_declaration[0]; const func_expression = func_declaration[0];
if (node.type === 'InlineComponent') { if (node.type === 'InlineComponent' || node.type === 'SlotTemplate') {
// <Comp let:data /> // <Comp let:data />
this.replace(func_expression); this.replace(func_expression);
} else { } else {

@ -333,7 +333,7 @@ export default function dom(
// $$props arg is still needed for unknown prop check // $$props arg is still needed for unknown prop check
args.push(x`$$props`); args.push(x`$$props`);
} }
// has_create_fragment is intentionally to be true in dev mode.
const has_create_fragment = component.compile_options.dev || block.has_content(); const has_create_fragment = component.compile_options.dev || block.has_content();
if (has_create_fragment) { if (has_create_fragment) {
body.push(b` body.push(b`

@ -9,6 +9,7 @@ import Text from '../../../nodes/Text';
import handle_select_value_binding from './handle_select_value_binding'; import handle_select_value_binding from './handle_select_value_binding';
import { Identifier, Node } from 'estree'; import { Identifier, Node } from 'estree';
import { namespaces } from '../../../../utils/namespaces'; import { namespaces } from '../../../../utils/namespaces';
import { boolean_attributes } from '../../../../../shared/boolean_attributes';
const non_textlike_input_types = new Set([ const non_textlike_input_types = new Set([
'button', 'button',
@ -255,7 +256,7 @@ export default class AttributeWrapper extends BaseAttributeWrapper {
get_value(block) { get_value(block) {
if (this.node.is_true) { if (this.node.is_true) {
if (this.metadata && boolean_attribute.has(this.metadata.property_name.toLowerCase())) { if (this.metadata && boolean_attributes.has(this.metadata.property_name.toLowerCase())) {
return x`true`; return x`true`;
} }
return x`""`; return x`""`;
@ -376,35 +377,6 @@ Object.keys(attribute_lookup).forEach(name => {
if (!metadata.property_name) metadata.property_name = name; if (!metadata.property_name) metadata.property_name = name;
}); });
// source: https://html.spec.whatwg.org/multipage/indices.html
const boolean_attribute = new Set([
'allowfullscreen',
'allowpaymentrequest',
'async',
'autofocus',
'autoplay',
'checked',
'controls',
'default',
'defer',
'disabled',
'formnovalidate',
'hidden',
'ismap',
'itemscope',
'loop',
'multiple',
'muted',
'nomodule',
'novalidate',
'open',
'playsinline',
'readonly',
'required',
'reversed',
'selected'
]);
function should_cache(attribute: AttributeWrapper) { function should_cache(attribute: AttributeWrapper) {
return attribute.is_src || attribute.node.should_cache(); return attribute.is_src || attribute.node.should_cache();
} }

@ -504,9 +504,10 @@ export default class ElementWrapper extends Wrapper {
get_render_statement(block: Block) { get_render_statement(block: Block) {
const { name, namespace, tag_expr } = this.node; const { name, namespace, tag_expr } = this.node;
const reference = tag_expr.manipulate(block);
if (namespace === namespaces.svg) { if (namespace === namespaces.svg) {
return x`@svg_element("${name}")`; return x`@svg_element(${reference})`;
} }
if (namespace) { if (namespace) {
@ -518,7 +519,6 @@ export default class ElementWrapper extends Wrapper {
return x`@element_is("${name}", ${is.render_chunks(block).reduce((lhs, rhs) => x`${lhs} + ${rhs}`)})`; return x`@element_is("${name}", ${is.render_chunks(block).reduce((lhs, rhs) => x`${lhs} + ${rhs}`)})`;
} }
const reference = tag_expr.manipulate(block);
return x`@element(${reference})`; return x`@element(${reference})`;
} }
@ -1052,7 +1052,10 @@ export default class ElementWrapper extends Wrapper {
block.chunks.update.push(updater); block.chunks.update.push(updater);
} else if ((dependencies && dependencies.size > 0) || this.class_dependencies.length) { } else if ((dependencies && dependencies.size > 0) || this.class_dependencies.length) {
const all_dependencies = this.class_dependencies.concat(...dependencies); const all_dependencies = this.class_dependencies.concat(...dependencies);
const condition = block.renderer.dirty(all_dependencies); let condition = block.renderer.dirty(all_dependencies);
if (block.has_outros) {
condition = x`!#current || ${condition}`;
}
// If all of the dependencies are non-dynamic (don't get updated) then there is no reason // If all of the dependencies are non-dynamic (don't get updated) then there is no reason
// to add an updater for this. // to add an updater for this.

@ -36,7 +36,7 @@ export default class HeadWrapper extends Wrapper {
let nodes; let nodes;
if (this.renderer.options.hydratable && this.fragment.nodes.length) { if (this.renderer.options.hydratable && this.fragment.nodes.length) {
nodes = block.get_unique_name('head_nodes'); nodes = block.get_unique_name('head_nodes');
block.chunks.claim.push(b`const ${nodes} = @query_selector_all('[data-svelte="${this.node.id}"]', @_document.head);`); block.chunks.claim.push(b`const ${nodes} = @head_selector('${this.node.id}', @_document.head);`);
} }
this.fragment.render(block, x`@_document.head` as unknown as Identifier, nodes); this.fragment.render(block, x`@_document.head` as unknown as Identifier, nodes);

@ -399,12 +399,21 @@ export default class InlineComponentWrapper extends Wrapper {
return b`${name}.$on("${handler.name}", ${snippet});`; return b`${name}.$on("${handler.name}", ${snippet});`;
}); });
const mount_target = has_css_custom_properties ? css_custom_properties_wrapper : (parent_node || '#target');
const mount_anchor = has_css_custom_properties ? 'null' : (parent_node ? 'null' : '#anchor');
const to_claim = parent_nodes && this.renderer.options.hydratable;
let claim_nodes = parent_nodes;
if (this.node.name === 'svelte:component') { if (this.node.name === 'svelte:component') {
const switch_value = block.get_unique_name('switch_value'); const switch_value = block.get_unique_name('switch_value');
const switch_props = block.get_unique_name('switch_props'); const switch_props = block.get_unique_name('switch_props');
const snippet = this.node.expression.manipulate(block); const snippet = this.node.expression.manipulate(block);
if (has_css_custom_properties) {
this.set_css_custom_properties(block, css_custom_properties_wrapper);
}
block.chunks.init.push(b` block.chunks.init.push(b`
var ${switch_value} = ${snippet}; var ${switch_value} = ${snippet};
@ -427,20 +436,13 @@ export default class InlineComponentWrapper extends Wrapper {
b`if (${name}) @create_component(${name}.$$.fragment);` b`if (${name}) @create_component(${name}.$$.fragment);`
); );
if (parent_nodes && this.renderer.options.hydratable) { if (css_custom_properties_wrapper) this.create_css_custom_properties_wrapper_mount_chunk(block, parent_node, css_custom_properties_wrapper);
block.chunks.claim.push( block.chunks.mount.push(b`if (${name}) @mount_component(${name}, ${mount_target}, ${mount_anchor});`);
b`if (${name}) @claim_component(${name}.$$.fragment, ${parent_nodes});`
);
}
block.chunks.mount.push(b`
if (${name}) {
@mount_component(${name}, ${parent_node || '#target'}, ${parent_node ? 'null' : '#anchor'});
}
`);
const anchor = this.get_or_create_anchor(block, parent_node, parent_nodes); if (to_claim) {
const update_mount_node = this.get_update_mount_node(anchor); if (css_custom_properties_wrapper) claim_nodes = this.create_css_custom_properties_wrapper_claim_chunk(block, claim_nodes, css_custom_properties_wrapper);
block.chunks.claim.push(b`if (${name}) @claim_component(${name}.$$.fragment, ${claim_nodes});`);
}
if (updates.length) { if (updates.length) {
block.chunks.update.push(b` block.chunks.update.push(b`
@ -448,6 +450,15 @@ export default class InlineComponentWrapper extends Wrapper {
`); `);
} }
const tmp_anchor = this.get_or_create_anchor(block, parent_node, parent_nodes);
const anchor = has_css_custom_properties ? 'null' : tmp_anchor;
const update_mount_node = has_css_custom_properties ? css_custom_properties_wrapper : this.get_update_mount_node(tmp_anchor);
const update_insert =
css_custom_properties_wrapper &&
(tmp_anchor.name !== 'null'
? b`@insert(${tmp_anchor}.parentNode, ${css_custom_properties_wrapper}, ${tmp_anchor});`
: b`@insert(${parent_node}, ${css_custom_properties_wrapper}, ${tmp_anchor});`);
block.chunks.update.push(b` block.chunks.update.push(b`
if (${switch_value} !== (${switch_value} = ${snippet})) { if (${switch_value} !== (${switch_value} = ${snippet})) {
if (${name}) { if (${name}) {
@ -455,11 +466,13 @@ export default class InlineComponentWrapper extends Wrapper {
const old_component = ${name}; const old_component = ${name};
@transition_out(old_component.$$.fragment, 1, 0, () => { @transition_out(old_component.$$.fragment, 1, 0, () => {
@destroy_component(old_component, 1); @destroy_component(old_component, 1);
${has_css_custom_properties ? b`@detach(${update_mount_node})` : null}
}); });
@check_outros(); @check_outros();
} }
if (${switch_value}) { if (${switch_value}) {
${update_insert}
${name} = @construct_svelte_component(${switch_value}, ${switch_props}(#ctx)); ${name} = @construct_svelte_component(${switch_value}, ${switch_props}(#ctx));
${munged_bindings} ${munged_bindings}
@ -501,62 +514,16 @@ export default class InlineComponentWrapper extends Wrapper {
`); `);
if (has_css_custom_properties) { if (has_css_custom_properties) {
block.chunks.create.push(b`${css_custom_properties_wrapper} = @element("div");`); this.set_css_custom_properties(block, css_custom_properties_wrapper);
block.chunks.hydrate.push(b`@set_style(${css_custom_properties_wrapper}, "display", "contents");`);
this.node.css_custom_properties.forEach(attr => {
const dependencies = attr.get_dependencies();
const should_cache = attr.should_cache();
const last = should_cache && block.get_unique_name(`${attr.name.replace(/[^a-zA-Z_$]/g, '_')}_last`);
if (should_cache) block.add_variable(last);
const value = attr.get_value(block);
const init = should_cache ? x`${last} = ${value}` : value;
block.chunks.hydrate.push(b`@set_style(${css_custom_properties_wrapper}, "${attr.name}", ${init});`);
if (dependencies.length > 0) {
let condition = block.renderer.dirty(dependencies);
if (should_cache) condition = x`${condition} && (${last} !== (${last} = ${value}))`;
block.chunks.update.push(b`
if (${condition}) {
@set_style(${css_custom_properties_wrapper}, "${attr.name}", ${should_cache ? last : value});
}
`);
}
});
} }
block.chunks.create.push(b`@create_component(${name}.$$.fragment);`); block.chunks.create.push(b`@create_component(${name}.$$.fragment);`);
if (parent_nodes && this.renderer.options.hydratable) { if (css_custom_properties_wrapper) this.create_css_custom_properties_wrapper_mount_chunk(block, parent_node, css_custom_properties_wrapper);
let nodes = parent_nodes; block.chunks.mount.push(b`@mount_component(${name}, ${mount_target}, ${mount_anchor});`);
if (has_css_custom_properties) {
nodes = block.get_unique_name(`${css_custom_properties_wrapper.name}_nodes`);
block.chunks.claim.push(b`
${css_custom_properties_wrapper} = @claim_element(${parent_nodes}, "DIV", { style: true })
var ${nodes} = @children(${css_custom_properties_wrapper});
`);
}
block.chunks.claim.push(
b`@claim_component(${name}.$$.fragment, ${nodes});`
);
}
if (has_css_custom_properties) { if (to_claim) {
if (parent_node) { if (css_custom_properties_wrapper) claim_nodes = this.create_css_custom_properties_wrapper_claim_chunk(block, claim_nodes, css_custom_properties_wrapper);
block.chunks.mount.push(b`@append(${parent_node}, ${css_custom_properties_wrapper})`); block.chunks.claim.push(b`@claim_component(${name}.$$.fragment, ${claim_nodes});`);
if (is_head(parent_node)) {
block.chunks.destroy.push(b`@detach(${css_custom_properties_wrapper});`);
}
} else {
block.chunks.mount.push(b`@insert(#target, ${css_custom_properties_wrapper}, #anchor);`);
// TODO we eventually need to consider what happens to elements
// that belong to the same outgroup as an outroing element...
block.chunks.destroy.push(b`if (detaching) @detach(${css_custom_properties_wrapper});`);
}
block.chunks.mount.push(b`@mount_component(${name}, ${css_custom_properties_wrapper}, null);`);
} else {
block.chunks.mount.push(
b`@mount_component(${name}, ${parent_node || '#target'}, ${parent_node ? 'null' : '#anchor'});`
);
} }
block.chunks.intro.push(b` block.chunks.intro.push(b`
@ -579,4 +546,64 @@ export default class InlineComponentWrapper extends Wrapper {
); );
} }
} }
private create_css_custom_properties_wrapper_mount_chunk(
block: Block,
parent_node: Identifier,
css_custom_properties_wrapper: Identifier | null
) {
if (parent_node) {
block.chunks.mount.push(b`@append(${parent_node}, ${css_custom_properties_wrapper})`);
if (is_head(parent_node)) {
block.chunks.destroy.push(b`@detach(${css_custom_properties_wrapper});`);
}
} else {
block.chunks.mount.push(b`@insert(#target, ${css_custom_properties_wrapper}, #anchor);`);
// TODO we eventually need to consider what happens to elements
// that belong to the same outgroup as an outroing element...
block.chunks.destroy.push(b`if (detaching && ${this.var}) @detach(${css_custom_properties_wrapper});`);
}
}
private create_css_custom_properties_wrapper_claim_chunk(
block: Block,
parent_nodes: Identifier,
css_custom_properties_wrapper: Identifier | null
) {
const nodes = block.get_unique_name(`${css_custom_properties_wrapper.name}_nodes`);
block.chunks.claim.push(b`
${css_custom_properties_wrapper} = @claim_element(${parent_nodes}, "DIV", { style: true })
var ${nodes} = @children(${css_custom_properties_wrapper});
`);
return nodes;
}
private set_css_custom_properties(
block: Block,
css_custom_properties_wrapper: Identifier
) {
block.chunks.create.push(b`${css_custom_properties_wrapper} = @element("div");`);
block.chunks.hydrate.push(b`@set_style(${css_custom_properties_wrapper}, "display", "contents");`);
this.node.css_custom_properties.forEach((attr) => {
const dependencies = attr.get_dependencies();
const should_cache = attr.should_cache();
const last = should_cache && block.get_unique_name(`${attr.name.replace(/[^a-zA-Z_$]/g, '_')}_last`);
if (should_cache) block.add_variable(last);
const value = attr.get_value(block);
const init = should_cache ? x`${last} = ${value}` : value;
block.chunks.hydrate.push(
b`@set_style(${css_custom_properties_wrapper}, "${attr.name}", ${init});`
);
if (dependencies.length > 0) {
let condition = block.renderer.dirty(dependencies);
if (should_cache) condition = x`${condition} && (${last} !== (${last} = ${value}))`;
block.chunks.update.push(b`
if (${condition}) {
@set_style(${css_custom_properties_wrapper}, "${attr.name}", ${should_cache ? last : value});
}
`);
}
});
}
} }

@ -157,10 +157,6 @@ export default function (node: Element, renderer: Renderer, options: RenderOptio
} }
}); });
if (options.hydratable && options.head_id) {
renderer.add_string(` data-svelte="${options.head_id}"`);
}
renderer.add_string('>'); renderer.add_string('>');
if (node_contents !== undefined) { if (node_contents !== undefined) {

@ -12,5 +12,5 @@ export default function(node: Head, renderer: Renderer, options: RenderOptions)
renderer.render(node.children, head_options); renderer.render(node.children, head_options);
const result = renderer.pop(); const result = renderer.pop();
renderer.add_expression(x`$$result.head += ${result}, ""`); renderer.add_expression(x`$$result.head += '<!-- HEAD_${node.id}_START -->' + ${result} + '<!-- HEAD_${node.id}_END -->', ""`);
} }

@ -237,7 +237,7 @@ function trim(nodes: TemplateNode[]) {
const node = nodes[end - 1] as Text; const node = nodes[end - 1] as Text;
if (node.type !== 'Text') break; if (node.type !== 'Text') break;
node.data = node.data.replace(/\s+$/, ''); node.data = node.data.trimRight();
if (node.data) break; if (node.data) break;
} }

@ -0,0 +1,157 @@
import {
ARIARoleDefintionKey,
roles as roles_map,
elementRoles,
ARIARoleRelationConcept
} from 'aria-query';
import { AXObjects, elementAXObjects } from 'axobject-query';
import Attribute from '../nodes/Attribute';
const roles = [...roles_map.keys()];
const non_interactive_roles = new Set(
roles
.filter((name) => {
const role = roles_map.get(name);
return (
!roles_map.get(name).abstract &&
// 'toolbar' does not descend from widget, but it does support
// aria-activedescendant, thus in practice we treat it as a widget.
name !== 'toolbar' &&
!role.superClass.some((classes) => classes.includes('widget'))
);
})
.concat(
// The `progressbar` is descended from `widget`, but in practice, its
// value is always `readonly`, so we treat it as a non-interactive role.
'progressbar'
)
);
const interactive_roles = new Set(
roles
.filter((name) => {
const role = roles_map.get(name);
return (
!role.abstract &&
// The `progressbar` is descended from `widget`, but in practice, its
// value is always `readonly`, so we treat it as a non-interactive role.
name !== 'progressbar' &&
role.superClass.some((classes) => classes.includes('widget'))
);
})
.concat(
// 'toolbar' does not descend from widget, but it does support
// aria-activedescendant, thus in practice we treat it as a widget.
'toolbar'
)
);
export function is_non_interactive_roles(role: ARIARoleDefintionKey) {
return non_interactive_roles.has(role);
}
export function is_interactive_roles(role: ARIARoleDefintionKey) {
return interactive_roles.has(role);
}
const presentation_roles = new Set(['presentation', 'none']);
export function is_presentation_role(role: ARIARoleDefintionKey) {
return presentation_roles.has(role);
}
export function is_hidden_from_screen_reader(tag_name: string, attribute_map: Map<string, Attribute>) {
if (tag_name === 'input') {
const type = attribute_map.get('type')?.get_static_value();
if (type && type === 'hidden') {
return true;
}
}
const aria_hidden = attribute_map.get('aria-hidden');
if (!aria_hidden) return false;
if (!aria_hidden.is_static) return true;
const aria_hidden_value = aria_hidden.get_static_value();
return aria_hidden_value === true || aria_hidden_value === 'true';
}
const non_interactive_element_role_schemas: ARIARoleRelationConcept[] = [];
elementRoles.entries().forEach(([schema, roles]) => {
if ([...roles].every((role) => non_interactive_roles.has(role))) {
non_interactive_element_role_schemas.push(schema);
}
});
const interactive_element_role_schemas: ARIARoleRelationConcept[] = [];
elementRoles.entries().forEach(([schema, roles]) => {
if ([...roles].every((role) => interactive_roles.has(role))) {
interactive_element_role_schemas.push(schema);
}
});
const interactive_ax_objects = new Set(
[...AXObjects.keys()].filter((name) => AXObjects.get(name).type === 'widget')
);
const interactive_element_ax_object_schemas: ARIARoleRelationConcept[] = [];
elementAXObjects.entries().forEach(([schema, ax_object]) => {
if ([...ax_object].every((role) => interactive_ax_objects.has(role))) {
interactive_element_ax_object_schemas.push(schema);
}
});
function match_schema(
schema: ARIARoleRelationConcept,
tag_name: string,
attribute_map: Map<string, Attribute>
) {
if (schema.name !== tag_name) return false;
if (!schema.attributes) return true;
return schema.attributes.every((schema_attribute) => {
const attribute = attribute_map.get(schema_attribute.name);
if (!attribute) return false;
if (
schema_attribute.value &&
schema_attribute.value !== attribute.get_static_value()
) {
return false;
}
return true;
});
}
export function is_interactive_element(
tag_name: string,
attribute_map: Map<string, Attribute>
): boolean {
if (
interactive_element_role_schemas.some((schema) =>
match_schema(schema, tag_name, attribute_map)
)
) {
return true;
}
if (
non_interactive_element_role_schemas.some((schema) =>
match_schema(schema, tag_name, attribute_map)
)
) {
return false;
}
if (
interactive_element_ax_object_schemas.some((schema) =>
match_schema(schema, tag_name, attribute_map)
)
) {
return true;
}
return false;
}

@ -4,3 +4,4 @@ export { default as preprocess } from './preprocess/index';
export { walk } from 'estree-walker'; export { walk } from 'estree-walker';
export const VERSION = '__VERSION__'; export const VERSION = '__VERSION__';
// additional exports added through generate-type-definitions.js

@ -34,7 +34,7 @@ export class Parser {
throw new TypeError('Template must be a string'); throw new TypeError('Template must be a string');
} }
this.template = template.replace(/\s+$/, ''); this.template = template.trimRight();
this.filename = options.filename; this.filename = options.filename;
this.customElement = options.customElement; this.customElement = options.customElement;

@ -40,3 +40,10 @@ export interface PreprocessorGroup {
style?: Preprocessor; style?: Preprocessor;
script?: Preprocessor; script?: Preprocessor;
} }
export interface SveltePreprocessor<
PreprocessorType extends keyof PreprocessorGroup,
Options = any
> {
(options?: Options): Required<Pick<PreprocessorGroup, PreprocessorType>>;
}

@ -0,0 +1,840 @@
/** ----------------------------------------------------------------------
This file is automatically generated by `scripts/globals-extractor.mjs`.
Generated At: 2022-09-03T15:22:37.415Z
---------------------------------------------------------------------- */
export default new Set([
'AbortController',
'AbortSignal',
'AbstractRange',
'ActiveXObject',
'AggregateError',
'AnalyserNode',
'Animation',
'AnimationEffect',
'AnimationEvent',
'AnimationPlaybackEvent',
'AnimationTimeline',
'Array',
'ArrayBuffer',
'Atomics',
'Attr',
'Audio',
'AudioBuffer',
'AudioBufferSourceNode',
'AudioContext',
'AudioDestinationNode',
'AudioListener',
'AudioNode',
'AudioParam',
'AudioParamMap',
'AudioProcessingEvent',
'AudioScheduledSourceNode',
'AudioWorklet',
'AudioWorkletNode',
'AuthenticatorAssertionResponse',
'AuthenticatorAttestationResponse',
'AuthenticatorResponse',
'BarProp',
'BaseAudioContext',
'BeforeUnloadEvent',
'BigInt',
'BigInt64Array',
'BigUint64Array',
'BiquadFilterNode',
'Blob',
'BlobEvent',
'Boolean',
'BroadcastChannel',
'ByteLengthQueuingStrategy',
'CDATASection',
'CSS',
'CSSAnimation',
'CSSConditionRule',
'CSSCounterStyleRule',
'CSSFontFaceRule',
'CSSGroupingRule',
'CSSImportRule',
'CSSKeyframeRule',
'CSSKeyframesRule',
'CSSMediaRule',
'CSSNamespaceRule',
'CSSPageRule',
'CSSRule',
'CSSRuleList',
'CSSStyleDeclaration',
'CSSStyleRule',
'CSSStyleSheet',
'CSSSupportsRule',
'CSSTransition',
'Cache',
'CacheStorage',
'CanvasCaptureMediaStreamTrack',
'CanvasGradient',
'CanvasPattern',
'CanvasRenderingContext2D',
'ChannelMergerNode',
'ChannelSplitterNode',
'CharacterData',
'ClientRect',
'Clipboard',
'ClipboardEvent',
'ClipboardItem',
'CloseEvent',
'Comment',
'CompositionEvent',
'ConstantSourceNode',
'ConvolverNode',
'CountQueuingStrategy',
'Credential',
'CredentialsContainer',
'Crypto',
'CryptoKey',
'CustomElementRegistry',
'CustomEvent',
'DOMException',
'DOMImplementation',
'DOMMatrix',
'DOMMatrixReadOnly',
'DOMParser',
'DOMPoint',
'DOMPointReadOnly',
'DOMQuad',
'DOMRect',
'DOMRectList',
'DOMRectReadOnly',
'DOMStringList',
'DOMStringMap',
'DOMTokenList',
'DataTransfer',
'DataTransferItem',
'DataTransferItemList',
'DataView',
'Date',
'DelayNode',
'DeviceMotionEvent',
'DeviceOrientationEvent',
'Document',
'DocumentFragment',
'DocumentTimeline',
'DocumentType',
'DragEvent',
'DynamicsCompressorNode',
'Element',
'ElementInternals',
'Enumerator',
'Error',
'ErrorEvent',
'EvalError',
'Event',
'EventCounts',
'EventSource',
'EventTarget',
'External',
'File',
'FileList',
'FileReader',
'FileSystem',
'FileSystemDirectoryEntry',
'FileSystemDirectoryHandle',
'FileSystemDirectoryReader',
'FileSystemEntry',
'FileSystemFileEntry',
'FileSystemFileHandle',
'FileSystemHandle',
'FinalizationRegistry',
'Float32Array',
'Float64Array',
'FocusEvent',
'FontFace',
'FontFaceSet',
'FontFaceSetLoadEvent',
'FormData',
'FormDataEvent',
'Function',
'GainNode',
'Gamepad',
'GamepadButton',
'GamepadEvent',
'GamepadHapticActuator',
'Geolocation',
'GeolocationCoordinates',
'GeolocationPosition',
'GeolocationPositionError',
'HTMLAllCollection',
'HTMLAnchorElement',
'HTMLAreaElement',
'HTMLAudioElement',
'HTMLBRElement',
'HTMLBaseElement',
'HTMLBodyElement',
'HTMLButtonElement',
'HTMLCanvasElement',
'HTMLCollection',
'HTMLDListElement',
'HTMLDataElement',
'HTMLDataListElement',
'HTMLDetailsElement',
'HTMLDialogElement',
'HTMLDirectoryElement',
'HTMLDivElement',
'HTMLDocument',
'HTMLElement',
'HTMLEmbedElement',
'HTMLFieldSetElement',
'HTMLFontElement',
'HTMLFormControlsCollection',
'HTMLFormElement',
'HTMLFrameElement',
'HTMLFrameSetElement',
'HTMLHRElement',
'HTMLHeadElement',
'HTMLHeadingElement',
'HTMLHtmlElement',
'HTMLIFrameElement',
'HTMLImageElement',
'HTMLInputElement',
'HTMLLIElement',
'HTMLLabelElement',
'HTMLLegendElement',
'HTMLLinkElement',
'HTMLMapElement',
'HTMLMarqueeElement',
'HTMLMediaElement',
'HTMLMenuElement',
'HTMLMetaElement',
'HTMLMeterElement',
'HTMLModElement',
'HTMLOListElement',
'HTMLObjectElement',
'HTMLOptGroupElement',
'HTMLOptionElement',
'HTMLOptionsCollection',
'HTMLOutputElement',
'HTMLParagraphElement',
'HTMLParamElement',
'HTMLPictureElement',
'HTMLPreElement',
'HTMLProgressElement',
'HTMLQuoteElement',
'HTMLScriptElement',
'HTMLSelectElement',
'HTMLSlotElement',
'HTMLSourceElement',
'HTMLSpanElement',
'HTMLStyleElement',
'HTMLTableCaptionElement',
'HTMLTableCellElement',
'HTMLTableColElement',
'HTMLTableElement',
'HTMLTableRowElement',
'HTMLTableSectionElement',
'HTMLTemplateElement',
'HTMLTextAreaElement',
'HTMLTimeElement',
'HTMLTitleElement',
'HTMLTrackElement',
'HTMLUListElement',
'HTMLUnknownElement',
'HTMLVideoElement',
'HashChangeEvent',
'Headers',
'History',
'IDBCursor',
'IDBCursorWithValue',
'IDBDatabase',
'IDBFactory',
'IDBIndex',
'IDBKeyRange',
'IDBObjectStore',
'IDBOpenDBRequest',
'IDBRequest',
'IDBTransaction',
'IDBVersionChangeEvent',
'IIRFilterNode',
'IdleDeadline',
'Image',
'ImageBitmap',
'ImageBitmapRenderingContext',
'ImageData',
'Infinity',
'InputDeviceInfo',
'InputEvent',
'Int16Array',
'Int32Array',
'Int8Array',
'InternalError',
'IntersectionObserver',
'IntersectionObserverEntry',
'Intl',
'JSON',
'KeyboardEvent',
'KeyframeEffect',
'Location',
'Lock',
'LockManager',
'Map',
'Math',
'MathMLElement',
'MediaCapabilities',
'MediaDeviceInfo',
'MediaDevices',
'MediaElementAudioSourceNode',
'MediaEncryptedEvent',
'MediaError',
'MediaKeyMessageEvent',
'MediaKeySession',
'MediaKeyStatusMap',
'MediaKeySystemAccess',
'MediaKeys',
'MediaList',
'MediaMetadata',
'MediaQueryList',
'MediaQueryListEvent',
'MediaRecorder',
'MediaRecorderErrorEvent',
'MediaSession',
'MediaSource',
'MediaStream',
'MediaStreamAudioDestinationNode',
'MediaStreamAudioSourceNode',
'MediaStreamTrack',
'MediaStreamTrackEvent',
'MessageChannel',
'MessageEvent',
'MessagePort',
'MimeType',
'MimeTypeArray',
'MouseEvent',
'MutationEvent',
'MutationObserver',
'MutationRecord',
'NaN',
'NamedNodeMap',
'NavigationPreloadManager',
'Navigator',
'NetworkInformation',
'Node',
'NodeFilter',
'NodeIterator',
'NodeList',
'Notification',
'Number',
'Object',
'OfflineAudioCompletionEvent',
'OfflineAudioContext',
'Option',
'OscillatorNode',
'OverconstrainedError',
'PageTransitionEvent',
'PannerNode',
'Path2D',
'PaymentAddress',
'PaymentMethodChangeEvent',
'PaymentRequest',
'PaymentRequestUpdateEvent',
'PaymentResponse',
'Performance',
'PerformanceEntry',
'PerformanceEventTiming',
'PerformanceMark',
'PerformanceMeasure',
'PerformanceNavigation',
'PerformanceNavigationTiming',
'PerformanceObserver',
'PerformanceObserverEntryList',
'PerformancePaintTiming',
'PerformanceResourceTiming',
'PerformanceServerTiming',
'PerformanceTiming',
'PeriodicWave',
'PermissionStatus',
'Permissions',
'PictureInPictureWindow',
'Plugin',
'PluginArray',
'PointerEvent',
'PopStateEvent',
'ProcessingInstruction',
'ProgressEvent',
'Promise',
'PromiseRejectionEvent',
'Proxy',
'PublicKeyCredential',
'PushManager',
'PushSubscription',
'PushSubscriptionOptions',
'RTCCertificate',
'RTCDTMFSender',
'RTCDTMFToneChangeEvent',
'RTCDataChannel',
'RTCDataChannelEvent',
'RTCDtlsTransport',
'RTCEncodedAudioFrame',
'RTCEncodedVideoFrame',
'RTCError',
'RTCErrorEvent',
'RTCIceCandidate',
'RTCIceTransport',
'RTCPeerConnection',
'RTCPeerConnectionIceErrorEvent',
'RTCPeerConnectionIceEvent',
'RTCRtpReceiver',
'RTCRtpSender',
'RTCRtpTransceiver',
'RTCSctpTransport',
'RTCSessionDescription',
'RTCStatsReport',
'RTCTrackEvent',
'RadioNodeList',
'Range',
'RangeError',
'ReadableByteStreamController',
'ReadableStream',
'ReadableStreamBYOBReader',
'ReadableStreamBYOBRequest',
'ReadableStreamDefaultController',
'ReadableStreamDefaultReader',
'ReferenceError',
'Reflect',
'RegExp',
'RemotePlayback',
'Request',
'ResizeObserver',
'ResizeObserverEntry',
'ResizeObserverSize',
'Response',
'SVGAElement',
'SVGAngle',
'SVGAnimateElement',
'SVGAnimateMotionElement',
'SVGAnimateTransformElement',
'SVGAnimatedAngle',
'SVGAnimatedBoolean',
'SVGAnimatedEnumeration',
'SVGAnimatedInteger',
'SVGAnimatedLength',
'SVGAnimatedLengthList',
'SVGAnimatedNumber',
'SVGAnimatedNumberList',
'SVGAnimatedPreserveAspectRatio',
'SVGAnimatedRect',
'SVGAnimatedString',
'SVGAnimatedTransformList',
'SVGAnimationElement',
'SVGCircleElement',
'SVGClipPathElement',
'SVGComponentTransferFunctionElement',
'SVGCursorElement',
'SVGDefsElement',
'SVGDescElement',
'SVGElement',
'SVGEllipseElement',
'SVGFEBlendElement',
'SVGFEColorMatrixElement',
'SVGFEComponentTransferElement',
'SVGFECompositeElement',
'SVGFEConvolveMatrixElement',
'SVGFEDiffuseLightingElement',
'SVGFEDisplacementMapElement',
'SVGFEDistantLightElement',
'SVGFEDropShadowElement',
'SVGFEFloodElement',
'SVGFEFuncAElement',
'SVGFEFuncBElement',
'SVGFEFuncGElement',
'SVGFEFuncRElement',
'SVGFEGaussianBlurElement',
'SVGFEImageElement',
'SVGFEMergeElement',
'SVGFEMergeNodeElement',
'SVGFEMorphologyElement',
'SVGFEOffsetElement',
'SVGFEPointLightElement',
'SVGFESpecularLightingElement',
'SVGFESpotLightElement',
'SVGFETileElement',
'SVGFETurbulenceElement',
'SVGFilterElement',
'SVGForeignObjectElement',
'SVGGElement',
'SVGGeometryElement',
'SVGGradientElement',
'SVGGraphicsElement',
'SVGImageElement',
'SVGLength',
'SVGLengthList',
'SVGLineElement',
'SVGLinearGradientElement',
'SVGMPathElement',
'SVGMarkerElement',
'SVGMaskElement',
'SVGMatrix',
'SVGMetadataElement',
'SVGNumber',
'SVGNumberList',
'SVGPathElement',
'SVGPatternElement',
'SVGPoint',
'SVGPointList',
'SVGPolygonElement',
'SVGPolylineElement',
'SVGPreserveAspectRatio',
'SVGRadialGradientElement',
'SVGRect',
'SVGRectElement',
'SVGSVGElement',
'SVGScriptElement',
'SVGSetElement',
'SVGStopElement',
'SVGStringList',
'SVGStyleElement',
'SVGSwitchElement',
'SVGSymbolElement',
'SVGTSpanElement',
'SVGTextContentElement',
'SVGTextElement',
'SVGTextPathElement',
'SVGTextPositioningElement',
'SVGTitleElement',
'SVGTransform',
'SVGTransformList',
'SVGUnitTypes',
'SVGUseElement',
'SVGViewElement',
'SafeArray',
'Screen',
'ScreenOrientation',
'ScriptProcessorNode',
'SecurityPolicyViolationEvent',
'Selection',
'ServiceWorker',
'ServiceWorkerContainer',
'ServiceWorkerRegistration',
'Set',
'ShadowRoot',
'SharedArrayBuffer',
'SharedWorker',
'SourceBuffer',
'SourceBufferList',
'SpeechRecognitionAlternative',
'SpeechRecognitionErrorEvent',
'SpeechRecognitionResult',
'SpeechRecognitionResultList',
'SpeechSynthesis',
'SpeechSynthesisErrorEvent',
'SpeechSynthesisEvent',
'SpeechSynthesisUtterance',
'SpeechSynthesisVoice',
'StaticRange',
'StereoPannerNode',
'Storage',
'StorageEvent',
'StorageManager',
'String',
'StyleMedia',
'StyleSheet',
'StyleSheetList',
'SubmitEvent',
'SubtleCrypto',
'Symbol',
'SyntaxError',
'Text',
'TextDecoder',
'TextDecoderStream',
'TextEncoder',
'TextEncoderStream',
'TextMetrics',
'TextTrack',
'TextTrackCue',
'TextTrackCueList',
'TextTrackList',
'TimeRanges',
'Touch',
'TouchEvent',
'TouchList',
'TrackEvent',
'TransformStream',
'TransformStreamDefaultController',
'TransitionEvent',
'TreeWalker',
'TypeError',
'UIEvent',
'URIError',
'URL',
'URLSearchParams',
'Uint16Array',
'Uint32Array',
'Uint8Array',
'Uint8ClampedArray',
'VBArray',
'VTTCue',
'VTTRegion',
'ValidityState',
'VarDate',
'VideoColorSpace',
'VideoPlaybackQuality',
'VisualViewport',
'WSH',
'WScript',
'WaveShaperNode',
'WeakMap',
'WeakRef',
'WeakSet',
'WebAssembly',
'WebGL2RenderingContext',
'WebGLActiveInfo',
'WebGLBuffer',
'WebGLContextEvent',
'WebGLFramebuffer',
'WebGLProgram',
'WebGLQuery',
'WebGLRenderbuffer',
'WebGLRenderingContext',
'WebGLSampler',
'WebGLShader',
'WebGLShaderPrecisionFormat',
'WebGLSync',
'WebGLTexture',
'WebGLTransformFeedback',
'WebGLUniformLocation',
'WebGLVertexArrayObject',
'WebKitCSSMatrix',
'WebSocket',
'WheelEvent',
'Window',
'Worker',
'Worklet',
'WritableStream',
'WritableStreamDefaultController',
'WritableStreamDefaultWriter',
'XMLDocument',
'XMLHttpRequest',
'XMLHttpRequestEventTarget',
'XMLHttpRequestUpload',
'XMLSerializer',
'XPathEvaluator',
'XPathExpression',
'XPathResult',
'XSLTProcessor',
'addEventListener',
'alert',
'atob',
'blur',
'btoa',
'caches',
'cancelAnimationFrame',
'cancelIdleCallback',
'captureEvents',
'clearInterval',
'clearTimeout',
'clientInformation',
'close',
'closed',
'confirm',
'console',
'createImageBitmap',
'crossOriginIsolated',
'crypto',
'customElements',
'decodeURI',
'decodeURIComponent',
'devicePixelRatio',
'dispatchEvent',
'document',
'encodeURI',
'encodeURIComponent',
'escape',
'eval',
'event',
'external',
'fetch',
'focus',
'frameElement',
'frames',
'getComputedStyle',
'getSelection',
'global',
'globalThis',
'history',
'importScripts',
'indexedDB',
'innerHeight',
'innerWidth',
'isFinite',
'isNaN',
'isSecureContext',
'length',
'localStorage',
'location',
'locationbar',
'matchMedia',
'menubar',
'moveBy',
'moveTo',
'name',
'navigator',
'onabort',
'onafterprint',
'onanimationcancel',
'onanimationend',
'onanimationiteration',
'onanimationstart',
'onauxclick',
'onbeforeprint',
'onbeforeunload',
'onblur',
'oncanplay',
'oncanplaythrough',
'onchange',
'onclick',
'onclose',
'oncontextmenu',
'oncuechange',
'ondblclick',
'ondevicemotion',
'ondeviceorientation',
'ondrag',
'ondragend',
'ondragenter',
'ondragleave',
'ondragover',
'ondragstart',
'ondrop',
'ondurationchange',
'onemptied',
'onended',
'onerror',
'onfocus',
'onformdata',
'ongamepadconnected',
'ongamepaddisconnected',
'ongotpointercapture',
'onhashchange',
'oninput',
'oninvalid',
'onkeydown',
'onkeypress',
'onkeyup',
'onlanguagechange',
'onload',
'onloadeddata',
'onloadedmetadata',
'onloadstart',
'onlostpointercapture',
'onmessage',
'onmessageerror',
'onmousedown',
'onmouseenter',
'onmouseleave',
'onmousemove',
'onmouseout',
'onmouseover',
'onmouseup',
'onoffline',
'ononline',
'onorientationchange',
'onpagehide',
'onpageshow',
'onpause',
'onplay',
'onplaying',
'onpointercancel',
'onpointerdown',
'onpointerenter',
'onpointerleave',
'onpointermove',
'onpointerout',
'onpointerover',
'onpointerup',
'onpopstate',
'onprogress',
'onratechange',
'onrejectionhandled',
'onreset',
'onresize',
'onscroll',
'onsecuritypolicyviolation',
'onseeked',
'onseeking',
'onselect',
'onselectionchange',
'onselectstart',
'onslotchange',
'onstalled',
'onstorage',
'onsubmit',
'onsuspend',
'ontimeupdate',
'ontoggle',
'ontouchcancel',
'ontouchend',
'ontouchmove',
'ontouchstart',
'ontransitioncancel',
'ontransitionend',
'ontransitionrun',
'ontransitionstart',
'onunhandledrejection',
'onunload',
'onvolumechange',
'onwaiting',
'onwebkitanimationend',
'onwebkitanimationiteration',
'onwebkitanimationstart',
'onwebkittransitionend',
'onwheel',
'open',
'opener',
'orientation',
'origin',
'outerHeight',
'outerWidth',
'pageXOffset',
'pageYOffset',
'parent',
'parseFloat',
'parseInt',
'performance',
'personalbar',
'postMessage',
'print',
'process',
'prompt',
'queueMicrotask',
'releaseEvents',
'removeEventListener',
'reportError',
'requestAnimationFrame',
'requestIdleCallback',
'resizeBy',
'resizeTo',
'screen',
'screenLeft',
'screenTop',
'screenX',
'screenY',
'scroll',
'scrollBy',
'scrollTo',
'scrollX',
'scrollY',
'scrollbars',
'self',
'sessionStorage',
'setInterval',
'setTimeout',
'speechSynthesis',
'status',
'statusbar',
'stop',
'structuredClone',
'toString',
'toolbar',
'top',
'undefined',
'unescape',
'visualViewport',
'webkitURL',
'window'
]);

@ -1,71 +1,6 @@
import { isIdentifierStart, isIdentifierChar } from 'acorn'; import { isIdentifierStart, isIdentifierChar } from 'acorn';
import full_char_code_at from './full_char_code_at'; import full_char_code_at from './full_char_code_at';
export const globals = new Set([
'alert',
'Array',
'BigInt',
'Boolean',
'clearInterval',
'clearTimeout',
'confirm',
'console',
'Date',
'decodeURI',
'decodeURIComponent',
'document',
'Element',
'encodeURI',
'encodeURIComponent',
'Error',
'EvalError',
'Event',
'EventSource',
'fetch',
'FormData',
'global',
'globalThis',
'history',
'HTMLElement',
'Infinity',
'InternalError',
'Intl',
'isFinite',
'isNaN',
'JSON',
'localStorage',
'location',
'Map',
'Math',
'NaN',
'navigator',
'Node',
'Number',
'Object',
'parseFloat',
'parseInt',
'process',
'Promise',
'prompt',
'RangeError',
'ReferenceError',
'RegExp',
'sessionStorage',
'Set',
'setInterval',
'setTimeout',
'String',
'SVGElement',
'Symbol',
'SyntaxError',
'TypeError',
'undefined',
'URIError',
'URL',
'URLSearchParams',
'window'
]);
export const reserved = new Set([ export const reserved = new Set([
'arguments', 'arguments',
'await', 'await',

@ -4,9 +4,17 @@
* immediately after Svelte has applied updates to the markup. * immediately after Svelte has applied updates to the markup.
* - destroy: Method that is called after the element is unmounted * - destroy: Method that is called after the element is unmounted
* *
* Additionally, you can specify which additional attributes and events the action enables on the applied element.
* This applies to TypeScript typings only and has no effect at runtime.
*
* Example usage: * Example usage:
* ```ts * ```ts
* export function myAction(node: HTMLElement, parameter: Parameter): ActionReturn<Parameter> { * interface Attributes {
* newprop?: string;
* 'on:event': (e: CustomEvent<boolean>) => void;
* }
*
* export function myAction(node: HTMLElement, parameter: Parameter): ActionReturn<Parameter, Attributes> {
* // ... * // ...
* return { * return {
* update: (updatedParameter) => {...}, * update: (updatedParameter) => {...},
@ -17,9 +25,15 @@
* *
* Docs: https://svelte.dev/docs#template-syntax-element-directives-use-action * Docs: https://svelte.dev/docs#template-syntax-element-directives-use-action
*/ */
export interface ActionReturn<Parameter = any> { export interface ActionReturn<Parameter = any, Attributes extends Record<string, any> = Record<never, any>> {
update?: (parameter: Parameter) => void; update?: (parameter: Parameter) => void;
destroy?: () => void; destroy?: () => void;
/**
* ### DO NOT USE THIS
* This exists solely for type-checking and has no effect at runtime.
* Set this through the `Attributes` generic instead.
*/
$$_attributes?: Attributes;
} }
/** /**
@ -32,11 +46,11 @@ export interface ActionReturn<Parameter = any> {
* // ... * // ...
* } * }
* ``` * ```
* You can return an object with methods `update` and `destroy` from the function. * You can return an object with methods `update` and `destroy` from the function and type which additional attributes and events it has.
* See interface `ActionReturn` for more details. * See interface `ActionReturn` for more details.
* *
* Docs: https://svelte.dev/docs#template-syntax-element-directives-use-action * Docs: https://svelte.dev/docs#template-syntax-element-directives-use-action
*/ */
export interface Action<Element = HTMLElement, Parameter = any> { export interface Action<Element = HTMLElement, Parameter = any, Attributes extends Record<string, any> = Record<never, any>> {
<Node extends Element>(node: Node, parameter?: Parameter): void | ActionReturn<Parameter>; <Node extends Element>(node: Node, parameter?: Parameter): void | ActionReturn<Parameter, Attributes>;
} }

@ -13,4 +13,5 @@ export {
createEventDispatcher, createEventDispatcher,
SvelteComponentDev as SvelteComponent, SvelteComponentDev as SvelteComponent,
SvelteComponentTyped SvelteComponentTyped
// additional exports added through generate-type-definitions.js
} from 'svelte/internal'; } from 'svelte/internal';

@ -117,7 +117,9 @@ export function validate_dynamic_element(tag: unknown) {
export function validate_void_dynamic_element(tag: undefined | string) { export function validate_void_dynamic_element(tag: undefined | string) {
if (tag && is_void(tag)) { if (tag && is_void(tag)) {
throw new Error(`<svelte:element this="${tag}"> is self-closing and cannot have content.`); console.warn(
`<svelte:element this="${tag}"> is self-closing and cannot have content.`
);
} }
} }
@ -146,7 +148,7 @@ export interface SvelteComponentDev {
$destroy(): void; $destroy(): void;
[accessor: string]: any; [accessor: string]: any;
} }
interface IComponentOptions<Props extends Record<string, any> = Record<string, any>> { export interface ComponentConstructorOptions<Props extends Record<string, any> = Record<string, any>> {
target: Element | ShadowRoot; target: Element | ShadowRoot;
anchor?: Element; anchor?: Element;
props?: Props; props?: Props;
@ -182,7 +184,7 @@ export class SvelteComponentDev extends SvelteComponent {
*/ */
$$slot_def: any; $$slot_def: any;
constructor(options: IComponentOptions) { constructor(options: ComponentConstructorOptions) {
if (!options || (!options.target && !options.$$inline)) { if (!options || (!options.target && !options.$$inline)) {
throw new Error("'target' is a required option"); throw new Error("'target' is a required option");
} }
@ -274,11 +276,69 @@ export class SvelteComponentTyped<
*/ */
$$slot_def: Slots; $$slot_def: Slots;
constructor(options: IComponentOptions<Props>) { constructor(options: ComponentConstructorOptions<Props>) {
super(options); super(options);
} }
} }
/**
* Convenience type to get the type of a Svelte component. Useful for example in combination with
* dynamic components using `<svelte:component>`.
*
* Example:
* ```html
* <script lang="ts">
* import type { ComponentType, SvelteComponentTyped } from 'svelte';
* import Component1 from './Component1.svelte';
* import Component2 from './Component2.svelte';
*
* const component: ComponentType = someLogic() ? Component1 : Component2;
* const componentOfCertainSubType: ComponentType<SvelteComponentTyped<{ needsThisProp: string }>> = someLogic() ? Component1 : Component2;
* </script>
*
* <svelte:component this={component} />
* <svelte:component this={componentOfCertainSubType} needsThisProp="hello" />
* ```
*/
export type ComponentType<Component extends SvelteComponentTyped = SvelteComponentTyped> = new (
options: ComponentConstructorOptions<
Component extends SvelteComponentTyped<infer Props> ? Props : Record<string, any>
>
) => Component;
/**
* Convenience type to get the props the given component expects. Example:
* ```html
* <script lang="ts">
* import type { ComponentProps } from 'svelte';
* import Component from './Component.svelte';
*
* const props: ComponentProps<Component> = { foo: 'bar' }; // Errors if these aren't the correct props
* </script>
* ```
*/
export type ComponentProps<Component extends SvelteComponent> = Component extends SvelteComponentTyped<infer Props>
? Props
: never;
/**
* Convenience type to get the events the given component expects. Example:
* ```html
* <script lang="ts">
* import type { ComponentEvents } from 'svelte';
* import Component from './Component.svelte';
*
* function handleCloseEvent(event: ComponentEvents<Component>['close']) {
* console.log(event.detail);
* }
* </script>
*
* <Component on:close={handleCloseEvent} />
* ```
*/
export type ComponentEvents<Component extends SvelteComponent> =
Component extends SvelteComponentTyped<any, infer Events> ? Events : never;
export function loop_guard(timeout) { export function loop_guard(timeout) {
const start = Date.now(); const start = Date.now();
return () => { return () => {

@ -162,13 +162,14 @@ export function append_empty_stylesheet(node: Node) {
function append_stylesheet(node: ShadowRoot | Document, style: HTMLStyleElement) { function append_stylesheet(node: ShadowRoot | Document, style: HTMLStyleElement) {
append((node as Document).head || node, style); append((node as Document).head || node, style);
return style.sheet as CSSStyleSheet;
} }
export function append_hydration(target: NodeEx, node: NodeEx) { export function append_hydration(target: NodeEx, node: NodeEx) {
if (is_hydrating) { if (is_hydrating) {
init_hydrate(target); init_hydrate(target);
if ((target.actual_end_child === undefined) || ((target.actual_end_child !== null) && (target.actual_end_child.parentElement !== target))) { if ((target.actual_end_child === undefined) || ((target.actual_end_child !== null) && (target.actual_end_child.parentNode !== target))) {
target.actual_end_child = target.firstChild; target.actual_end_child = target.firstChild;
} }
@ -645,6 +646,27 @@ export function query_selector_all(selector: string, parent: HTMLElement = docum
return Array.from(parent.querySelectorAll(selector)) as ChildNodeArray; return Array.from(parent.querySelectorAll(selector)) as ChildNodeArray;
} }
export function head_selector(nodeId: string, head: HTMLElement) {
const result = [];
let started = 0;
for (const node of head.childNodes) {
if (node.nodeType === 8 /* comment node */) {
const comment = node.textContent.trim();
if (comment === `HEAD_${nodeId}_END`) {
started -= 1;
result.push(node);
} else if (comment === `HEAD_${nodeId}_START`) {
started += 1;
result.push(node);
}
} else if (started > 0) {
result.push(node);
}
}
return result;
}
export class HtmlTag { export class HtmlTag {
private is_svg = false; private is_svg = false;
// parent for creating node // parent for creating node

@ -85,18 +85,20 @@ export function escape(value: unknown, is_attr = false) {
let escaped = ''; let escaped = '';
let last = 0; let last = 0;
while (pattern.test(str)) { while (pattern.test(str)) {
const i = pattern.lastIndex - 1; const i = pattern.lastIndex - 1;
const ch = str[i]; const ch = str[i];
escaped += str.substring(last, i) + (ch === '&' ? '&amp;' : (ch === '"' ? '&quot;' : '&lt;')); escaped += str.substring(last, i) + (ch === '&' ? '&amp;' : (ch === '"' ? '&quot;' : '&lt;'));
last = i + 1; last = i + 1;
} }
return escaped + str.substring(last); return escaped + str.substring(last);
} }
export function escape_attribute_value(value) { export function escape_attribute_value(value) {
return typeof value === 'string' ? escape(value, true) : value; // keep booleans, null, and undefined for the sake of `spread`
const should_escape = typeof value === 'string' || (value && typeof value === 'object');
return should_escape ? escape(value, true) : value;
} }
export function escape_object(obj) { export function escape_object(obj) {
@ -192,7 +194,7 @@ export function create_ssr_component(fn) {
export function add_attribute(name, value, boolean) { export function add_attribute(name, value, boolean) {
if (value == null || (boolean && !value)) return ''; if (value == null || (boolean && !value)) return '';
const assignment = (boolean && value === true) ? '' : `="${escape_attribute_value(value.toString())}"`; const assignment = (boolean && value === true) ? '' : `="${escape(value, true)}"`;
return ` ${name}${assignment}`; return ` ${name}${assignment}`;
} }

@ -1,4 +1,4 @@
import { append_empty_stylesheet, get_root_for_style } from './dom'; import { append_empty_stylesheet, detach, get_root_for_style } from './dom';
import { raf } from './environment'; import { raf } from './environment';
interface StyleInformation { interface StyleInformation {
@ -71,10 +71,9 @@ export function clear_rules() {
raf(() => { raf(() => {
if (active) return; if (active) return;
managed_styles.forEach(info => { managed_styles.forEach(info => {
const { stylesheet } = info; const { ownerNode } = info.stylesheet;
let i = stylesheet.cssRules.length; // there is no ownerNode if it runs on jsdom.
while (i--) stylesheet.deleteRule(i); if (ownerNode) detach(ownerNode);
info.rules = {};
}); });
managed_styles.clear(); managed_styles.clear();
}); });

@ -79,6 +79,8 @@ export function transition_out(block: Fragment, local: 0 | 1, detach?: 0 | 1, ca
}); });
block.o(local); block.o(local);
} else if (callback) {
callback();
} }
} }
@ -143,7 +145,7 @@ export function create_in_transition(node: Element & ElementCSSInlineStyle, fn:
return { return {
start() { start() {
if (started) return; if (started) return;
started = true; started = true;
delete_rule(node); delete_rule(node);

@ -12,7 +12,9 @@ export const boolean_attributes = new Set([
'disabled', 'disabled',
'formnovalidate', 'formnovalidate',
'hidden', 'hidden',
'inert',
'ismap', 'ismap',
'itemscope',
'loop', 'loop',
'multiple', 'multiple',
'muted', 'muted',

@ -1,5 +1,18 @@
/** regex of all html void element names */
const void_element_names = /^(?:area|base|br|col|command|embed|hr|img|input|keygen|link|meta|param|source|track|wbr)$/; const void_element_names = /^(?:area|base|br|col|command|embed|hr|img|input|keygen|link|meta|param|source|track|wbr)$/;
/** regex of all html element names. svg and math are omitted because they belong to the svg elements namespace */
const html_element_names = /^(?:a|abbr|address|area|article|aside|audio|b|base|bdi|bdo|blockquote|body|br|button|canvas|caption|cite|code|col|colgroup|data|datalist|dd|del|details|dfn|dialog|div|dl|dt|em|embed|fieldset|figcaption|figure|footer|form|h1|h2|h3|h4|h5|h6|head|header|hr|html|i|iframe|img|input|ins|kbd|label|legend|li|link|main|map|mark|meta|meter|nav|noscript|object|ol|optgroup|option|output|p|param|picture|pre|progress|q|rp|rt|ruby|s|samp|script|section|select|small|source|span|strong|style|sub|summary|sup|table|tbody|td|template|textarea|tfoot|th|thead|time|title|tr|track|u|ul|var|video|wbr)$/;
/** regex of all svg element names */
const svg = /^(?:altGlyph|altGlyphDef|altGlyphItem|animate|animateColor|animateMotion|animateTransform|circle|clipPath|color-profile|cursor|defs|desc|discard|ellipse|feBlend|feColorMatrix|feComponentTransfer|feComposite|feConvolveMatrix|feDiffuseLighting|feDisplacementMap|feDistantLight|feDropShadow|feFlood|feFuncA|feFuncB|feFuncG|feFuncR|feGaussianBlur|feImage|feMerge|feMergeNode|feMorphology|feOffset|fePointLight|feSpecularLighting|feSpotLight|feTile|feTurbulence|filter|font|font-face|font-face-format|font-face-name|font-face-src|font-face-uri|foreignObject|g|glyph|glyphRef|hatch|hatchpath|hkern|image|line|linearGradient|marker|mask|mesh|meshgradient|meshpatch|meshrow|metadata|missing-glyph|mpath|path|pattern|polygon|polyline|radialGradient|rect|set|solidcolor|stop|svg|switch|symbol|text|textPath|tref|tspan|unknown|use|view|vkern)$/;
export function is_void(name: string) { export function is_void(name: string) {
return void_element_names.test(name) || name.toLowerCase() === '!doctype'; return void_element_names.test(name) || name.toLowerCase() === '!doctype';
} }
export function is_html(name: string) {
return html_element_names.test(name);
}
export function is_svg(name: string) {
return svg.test(name);
}

@ -0,0 +1 @@
@layer base, special;@layer special{div.svelte-xyz{color:rebeccapurple}}@layer base{div.svelte-xyz{color:green}}

@ -0,0 +1,17 @@
<div>hello</div>
<style>
@layer base, special;
@layer special {
div {
color: rebeccapurple;
}
}
@layer base {
div {
color: green;
}
}
</style>

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

@ -0,0 +1 @@
div.svelte-xyz.svelte-xyz.svelte-xyz{color:red}h2.svelte-xyz>p.svelte-xyz.svelte-xyz{color:red}h2.svelte-xyz span.svelte-xyz.svelte-xyz{color:red}h2.svelte-xyz>span.svelte-xyz>b.svelte-xyz{color:red}h2.svelte-xyz span b.svelte-xyz.svelte-xyz{color:red}h2.svelte-xyz b.svelte-xyz.svelte-xyz{color:red}

@ -0,0 +1,4 @@
<div class="svelte-xyz"></div>
<h2 class="svelte-xyz">
<div class="svelte-xyz"><b class="svelte-xyz">text</b></div>
</h2>

@ -0,0 +1,32 @@
<script>
export let element = 'div';
</script>
<svelte:element this={element} />
<h2>
<svelte:element this={element}>
<b>text</b>
</svelte:element>
</h2>
<style>
div {
color: red;
}
h2 > p {
color: red;
}
h2 span {
color: red;
}
h2 > span > b {
color: red;
}
h2 span b {
color: red;
}
h2 b {
color: red;
}
</style>

@ -0,0 +1,2 @@
{@html '<meta name="head_nested_html" content="head_nested_html">'}
<meta name="head_nested" content="head_nested">

@ -0,0 +1,5 @@
<svelte:head>
{@html '<meta name="nested_html" content="nested_html">'}
<meta name="nested" content="nested">
</svelte:head>

@ -0,0 +1,12 @@
<!-- HEAD_svelte-17ibcve_START -->
<!-- HTML_TAG_START --><meta name="main_html" content="main_html"><!-- HTML_TAG_END -->
<meta name="main" content="main">
<!-- HTML_TAG_START --><meta name="head_nested_html" content="head_nested_html"><!-- HTML_TAG_END -->
<meta name="head_nested" content="head_nested">
<!-- HEAD_svelte-17ibcve_END -->
<!-- HEAD_svelte-1gqzvnn_START -->
<!-- HTML_TAG_START --><meta name="nested_html" content="nested_html"><!-- HTML_TAG_END -->
<meta name="nested" content="nested">
<!-- HEAD_svelte-1gqzvnn_END -->

@ -0,0 +1,11 @@
<!-- HEAD_svelte-17ibcve_START -->
<!-- HTML_TAG_START --><meta name="main_html" content="main_html"><!-- HTML_TAG_END -->
<meta name="main" content="main">
<!-- HTML_TAG_START --><meta name="head_nested_html" content="head_nested_html"><!-- HTML_TAG_END -->
<meta name="head_nested" content="head_nested">
<!-- HEAD_svelte-17ibcve_END -->
<!-- HEAD_svelte-1gqzvnn_START -->
<!-- HTML_TAG_START --><meta name="nested_html" content="nested_html"><!-- HTML_TAG_END -->
<meta name="nested" content="nested">
<!-- HEAD_svelte-1gqzvnn_END -->

@ -0,0 +1,12 @@
<script>
import HeadNested from './HeadNested.svelte';
import Nested from './Nested.svelte';
</script>
<svelte:head>
{@html '<meta name="main_html" content="main_html">'}
<meta name="main" content="main">
<HeadNested />
</svelte:head>
<Nested/>

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

@ -1,4 +1,6 @@
<title>Some Title</title> <title>Some Title</title>
<link rel="canonical" href="/" data-svelte="svelte-1s8aodm"> <!-- HEAD_svelte-1s8aodm_START -->
<meta name="description" content="some description" data-svelte="svelte-1s8aodm"> <link rel="canonical" href="/">
<meta name="keywords" content="some keywords" data-svelte="svelte-1s8aodm"> <meta name="description" content="some description">
<meta name="keywords" content="some keywords">
<!-- HEAD_svelte-1s8aodm_END -->

@ -0,0 +1,111 @@
/* generated by Svelte vX.Y.Z */
import {
SvelteComponent,
append,
assign,
detach,
empty,
get_spread_update,
init,
insert,
noop,
safe_not_equal,
set_svg_attributes,
svg_element
} from "svelte/internal";
function create_dynamic_element_1(ctx) {
return { c: noop, m: noop, p: noop, d: noop };
}
// (1:0) <svelte:element this="svg" xmlns="http://www.w3.org/2000/svg">
function create_dynamic_element(ctx) {
let svelte_element1;
let svelte_element0;
let svelte_element0_levels = [{ xmlns: "http://www.w3.org/2000/svg" }];
let svelte_element0_data = {};
for (let i = 0; i < svelte_element0_levels.length; i += 1) {
svelte_element0_data = assign(svelte_element0_data, svelte_element0_levels[i]);
}
let svelte_element1_levels = [{ xmlns: "http://www.w3.org/2000/svg" }];
let svelte_element1_data = {};
for (let i = 0; i < svelte_element1_levels.length; i += 1) {
svelte_element1_data = assign(svelte_element1_data, svelte_element1_levels[i]);
}
return {
c() {
svelte_element1 = svg_element("svg");
svelte_element0 = svg_element("path");
set_svg_attributes(svelte_element0, svelte_element0_data);
set_svg_attributes(svelte_element1, svelte_element1_data);
},
m(target, anchor) {
insert(target, svelte_element1, anchor);
append(svelte_element1, svelte_element0);
},
p(ctx, dirty) {
set_svg_attributes(svelte_element0, svelte_element0_data = get_spread_update(svelte_element0_levels, [{ xmlns: "http://www.w3.org/2000/svg" }]));
set_svg_attributes(svelte_element1, svelte_element1_data = get_spread_update(svelte_element1_levels, [{ xmlns: "http://www.w3.org/2000/svg" }]));
},
d(detaching) {
if (detaching) detach(svelte_element1);
}
};
}
function create_fragment(ctx) {
let previous_tag = "svg";
let svelte_element1_anchor;
let svelte_element1 = "svg" && create_dynamic_element(ctx);
return {
c() {
if (svelte_element1) svelte_element1.c();
svelte_element1_anchor = empty();
},
m(target, anchor) {
if (svelte_element1) svelte_element1.m(target, anchor);
insert(target, svelte_element1_anchor, anchor);
},
p(ctx, [dirty]) {
if ("svg") {
if (!previous_tag) {
svelte_element1 = create_dynamic_element(ctx);
svelte_element1.c();
svelte_element1.m(svelte_element1_anchor.parentNode, svelte_element1_anchor);
} else if (safe_not_equal(previous_tag, "svg")) {
svelte_element1.d(1);
svelte_element1 = create_dynamic_element(ctx);
svelte_element1.c();
svelte_element1.m(svelte_element1_anchor.parentNode, svelte_element1_anchor);
} else {
svelte_element1.p(ctx, dirty);
}
} else if (previous_tag) {
svelte_element1.d(1);
svelte_element1 = null;
}
previous_tag = "svg";
},
i: noop,
o: noop,
d(detaching) {
if (detaching) detach(svelte_element1_anchor);
if (svelte_element1) svelte_element1.d(detaching);
}
};
}
class Component extends SvelteComponent {
constructor(options) {
super();
init(this, options, null, create_fragment, safe_not_equal, {});
}
}
export default Component;

@ -0,0 +1,3 @@
<svelte:element this="svg" xmlns="http://www.w3.org/2000/svg">
<svelte:element this="path" xmlns="http://www.w3.org/2000/svg"></svelte:element>
</svelte:element>

@ -117,8 +117,12 @@ describe('runtime (puppeteer)', function() {
load(id) { load(id) {
if (id === 'main') { if (id === 'main') {
return ` return `
import SvelteComponent from ${JSON.stringify(path.join(__dirname, 'samples', dir, 'main.svelte'))}; import SvelteComponent from ${JSON.stringify(
import config from ${JSON.stringify(path.join(__dirname, 'samples', dir, '_config.js'))}; path.join(__dirname, 'samples', dir, 'main.svelte')
)};
import config from ${JSON.stringify(
path.join(__dirname, 'samples', dir, '_config.js')
)};
import * as assert from 'assert'; import * as assert from 'assert';
export default async function (target) { export default async function (target) {
@ -140,6 +144,14 @@ describe('runtime (puppeteer)', function() {
const component = new SvelteComponent(options); const component = new SvelteComponent(options);
const waitUntil = async (fn, ms = 500) => {
const start = new Date().getTime();
do {
if (fn()) return;
await new Promise(resolve => window.setTimeout(resolve, 1));
} while (new Date().getTime() <= start + ms);
};
if (config.html) { if (config.html) {
assert.htmlEqual(target.innerHTML, config.html); assert.htmlEqual(target.innerHTML, config.html);
} }
@ -150,6 +162,7 @@ describe('runtime (puppeteer)', function() {
component, component,
target, target,
window, window,
waitUntil,
}); });
component.$destroy(); component.$destroy();

@ -0,0 +1,17 @@
export default {
skip_if_ssr: true,
skip_if_hydrate: true,
skip_if_hydrate_from_ssr: true,
test: async ({ component, assert, window, waitUntil }) => {
assert.htmlEqual(window.document.head.innerHTML, '');
component.visible = true;
assert.htmlEqual(window.document.head.innerHTML, '<style></style>');
await waitUntil(() => window.document.head.innerHTML === '');
assert.htmlEqual(window.document.head.innerHTML, '');
component.visible = false;
assert.htmlEqual(window.document.head.innerHTML, '<style></style>');
await waitUntil(() => window.document.head.innerHTML === '');
assert.htmlEqual(window.document.head.innerHTML, '');
}
};

@ -0,0 +1,16 @@
<script>
export let visible;
function foo() {
return {
duration: 10,
css: t => {
return `opacity: ${t}`;
}
};
}
</script>
{#if visible}
<div transition:foo></div>
{/if}

@ -0,0 +1,17 @@
<script>
export let id;
</script>
<div {id}>
<p>Slider</p>
<span>Track</span>
</div>
<style>
p {
color: var(--rail-color);
}
span {
color: var(--track-color);
}
</style>

@ -0,0 +1,41 @@
export default {
props: {
railColor1: 'black',
trackColor1: 'red',
railColor2: 'green',
trackColor2: 'blue'
},
html: `
<div style="display: contents; --rail-color:black; --track-color:red;">
<div id="slider-1">
<p class="svelte-17ay6rc">Slider</p>
<span class="svelte-17ay6rc">Track</span>
</div>
</div>
<div style="display: contents; --rail-color:green; --track-color:blue;">
<div id="slider-2">
<p class="svelte-17ay6rc">Slider</p>
<span class="svelte-17ay6rc">Track</span>
</div>
</div>
`,
test({ component, assert, target }) {
component.railColor1 = 'yellow';
component.trackColor2 = 'orange';
assert.htmlEqual(target.innerHTML, `
<div style="display: contents; --rail-color:yellow; --track-color:red;">
<div id="slider-1">
<p class="svelte-17ay6rc">Slider</p>
<span class="svelte-17ay6rc">Track</span>
</div>
</div>
<div style="display: contents; --rail-color:green; --track-color:orange;">
<div id="slider-2">
<p class="svelte-17ay6rc">Slider</p>
<span class="svelte-17ay6rc">Track</span>
</div>
</div>
`);
}
};

@ -0,0 +1,25 @@
<script>
import Slider from './Slider.svelte';
export let railColor1;
export let railColor2;
export let trackColor1;
export let trackColor2;
function identity(color) {
return color;
}
</script>
<svelte:component
this={Slider}
id="slider-1"
--rail-color={railColor1}
--track-color={trackColor1}
/>
<svelte:component
this={Slider}
id="slider-2"
--rail-color={railColor2}
--track-color={identity(trackColor2)}
/>

@ -0,0 +1,17 @@
<script>
export let id;
</script>
<div {id}>
<p>Slider1</p>
<span>Track</span>
</div>
<style>
p {
color: var(--rail-color);
}
span {
color: var(--track-color);
}
</style>

@ -0,0 +1,17 @@
<script>
export let id;
</script>
<div {id}>
<p>Slider2</p>
<span>Track</span>
</div>
<style>
p {
color: var(--rail-color);
}
span {
color: var(--track-color);
}
</style>

@ -0,0 +1,57 @@
export default {
props: {
componentName: 'Slider1'
},
html: `
<div style="display: contents; --rail-color:rgb(0, 0, 0); --track-color:rgb(255, 0, 0);">
<div id="component1">
<p class="svelte-17ay6rc">Slider1</p>
<span class="svelte-17ay6rc">Track</span>
</div>
</div>
<div style="display: contents; --rail-color:rgb(0, 255, 0); --track-color:rgb(0, 0, 255);">
<div id="component2">
<p class="svelte-17ay6rc">Slider1</p>
<span class="svelte-17ay6rc">Track</span>
</div>
</div>
`,
test({ target, window, assert, component }) {
function assert_slider_1() {
const railColor1 = target.querySelector('#component1 p');
const trackColor1 = target.querySelector('#component1 span');
const railColor2 = target.querySelector('#component2 p');
const trackColor2 = target.querySelector('#component2 span');
assert.equal(window.getComputedStyle(railColor1).color, 'rgb(0, 0, 0)');
assert.equal(window.getComputedStyle(trackColor1).color, 'rgb(255, 0, 0)');
assert.equal(window.getComputedStyle(railColor2).color, 'rgb(0, 255, 0)');
assert.equal(window.getComputedStyle(trackColor2).color, 'rgb(0, 0, 255)');
assert.equal(railColor1.textContent, 'Slider1');
assert.equal(railColor2.textContent, 'Slider1');
}
function assert_slider_2() {
const railColor1 = target.querySelector('#component1 p');
const trackColor1 = target.querySelector('#component1 span');
const railColor2 = target.querySelector('#component2 p');
const trackColor2 = target.querySelector('#component2 span');
assert.equal(window.getComputedStyle(railColor1).color, 'rgb(0, 0, 0)');
assert.equal(window.getComputedStyle(trackColor1).color, 'rgb(255, 0, 0)');
assert.equal(window.getComputedStyle(railColor2).color, 'rgb(0, 255, 0)');
assert.equal(window.getComputedStyle(trackColor2).color, 'rgb(0, 0, 255)');
assert.equal(railColor1.textContent, 'Slider2');
assert.equal(railColor2.textContent, 'Slider2');
}
assert_slider_1();
component.componentName = 'Slider2';
assert_slider_2();
component.componentName = undefined;
assert.equal(window.document.querySelector('div'), null);
component.componentName = 'Slider1';
assert_slider_1();
}
};

@ -0,0 +1,20 @@
<script>
import Slider1 from './Slider1.svelte';
import Slider2 from './Slider2.svelte';
export let componentName = 'Slider1';
$: slider = componentName === 'Slider1' ? Slider1 : componentName === 'Slider2' ? Slider2 : undefined;
</script>
<svelte:component
this={slider}
id="component1"
--rail-color="rgb(0, 0, 0)"
--track-color="rgb(255, 0, 0)"
/>
<svelte:component
this={slider}
id="component2"
--rail-color="rgb(0, 255, 0)"
--track-color="rgb(0, 0, 255)"
/>

@ -0,0 +1,17 @@
<script>
export let id;
</script>
<div {id}>
<p>Slider1</p>
<span>Track</span>
</div>
<style>
p {
color: var(--rail-color);
}
span {
color: var(--track-color);
}
</style>

@ -0,0 +1,17 @@
<script>
export let id;
</script>
<div {id}>
<p>Slider2</p>
<span>Track</span>
</div>
<style>
p {
color: var(--rail-color);
}
span {
color: var(--track-color);
}
</style>

@ -0,0 +1,59 @@
export default {
props: {
componentName: 'Slider1'
},
html: `
<section>
<div style="display: contents; --rail-color:rgb(0, 0, 0); --track-color:rgb(255, 0, 0);">
<div id="component1">
<p class="svelte-17ay6rc">Slider1</p>
<span class="svelte-17ay6rc">Track</span>
</div>
</div>
<div style="display: contents; --rail-color:rgb(0, 255, 0); --track-color:rgb(0, 0, 255);">
<div id="component2">
<p class="svelte-17ay6rc">Slider1</p>
<span class="svelte-17ay6rc">Track</span>
</div>
</div>
</section>
`,
test({ target, window, assert, component }) {
function assert_slider_1() {
const railColor1 = target.querySelector('#component1 p');
const trackColor1 = target.querySelector('#component1 span');
const railColor2 = target.querySelector('#component2 p');
const trackColor2 = target.querySelector('#component2 span');
assert.equal(window.getComputedStyle(railColor1).color, 'rgb(0, 0, 0)');
assert.equal(window.getComputedStyle(trackColor1).color, 'rgb(255, 0, 0)');
assert.equal(window.getComputedStyle(railColor2).color, 'rgb(0, 255, 0)');
assert.equal(window.getComputedStyle(trackColor2).color, 'rgb(0, 0, 255)');
assert.equal(railColor1.textContent, 'Slider1');
assert.equal(railColor2.textContent, 'Slider1');
}
function assert_slider_2() {
const railColor1 = target.querySelector('#component1 p');
const trackColor1 = target.querySelector('#component1 span');
const railColor2 = target.querySelector('#component2 p');
const trackColor2 = target.querySelector('#component2 span');
assert.equal(window.getComputedStyle(railColor1).color, 'rgb(0, 0, 0)');
assert.equal(window.getComputedStyle(trackColor1).color, 'rgb(255, 0, 0)');
assert.equal(window.getComputedStyle(railColor2).color, 'rgb(0, 255, 0)');
assert.equal(window.getComputedStyle(trackColor2).color, 'rgb(0, 0, 255)');
assert.equal(railColor1.textContent, 'Slider2');
assert.equal(railColor2.textContent, 'Slider2');
}
assert_slider_1();
component.componentName = 'Slider2';
assert_slider_2();
component.componentName = undefined;
assert.equal(window.document.querySelector('div'), null);
component.componentName = 'Slider1';
assert_slider_1();
}
};

@ -0,0 +1,22 @@
<script>
import Slider1 from './Slider1.svelte';
import Slider2 from './Slider2.svelte';
export let componentName = 'Slider1';
$: slider = componentName === 'Slider1' ? Slider1 : componentName === 'Slider2' ? Slider2 : undefined;
</script>
<section>
<svelte:component
this={slider}
id="component1"
--rail-color="rgb(0, 0, 0)"
--track-color="rgb(255, 0, 0)"
/>
<svelte:component
this={slider}
id="component2"
--rail-color="rgb(0, 255, 0)"
--track-color="rgb(0, 0, 255)"
/>
</section>

@ -0,0 +1,29 @@
<script>
export let id;
export let count = 0;
export let railColor1;
export let trackColor1;
</script>
<div {id}>
<p>Slider</p>
<span>Track</span>
</div>
{#if count === 0}
<svelte:self
id="nest-{id}"
count="{count + 1}"
--rail-color={railColor1}
--track-color={trackColor1}
/>
{/if}
<style>
p {
color: var(--rail-color);
}
span {
color: var(--track-color);
}
</style>

@ -0,0 +1,71 @@
export default {
props: {
railColor1: 'black',
trackColor1: 'red',
railColor2: 'green',
trackColor2: 'blue',
nestRailColor1: 'white',
nestTrackColor1: 'gray',
nestRailColor2: 'aqua',
nestTrackColor2: 'pink'
},
html: `
<div style="display: contents; --rail-color:black; --track-color:red;">
<div id="slider-1">
<p class="svelte-17ay6rc">Slider</p>
<span class="svelte-17ay6rc">Track</span>
</div>
<div style="display: contents; --rail-color:white; --track-color:gray;">
<div id="nest-slider-1">
<p class="svelte-17ay6rc">Slider</p>
<span class="svelte-17ay6rc">Track</span>
</div>
</div>
</div>
<div style="display: contents; --rail-color:green; --track-color:blue;">
<div id="slider-2">
<p class="svelte-17ay6rc">Slider</p>
<span class="svelte-17ay6rc">Track</span>
</div>
<div style="display: contents; --rail-color:aqua; --track-color:pink;">
<div id="nest-slider-2">
<p class="svelte-17ay6rc">Slider</p>
<span class="svelte-17ay6rc">Track</span>
</div>
</div>
</div>
`,
test({ component, assert, target }) {
component.railColor1 = 'yellow';
component.trackColor2 = 'orange';
component.nestRailColor1 = 'lime';
component.nestTrackColor2 = 'gold';
assert.htmlEqual(target.innerHTML, `
<div style="display: contents; --rail-color:yellow; --track-color:red;">
<div id="slider-1">
<p class="svelte-17ay6rc">Slider</p>
<span class="svelte-17ay6rc">Track</span>
</div>
<div style="display: contents; --rail-color:lime; --track-color:gray;">
<div id="nest-slider-1">
<p class="svelte-17ay6rc">Slider</p>
<span class="svelte-17ay6rc">Track</span>
</div>
</div>
</div>
<div style="display: contents; --rail-color:green; --track-color:orange;">
<div id="slider-2">
<p class="svelte-17ay6rc">Slider</p>
<span class="svelte-17ay6rc">Track</span>
</div>
<div style="display: contents; --rail-color:aqua; --track-color:gold;">
<div id="nest-slider-2">
<p class="svelte-17ay6rc">Slider</p>
<span class="svelte-17ay6rc">Track</span>
</div>
</div>
</div>
`);
}
};

@ -0,0 +1,32 @@
<script>
import Slider from './Slider.svelte';
export let railColor1;
export let railColor2;
export let trackColor1;
export let trackColor2;
export let nestRailColor1;
export let nestRailColor2;
export let nestTrackColor1;
export let nestTrackColor2;
function identity(color) {
return color;
}
</script>
<Slider
id="slider-1"
--rail-color={railColor1}
--track-color={trackColor1}
railColor1={nestRailColor1}
trackColor1={nestTrackColor1}
/>
<svelte:component
this={Slider}
id="slider-2"
--rail-color={railColor2}
--track-color={identity(trackColor2)}
railColor1={nestRailColor2}
trackColor1={nestTrackColor2}
/>

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

Loading…
Cancel
Save