diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ff0ec4f633..4e04386fcc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,6 +3,7 @@ on: [push, pull_request] jobs: Tests: runs-on: ${{ matrix.os }} + timeout-minutes: 10 strategy: matrix: node-version: [8, 10, 12, 14] @@ -18,12 +19,14 @@ jobs: CI: true Lint: runs-on: ubuntu-latest + timeout-minutes: 2 steps: - uses: actions/checkout@v1 - uses: actions/setup-node@v1 - run: 'npm i && npm run lint' Unit: runs-on: ${{ matrix.os }} + timeout-minutes: 5 strategy: matrix: os: [ubuntu-latest, windows-latest, macOS-latest] diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f15d40206..61b4c36842 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,16 +2,26 @@ ## Unreleased +* Fix reactivity when passing `$$props` to a `` ([#3364](https://github.com/sveltejs/svelte/issues/3364)) +* Fix unneeded invalidation of `$$props` and `$$restProps` ([#4993](https://github.com/sveltejs/svelte/issues/4993), [#5118](https://github.com/sveltejs/svelte/issues/5118)) + +## 3.24.0 + * Support nullish coalescing (`??`) and optional chaining (`?.`) operators ([#1972](https://github.com/sveltejs/svelte/issues/1972)) * Support `import.meta` ([#4379](https://github.com/sveltejs/svelte/issues/4379)) -* Fix placement of `{@html}` when used at the root of a slot or the root of a component ([#5012](https://github.com/sveltejs/svelte/issues/5012)) +* Fix only setting `` values when they're changed when there are spread attributes ([#4418](https://github.com/sveltejs/svelte/issues/4418)) +* Fix placement of `{@html}` when used at the root of a slot, at the root of a component, or in `` ([#5012](https://github.com/sveltejs/svelte/issues/5012), [#5071](https://github.com/sveltejs/svelte/pull/5071)) +* Fix certain handling of two-way bound `contenteditable` elements ([#5018](https://github.com/sveltejs/svelte/issues/5018)) * Fix handling of `import`ed value that is used as a store and is also mutated ([#5019](https://github.com/sveltejs/svelte/issues/5019)) * Do not display `a11y-missing-content` warning on elements with `contenteditable` bindings ([#5020](https://github.com/sveltejs/svelte/issues/5020)) * Fix handling of `this` in inline function expressions in the template ([#5033](https://github.com/sveltejs/svelte/issues/5033)) * Fix collapsing HTML with static content ([#5040](https://github.com/sveltejs/svelte/issues/5040)) +* Prevent use of `$store` at compile time when top-level `store` has been shadowed ([#5048](https://github.com/sveltejs/svelte/issues/5048)) * Update ` {/each} diff --git a/site/content/faq/400-how-can-i-get-syntax-highlighting.md b/site/content/faq/400-how-can-i-get-syntax-highlighting.md index 90f10b254f..96a80e3c32 100644 --- a/site/content/faq/400-how-can-i-get-syntax-highlighting.md +++ b/site/content/faq/400-how-can-i-get-syntax-highlighting.md @@ -1,5 +1,5 @@ --- -question: How can I get VSCode to syntax-highlight my .svelte files? +question: How can I get VS Code to syntax-highlight my .svelte files? --- -There is an [official VSCode extension for Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode), however it is still in the **beta** testing stage, and not all issues have been ironed out. \ No newline at end of file +There is an [official VS Code extension for Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). diff --git a/site/content/faq/450-how-do-i-document-my-components.md b/site/content/faq/450-how-do-i-document-my-components.md new file mode 100644 index 0000000000..78177abd54 --- /dev/null +++ b/site/content/faq/450-how-do-i-document-my-components.md @@ -0,0 +1,32 @@ +--- +question: How do I document my components? +--- + +In editors which use the Svelte Language Server you can document Components, functions and exports using specially formatted comments. + +````svelte + + + +
+

+ Hello, {name} +

+
+```` + +Note: The `@component` is necessary in the HTML comment which describes your component. diff --git a/site/content/faq/500-what-about-typescript-support.md b/site/content/faq/500-what-about-typescript-support.md index 7cd0ccbe54..adfd63764e 100644 --- a/site/content/faq/500-what-about-typescript-support.md +++ b/site/content/faq/500-what-about-typescript-support.md @@ -1,10 +1,11 @@ --- -question: What about Typescript support? +question: What about TypeScript support? --- -You need to install a preprocessor such as [svelte-preprocess](https://github.com/sveltejs/svelte-preprocess). Work is ongoing to improve [IDE support](https://github.com/sveltejs/language-tools/issues/83). You can also run type checking from the command line with [svelte-check](https://www.npmjs.com/package/svelte-check). +You need to install a preprocessor such as [svelte-preprocess](https://github.com/sveltejs/svelte-preprocess). You can run type checking from the command line with [svelte-check](https://www.npmjs.com/package/svelte-check). + +To declare the type of a reactive variable in a Svelte template, you should use the following syntax: -To declare the type of a reactive variable in a Svelte template, you can use the following syntax: ``` let x: number; $: x = count + 1; diff --git a/site/package-lock.json b/site/package-lock.json index a34f0d528e..1132b9f324 100644 --- a/site/package-lock.json +++ b/site/package-lock.json @@ -1281,9 +1281,9 @@ } }, "@sveltejs/site-kit": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@sveltejs/site-kit/-/site-kit-1.1.5.tgz", - "integrity": "sha512-Rs2quQ/H00DAN/ZTFa+unLefL335UW3Yo4I2rTocW5JwW73Kvi5++d7BcY8LsjhMCbG1PkwQmJE2RVrIIxQcOw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@sveltejs/site-kit/-/site-kit-1.2.0.tgz", + "integrity": "sha512-C7puq+1so3fKPPZAnQJQlKfyCG6FsnSSFSS2LRIhWD8VK2FL5j8Eq7DIKSxUvWbGw1AsxnzO3dIHJWPB7fwjKg==", "dev": true, "requires": { "@sindresorhus/slugify": "^0.9.1", @@ -1291,9 +1291,9 @@ } }, "@sveltejs/svelte-repl": { - "version": "0.1.20", - "resolved": "https://registry.npmjs.org/@sveltejs/svelte-repl/-/svelte-repl-0.1.20.tgz", - "integrity": "sha512-PPy1Sxn+yLSo+H/KPvl8jRJizv4VgkDLL2u3SLfSgOgQgzUVBEjiOW9HUlgOwW61uCq2lSsS7A8NdILxEkrFnA==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@sveltejs/svelte-repl/-/svelte-repl-0.2.0.tgz", + "integrity": "sha512-2vLQnOVrsmn2d2K4a6urGm8OulGGSPhZCGNySSb1H8nOPsgKrdcTt5qoaxNYXgcyVp55Yow2SvXYXsyJKd4KEQ==", "dev": true, "requires": { "codemirror": "^5.49.2", @@ -2404,9 +2404,9 @@ } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", "dev": true }, "lodash.deburr": { diff --git a/site/package.json b/site/package.json index 06081570b8..30075c9f37 100644 --- a/site/package.json +++ b/site/package.json @@ -36,8 +36,8 @@ "@babel/preset-env": "^7.6.0", "@babel/runtime": "^7.6.0", "@sindresorhus/slugify": "^0.9.1", - "@sveltejs/site-kit": "^1.1.5", - "@sveltejs/svelte-repl": "^0.1.20", + "@sveltejs/site-kit": "^1.2.0", + "@sveltejs/svelte-repl": "^0.2.0", "degit": "^2.1.4", "dotenv": "^8.1.0", "esm": "^3.2.25", diff --git a/site/src/routes/docs/_sections.js b/site/src/routes/docs/_sections.js index bb081a050b..3657ba85ac 100644 --- a/site/src/routes/docs/_sections.js +++ b/site/src/routes/docs/_sections.js @@ -85,7 +85,7 @@ export default function() { renderer.heading = (text, level, rawtext) => { let slug; - const match = /(.+)<\/a>/.exec(text); + const match = /]*>(.+)<\/a>/.exec(text); if (match) { slug = match[1]; text = match[2]; diff --git a/site/src/routes/repl/[id]/_components/AppControls/index.svelte b/site/src/routes/repl/[id]/_components/AppControls/index.svelte index 10639e91c0..1d4e6b3f03 100644 --- a/site/src/routes/repl/[id]/_components/AppControls/index.svelte +++ b/site/src/routes/repl/[id]/_components/AppControls/index.svelte @@ -227,6 +227,7 @@ export default app;` }); padding: .6rem var(--side-nav); background-color: var(--second); color: white; + white-space: nowrap; } .icon { diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 5f06de8e21..88fe197993 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -836,7 +836,7 @@ export default class Component { }); } - warn_on_undefined_store_value_references(node, parent, scope) { + warn_on_undefined_store_value_references(node, parent, scope: Scope) { if ( node.type === 'LabeledStatement' && node.label.name === '$' && @@ -852,8 +852,17 @@ export default class Component { const object = get_object(node); const { name } = object; - if (name[0] === '$' && !scope.has(name)) { - this.warn_if_undefined(name, object, null); + if (name[0] === '$') { + if (!scope.has(name)) { + this.warn_if_undefined(name, object, null); + } + + if (name[1] !== '$' && scope.has(name.slice(1)) && scope.find_owner(name.slice(1)) !== this.instance_scope) { + this.error(node, { + code: `contextual-store`, + message: `Stores must be declared at the top level of the component (this may change in a future version of Svelte)` + }); + } } } } diff --git a/src/compiler/compile/nodes/shared/Expression.ts b/src/compiler/compile/nodes/shared/Expression.ts index d4a219418b..8bfc2bffce 100644 --- a/src/compiler/compile/nodes/shared/Expression.ts +++ b/src/compiler/compile/nodes/shared/Expression.ts @@ -78,11 +78,14 @@ export default class Expression { if (scope.has(name)) return; - if (name[0] === '$' && template_scope.names.has(name.slice(1))) { - component.error(node, { - code: `contextual-store`, - message: `Stores must be declared at the top level of the component (this may change in a future version of Svelte)` - }); + if (name[0] === '$') { + const store_name = name.slice(1); + if (template_scope.names.has(store_name) || scope.has(store_name)) { + component.error(node, { + code: `contextual-store`, + message: `Stores must be declared at the top level of the component (this may change in a future version of Svelte)` + }); + } } if (template_scope.is_let(name)) { diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 3b5001d483..f6ffd8f2a6 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -86,6 +86,7 @@ export default function dom( const set = (uses_props || uses_rest || writable_props.length > 0 || component.slots.size > 0) ? x` ${$$props} => { + ${(uses_props || uses_rest) && b`if (@is_empty(${$$props})) return;`} ${uses_props && renderer.invalidate('$$props', x`$$props = @assign(@assign({}, $$props), @exclude_internal_props($$new_props))`)} ${uses_rest && !uses_props && x`$$props = @assign(@assign({}, $$props), @exclude_internal_props($$new_props))`} ${uses_rest && renderer.invalidate('$$restProps', x`$$restProps = ${compute_rest}`)} diff --git a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts index 86b67ca47e..ec281648b8 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts @@ -7,8 +7,9 @@ import { b, x } from 'code-red'; import Expression from '../../../nodes/shared/Expression'; import Text from '../../../nodes/Text'; import handle_select_value_binding from './handle_select_value_binding'; +import { Identifier, Node } from 'estree'; -export default class AttributeWrapper { +export class BaseAttributeWrapper { node: Attribute; parent: ElementWrapper; @@ -21,7 +22,29 @@ export default class AttributeWrapper { parent.not_static_content(); block.add_dependencies(node.dependencies); + } + } + + render(_block: Block) {} +} +export default class AttributeWrapper extends BaseAttributeWrapper { + node: Attribute; + parent: ElementWrapper; + metadata: any; + name: string; + property_name: string; + is_indirectly_bound_value: boolean; + is_src: boolean; + is_select_value_attribute: boolean; + is_input_value: boolean; + should_cache: boolean; + last: Identifier; + + constructor(parent: ElementWrapper, block: Block, node: Attribute) { + super(parent, block, node); + + if (node.dependencies.size > 0) { // special case —