From 38a3ae321ffceccd7da838e09f092af86d1b6dc4 Mon Sep 17 00:00:00 2001 From: Andrey Sitnik Date: Tue, 24 Dec 2024 13:16:03 +0100 Subject: [PATCH 01/63] fix: Allow to disable animation prefix (#14822) * fix: Allow to disable animation prefix * Apply suggestions from code review --------- Co-authored-by: Paolo Ricciuti --- .changeset/twenty-shoes-peel.md | 5 +++++ .../src/compiler/phases/2-analyze/css/css-analyze.js | 10 +++++++++- .../svelte/tests/css/samples/global-block/expected.css | 4 ++++ .../svelte/tests/css/samples/global-block/input.svelte | 4 ++++ 4 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 .changeset/twenty-shoes-peel.md diff --git a/.changeset/twenty-shoes-peel.md b/.changeset/twenty-shoes-peel.md new file mode 100644 index 0000000000..e0a8e0701d --- /dev/null +++ b/.changeset/twenty-shoes-peel.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: don't include keyframes in global scope in the keyframes to rename diff --git a/packages/svelte/src/compiler/phases/2-analyze/css/css-analyze.js b/packages/svelte/src/compiler/phases/2-analyze/css/css-analyze.js index b8c88a1023..ed22838582 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/css/css-analyze.js +++ b/packages/svelte/src/compiler/phases/2-analyze/css/css-analyze.js @@ -28,11 +28,19 @@ function is_global_block_selector(simple_selector) { ); } +/** + * + * @param {Array} path + */ +function is_in_global_block(path) { + return path.some((node) => node.type === 'Rule' && node.metadata.is_global_block); +} + /** @type {CssVisitors} */ const css_visitors = { Atrule(node, context) { if (is_keyframes_node(node)) { - if (!node.prelude.startsWith('-global-')) { + if (!node.prelude.startsWith('-global-') && !is_in_global_block(context.path)) { context.state.keyframes.push(node.prelude); } } diff --git a/packages/svelte/tests/css/samples/global-block/expected.css b/packages/svelte/tests/css/samples/global-block/expected.css index 8a7c493d7c..438749224b 100644 --- a/packages/svelte/tests/css/samples/global-block/expected.css +++ b/packages/svelte/tests/css/samples/global-block/expected.css @@ -74,6 +74,10 @@ animation: svelte-xyz-test 1s; } + .y{ + animation: test-in 1s; + } + @keyframes test-in{ to{ opacity: 1; diff --git a/packages/svelte/tests/css/samples/global-block/input.svelte b/packages/svelte/tests/css/samples/global-block/input.svelte index dc1a754010..a1833636a1 100644 --- a/packages/svelte/tests/css/samples/global-block/input.svelte +++ b/packages/svelte/tests/css/samples/global-block/input.svelte @@ -76,6 +76,10 @@ animation: test 1s; } + .y{ + animation: test-in 1s; + } + @keyframes test-in{ to{ opacity: 1; From 015210a1a8a230383303a2c3aa044916a49d2681 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Tue, 24 Dec 2024 14:58:49 +0100 Subject: [PATCH 02/63] feat: allow objects/arrays for class attribute (#14714) * WIP * missed * fix * fix * rename, smooth over incompatibilities * spread support + test * docs * types * implement CSS pruning for array/object expressions * beefier static analysis * lint * rename doc * move class after all directive docs * tweak docs - clarify top-level falsy values, stagger examples, demonstrate composition, discourage class: more strongly * changeset * fix * Update documentation/docs/03-template-syntax/18-class.md Co-authored-by: Conduitry * Apply suggestions from code review --------- Co-authored-by: Rich Harris Co-authored-by: Conduitry --- .changeset/thin-panthers-sing.md | 5 ++ .../docs/03-template-syntax/16-class.md | 23 ----- .../docs/03-template-syntax/18-class.md | 90 +++++++++++++++++++ packages/svelte/elements.d.ts | 4 +- packages/svelte/package.json | 1 + .../phases/2-analyze/css/css-prune.js | 4 +- .../compiler/phases/2-analyze/css/utils.js | 75 ++++++++++++++-- .../src/compiler/phases/2-analyze/index.js | 2 + .../phases/2-analyze/visitors/Attribute.js | 13 +++ .../client/visitors/RegularElement.js | 8 +- .../server/visitors/shared/element.js | 31 ++++++- packages/svelte/src/compiler/phases/nodes.js | 3 +- .../svelte/src/compiler/types/template.d.ts | 2 + .../client/dom/elements/attributes.js | 5 ++ .../src/internal/client/dom/elements/class.js | 22 +++-- packages/svelte/src/internal/client/index.js | 2 +- packages/svelte/src/internal/server/index.js | 8 +- .../svelte/src/internal/shared/attributes.js | 14 +++ .../css/samples/clsx-can-prune/_config.js | 20 +++++ .../css/samples/clsx-can-prune/expected.css | 12 +++ .../css/samples/clsx-can-prune/input.svelte | 25 ++++++ .../samples/clsx-cannot-prune-1/expected.css | 2 + .../samples/clsx-cannot-prune-1/input.svelte | 5 ++ .../samples/clsx-cannot-prune-2/expected.css | 2 + .../samples/clsx-cannot-prune-2/input.svelte | 5 ++ .../samples/clsx-cannot-prune-3/expected.css | 2 + .../samples/clsx-cannot-prune-3/input.svelte | 5 ++ .../_config.js | 2 +- .../_config.js | 2 +- .../_config.js | 2 +- .../_config.js | 2 +- .../runtime-runes/samples/clsx/_config.js | 43 +++++++++ .../runtime-runes/samples/clsx/child.svelte | 5 ++ .../runtime-runes/samples/clsx/main.svelte | 33 +++++++ pnpm-lock.yaml | 9 ++ 35 files changed, 433 insertions(+), 55 deletions(-) create mode 100644 .changeset/thin-panthers-sing.md delete mode 100644 documentation/docs/03-template-syntax/16-class.md create mode 100644 documentation/docs/03-template-syntax/18-class.md create mode 100644 packages/svelte/tests/css/samples/clsx-can-prune/_config.js create mode 100644 packages/svelte/tests/css/samples/clsx-can-prune/expected.css create mode 100644 packages/svelte/tests/css/samples/clsx-can-prune/input.svelte create mode 100644 packages/svelte/tests/css/samples/clsx-cannot-prune-1/expected.css create mode 100644 packages/svelte/tests/css/samples/clsx-cannot-prune-1/input.svelte create mode 100644 packages/svelte/tests/css/samples/clsx-cannot-prune-2/expected.css create mode 100644 packages/svelte/tests/css/samples/clsx-cannot-prune-2/input.svelte create mode 100644 packages/svelte/tests/css/samples/clsx-cannot-prune-3/expected.css create mode 100644 packages/svelte/tests/css/samples/clsx-cannot-prune-3/input.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/clsx/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/clsx/child.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/clsx/main.svelte diff --git a/.changeset/thin-panthers-sing.md b/.changeset/thin-panthers-sing.md new file mode 100644 index 0000000000..223de002c6 --- /dev/null +++ b/.changeset/thin-panthers-sing.md @@ -0,0 +1,5 @@ +--- +'svelte': minor +--- + +feat: allow `class` attribute to be an object or array, using `clsx` diff --git a/documentation/docs/03-template-syntax/16-class.md b/documentation/docs/03-template-syntax/16-class.md deleted file mode 100644 index cecbc7cf20..0000000000 --- a/documentation/docs/03-template-syntax/16-class.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -title: class: ---- - -The `class:` directive is a convenient way to conditionally set classes on elements, as an alternative to using conditional expressions inside `class` attributes: - -```svelte - -
...
-
...
-``` - -As with other directives, we can use a shorthand when the name of the class coincides with the value: - -```svelte -
...
-``` - -Multiple `class:` directives can be added to a single element: - -```svelte -
...
-``` diff --git a/documentation/docs/03-template-syntax/18-class.md b/documentation/docs/03-template-syntax/18-class.md new file mode 100644 index 0000000000..880a34e9ec --- /dev/null +++ b/documentation/docs/03-template-syntax/18-class.md @@ -0,0 +1,90 @@ +--- +title: class +--- + +There are two ways to set classes on elements: the `class` attribute, and the `class:` directive. + +## Attributes + +Primitive values are treated like any other attribute: + +```svelte +
...
+``` + +> [!NOTE] +> For historical reasons, falsy values (like `false` and `NaN`) are stringified (`class="false"`), though `class={undefined}` (or `null`) cause the attribute to be omitted altogether. In a future version of Svelte, all falsy values will cause `class` to be omitted. + +### Objects and arrays + +Since Svelte 5.16, `class` can be an object or array, and is converted to a string using [clsx](https://github.com/lukeed/clsx). + +If the value is an object, the truthy keys are added: + +```svelte + + + +
...
+``` + +If the value is an array, the truthy values are combined: + +```svelte + +
...
+``` + +Note that whether we're using the array or object form, we can set multiple classes simultaneously with a single condition, which is particularly useful if you're using things like Tailwind. + +Arrays can contain arrays and objects, and clsx will flatten them. This is useful for combining local classes with props, for example: + +```svelte + + + + +``` + +The user of this component has the same flexibility to use a mixture of objects, arrays and strings: + +```svelte + + + + +``` + +## The `class:` directive + +Prior to Svelte 5.16, the `class:` directive was the most convenient way to set classes on elements conditionally. + +```svelte + +
...
+
...
+``` + +As with other directives, we can use a shorthand when the name of the class coincides with the value: + +```svelte +
...
+``` + +> [!NOTE] Unless you're using an older version of Svelte, consider avoiding `class:`, since the attribute is more powerful and composable. diff --git a/packages/svelte/elements.d.ts b/packages/svelte/elements.d.ts index 8800b65172..604403f0a2 100644 --- a/packages/svelte/elements.d.ts +++ b/packages/svelte/elements.d.ts @@ -741,7 +741,7 @@ export interface HTMLAttributes extends AriaAttributes, D accesskey?: string | undefined | null; autocapitalize?: 'characters' | 'off' | 'on' | 'none' | 'sentences' | 'words' | undefined | null; autofocus?: boolean | undefined | null; - class?: string | undefined | null; + class?: string | import('clsx').ClassArray | import('clsx').ClassDictionary | undefined | null; contenteditable?: Booleanish | 'inherit' | 'plaintext-only' | undefined | null; contextmenu?: string | undefined | null; dir?: 'ltr' | 'rtl' | 'auto' | undefined | null; @@ -1522,7 +1522,7 @@ export interface SvelteWindowAttributes extends HTMLAttributes { export interface SVGAttributes extends AriaAttributes, DOMAttributes { // Attributes which also defined in HTMLAttributes className?: string | undefined | null; - class?: string | undefined | null; + class?: string | import('clsx').ClassArray | import('clsx').ClassDictionary | undefined | null; color?: string | undefined | null; height?: number | string | undefined | null; id?: string | undefined | null; diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 05169a7bc2..b9f4d3de09 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -153,6 +153,7 @@ "acorn-typescript": "^1.4.13", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", + "clsx": "^2.1.1", "esm-env": "^1.2.1", "esrap": "^1.3.2", "is-reference": "^3.0.3", diff --git a/packages/svelte/src/compiler/phases/2-analyze/css/css-prune.js b/packages/svelte/src/compiler/phases/2-analyze/css/css-prune.js index 35bc675166..ca7476ef7f 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/css/css-prune.js +++ b/packages/svelte/src/compiler/phases/2-analyze/css/css-prune.js @@ -731,7 +731,7 @@ function attribute_matches(node, name, expected_value, operator, case_insensitiv /** @type {string[]} */ let prev_values = []; for (const chunk of chunks) { - const current_possible_values = get_possible_values(chunk); + const current_possible_values = get_possible_values(chunk, name === 'class'); // impossible to find out all combinations if (!current_possible_values) return true; @@ -784,7 +784,7 @@ function attribute_matches(node, name, expected_value, operator, case_insensitiv prev_values.push(current_possible_value); } }); - if (prev_values.length < current_possible_values.size) { + if (prev_values.length < current_possible_values.length) { prev_values.push(' '); } if (prev_values.length > 20) { diff --git a/packages/svelte/src/compiler/phases/2-analyze/css/utils.js b/packages/svelte/src/compiler/phases/2-analyze/css/utils.js index d3fd71ec39..d7544b55c0 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/css/utils.js +++ b/packages/svelte/src/compiler/phases/2-analyze/css/utils.js @@ -4,14 +4,74 @@ const UNKNOWN = {}; /** * @param {Node} node + * @param {boolean} is_class * @param {Set} set + * @param {boolean} is_nested */ -function gather_possible_values(node, set) { +function gather_possible_values(node, is_class, set, is_nested = false) { + if (set.has(UNKNOWN)) { + // no point traversing any further + return; + } + if (node.type === 'Literal') { set.add(String(node.value)); } else if (node.type === 'ConditionalExpression') { - gather_possible_values(node.consequent, set); - gather_possible_values(node.alternate, set); + gather_possible_values(node.consequent, is_class, set, is_nested); + gather_possible_values(node.alternate, is_class, set, is_nested); + } else if (node.type === 'LogicalExpression') { + if (node.operator === '&&') { + // && is a special case, because the only way the left + // hand value can be included is if it's falsy. this is + // a bit of extra work but it's worth it because + // `class={[condition && 'blah']}` is common, + // and we don't want to deopt on `condition` + const left = new Set(); + gather_possible_values(node.left, is_class, left, is_nested); + + if (left.has(UNKNOWN)) { + // add all non-nullish falsy values, unless this is a `class` attribute that + // will be processed by cslx, in which case falsy values are removed, unless + // they're not inside an array/object (TODO 6.0 remove that last part) + if (!is_class || !is_nested) { + set.add(''); + set.add(false); + set.add(NaN); + set.add(0); // -0 and 0n are also falsy, but stringify to '0' + } + } else { + for (const value of left) { + if (!value && value != undefined && (!is_class || !is_nested)) { + set.add(value); + } + } + } + + gather_possible_values(node.right, is_class, set, is_nested); + } else { + gather_possible_values(node.left, is_class, set, is_nested); + gather_possible_values(node.right, is_class, set, is_nested); + } + } else if (is_class && node.type === 'ArrayExpression') { + for (const entry of node.elements) { + if (entry) { + gather_possible_values(entry, is_class, set, true); + } + } + } else if (is_class && node.type === 'ObjectExpression') { + for (const property of node.properties) { + if ( + property.type === 'Property' && + !property.computed && + (property.key.type === 'Identifier' || property.key.type === 'Literal') + ) { + set.add( + property.key.type === 'Identifier' ? property.key.name : String(property.key.value) + ); + } else { + set.add(UNKNOWN); + } + } } else { set.add(UNKNOWN); } @@ -19,19 +79,20 @@ function gather_possible_values(node, set) { /** * @param {AST.Text | AST.ExpressionTag} chunk - * @returns {Set | null} + * @param {boolean} is_class + * @returns {string[] | null} */ -export function get_possible_values(chunk) { +export function get_possible_values(chunk, is_class) { const values = new Set(); if (chunk.type === 'Text') { values.add(chunk.data); } else { - gather_possible_values(chunk.expression, values); + gather_possible_values(chunk.expression, is_class, values); } if (values.has(UNKNOWN)) return null; - return values; + return [...values].map((value) => String(value)); } /** diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index c0e4a65571..76c1e94277 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -773,6 +773,8 @@ export function analyze_component(root, source, options) { if (attribute.type !== 'Attribute') continue; if (attribute.name.toLowerCase() !== 'class') continue; + // The dynamic class method appends the hash to the end of the class attribute on its own + if (attribute.metadata.needs_clsx) continue outer; class_attribute = attribute; } diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/Attribute.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/Attribute.js index 6eb9faca6d..9d801e095e 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/Attribute.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/Attribute.js @@ -38,6 +38,19 @@ export function Attribute(node, context) { mark_subtree_dynamic(context.path); } + // class={[...]} or class={{...}} or `class={x}` need clsx to resolve the classes + if ( + node.name === 'class' && + !Array.isArray(node.value) && + node.value !== true && + node.value.expression.type !== 'Literal' && + node.value.expression.type !== 'TemplateLiteral' && + node.value.expression.type !== 'BinaryExpression' + ) { + mark_subtree_dynamic(context.path); + node.metadata.needs_clsx = true; + } + if (node.value !== true) { for (const chunk of get_attribute_chunks(node.value)) { if (chunk.type !== 'ExpressionTag') continue; diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js index 2c2c287f12..59a6fafbc5 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js @@ -553,6 +553,10 @@ function build_element_attribute_update_assignment( let update; if (name === 'class') { + if (attribute.metadata.needs_clsx) { + value = b.call('$.clsx', value); + } + if (attribute.metadata.expression.has_state && has_call) { // ensure we're not creating a separate template effect for this so that // potential class directives are added to the same effect and therefore always apply @@ -561,11 +565,13 @@ function build_element_attribute_update_assignment( value = b.call('$.get', id); has_call = false; } + update = b.stmt( b.call( is_svg ? '$.set_svg_class' : is_mathml ? '$.set_mathml_class' : '$.set_class', node_id, - value + value, + attribute.metadata.needs_clsx ? b.literal(context.state.analysis.css.hash) : undefined ) ); } else if (name === 'value') { diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js index 5ebc647571..d0d800d3cb 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js @@ -86,10 +86,35 @@ export function build_element_attributes(node, context) { } else if (attribute.name !== 'defaultValue' && attribute.name !== 'defaultChecked') { if (attribute.name === 'class') { class_index = attributes.length; - } else if (attribute.name === 'style') { - style_index = attributes.length; + + if (attribute.metadata.needs_clsx) { + const clsx_value = b.call( + '$.clsx', + /** @type {AST.ExpressionTag} */ (attribute.value).expression + ); + attributes.push({ + ...attribute, + value: { + .../** @type {AST.ExpressionTag} */ (attribute.value), + expression: context.state.analysis.css.hash + ? b.binary( + '+', + b.binary('+', clsx_value, b.literal(' ')), + b.literal(context.state.analysis.css.hash) + ) + : clsx_value + } + }); + } else { + attributes.push(attribute); + } + } else { + if (attribute.name === 'style') { + style_index = attributes.length; + } + + attributes.push(attribute); } - attributes.push(attribute); } } else if (attribute.type === 'BindDirective') { if (attribute.name === 'value' && node.name === 'select') continue; diff --git a/packages/svelte/src/compiler/phases/nodes.js b/packages/svelte/src/compiler/phases/nodes.js index 7aa9fecd3a..5066833feb 100644 --- a/packages/svelte/src/compiler/phases/nodes.js +++ b/packages/svelte/src/compiler/phases/nodes.js @@ -45,7 +45,8 @@ export function create_attribute(name, start, end, value) { value, metadata: { expression: create_expression_metadata(), - delegated: null + delegated: null, + needs_clsx: false } }; } diff --git a/packages/svelte/src/compiler/types/template.d.ts b/packages/svelte/src/compiler/types/template.d.ts index 97a25df4a7..8be9aed177 100644 --- a/packages/svelte/src/compiler/types/template.d.ts +++ b/packages/svelte/src/compiler/types/template.d.ts @@ -482,6 +482,8 @@ export namespace AST { expression: ExpressionMetadata; /** May be set if this is an event attribute */ delegated: null | DelegatedEvent; + /** May be `true` if this is a `class` attribute that needs `clsx` */ + needs_clsx: boolean; }; } diff --git a/packages/svelte/src/internal/client/dom/elements/attributes.js b/packages/svelte/src/internal/client/dom/elements/attributes.js index 9c62d684c1..6656532986 100644 --- a/packages/svelte/src/internal/client/dom/elements/attributes.js +++ b/packages/svelte/src/internal/client/dom/elements/attributes.js @@ -13,6 +13,7 @@ import { set_active_effect, set_active_reaction } from '../../runtime.js'; +import { clsx } from '../../../shared/attributes.js'; /** * The value/checked attribute in the template actually corresponds to the defaultValue property, so we need @@ -267,6 +268,10 @@ export function set_attributes( } } + if (next.class) { + next.class = clsx(next.class); + } + if (css_hash !== undefined) { next.class = next.class ? next.class + ' ' + css_hash : css_hash; } diff --git a/packages/svelte/src/internal/client/dom/elements/class.js b/packages/svelte/src/internal/client/dom/elements/class.js index 22f3da0f44..62ffb6d14b 100644 --- a/packages/svelte/src/internal/client/dom/elements/class.js +++ b/packages/svelte/src/internal/client/dom/elements/class.js @@ -3,12 +3,13 @@ import { hydrating } from '../hydration.js'; /** * @param {SVGElement} dom * @param {string} value + * @param {string} [hash] * @returns {void} */ -export function set_svg_class(dom, value) { +export function set_svg_class(dom, value, hash) { // @ts-expect-error need to add __className to patched prototype var prev_class_name = dom.__className; - var next_class_name = to_class(value); + var next_class_name = to_class(value, hash); if (hydrating && dom.getAttribute('class') === next_class_name) { // In case of hydration don't reset the class as it's already correct. @@ -32,12 +33,13 @@ export function set_svg_class(dom, value) { /** * @param {MathMLElement} dom * @param {string} value + * @param {string} [hash] * @returns {void} */ -export function set_mathml_class(dom, value) { +export function set_mathml_class(dom, value, hash) { // @ts-expect-error need to add __className to patched prototype var prev_class_name = dom.__className; - var next_class_name = to_class(value); + var next_class_name = to_class(value, hash); if (hydrating && dom.getAttribute('class') === next_class_name) { // In case of hydration don't reset the class as it's already correct. @@ -61,12 +63,13 @@ export function set_mathml_class(dom, value) { /** * @param {HTMLElement} dom * @param {string} value + * @param {string} [hash] * @returns {void} */ -export function set_class(dom, value) { +export function set_class(dom, value, hash) { // @ts-expect-error need to add __className to patched prototype var prev_class_name = dom.__className; - var next_class_name = to_class(value); + var next_class_name = to_class(value, hash); if (hydrating && dom.className === next_class_name) { // In case of hydration don't reset the class as it's already correct. @@ -79,7 +82,7 @@ export function set_class(dom, value) { // Removing the attribute when the value is only an empty string causes // peformance issues vs simply making the className an empty string. So // we should only remove the class if the the value is nullish. - if (value == null) { + if (value == null && !hash) { dom.removeAttribute('class'); } else { dom.className = next_class_name; @@ -93,10 +96,11 @@ export function set_class(dom, value) { /** * @template V * @param {V} value + * @param {string} [hash] * @returns {string | V} */ -function to_class(value) { - return value == null ? '' : value; +function to_class(value, hash) { + return (value == null ? '' : value) + (hash ? ' ' + hash : ''); } /** diff --git a/packages/svelte/src/internal/client/index.js b/packages/svelte/src/internal/client/index.js index f22c33babc..3b85ae1816 100644 --- a/packages/svelte/src/internal/client/index.js +++ b/packages/svelte/src/internal/client/index.js @@ -161,7 +161,7 @@ export { $window as window, $document as document } from './dom/operations.js'; -export { attr } from '../shared/attributes.js'; +export { attr, clsx } from '../shared/attributes.js'; export { snapshot } from '../shared/clone.js'; export { noop, fallback } from '../shared/utils.js'; export { diff --git a/packages/svelte/src/internal/server/index.js b/packages/svelte/src/internal/server/index.js index b8371b7e00..89b3c33df8 100644 --- a/packages/svelte/src/internal/server/index.js +++ b/packages/svelte/src/internal/server/index.js @@ -2,7 +2,7 @@ /** @import { Component, Payload, RenderOutput } from '#server' */ /** @import { Store } from '#shared' */ export { FILENAME, HMR } from '../../constants.js'; -import { attr } from '../shared/attributes.js'; +import { attr, clsx } from '../shared/attributes.js'; import { is_promise, noop } from '../shared/utils.js'; import { subscribe_to_store } from '../../store/utils.js'; import { @@ -195,6 +195,10 @@ export function spread_attributes(attrs, classes, styles, flags = 0) { : style_object_to_string(styles); } + if (attrs.class) { + attrs.class = clsx(attrs.class); + } + if (classes) { const classlist = attrs.class ? [attrs.class] : []; @@ -522,7 +526,7 @@ export function once(get_value) { }; } -export { attr }; +export { attr, clsx }; export { html } from './blocks/html.js'; diff --git a/packages/svelte/src/internal/shared/attributes.js b/packages/svelte/src/internal/shared/attributes.js index 867d6ba5d3..a561501bf4 100644 --- a/packages/svelte/src/internal/shared/attributes.js +++ b/packages/svelte/src/internal/shared/attributes.js @@ -1,4 +1,5 @@ import { escape_html } from '../../escaping.js'; +import { clsx as _clsx } from 'clsx'; /** * `
` should be rendered as `
` and _not_ @@ -26,3 +27,16 @@ export function attr(name, value, is_boolean = false) { const assignment = is_boolean ? '' : `="${escape_html(normalized, true)}"`; return ` ${name}${assignment}`; } + +/** + * Small wrapper around clsx to preserve Svelte's (weird) handling of falsy values. + * TODO Svelte 6 revisit this, and likely turn all falsy values into the empty string (what clsx also does) + * @param {any} value + */ +export function clsx(value) { + if (typeof value === 'object') { + return _clsx(value); + } else { + return value ?? ''; + } +} diff --git a/packages/svelte/tests/css/samples/clsx-can-prune/_config.js b/packages/svelte/tests/css/samples/clsx-can-prune/_config.js new file mode 100644 index 0000000000..43c80a318d --- /dev/null +++ b/packages/svelte/tests/css/samples/clsx-can-prune/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + warnings: [ + { + code: 'css_unused_selector', + message: 'Unused CSS selector ".unused"\nhttps://svelte.dev/e/css_unused_selector', + start: { + line: 24, + column: 1, + character: 548 + }, + end: { + line: 24, + column: 8, + character: 555 + } + } + ] +}); diff --git a/packages/svelte/tests/css/samples/clsx-can-prune/expected.css b/packages/svelte/tests/css/samples/clsx-can-prune/expected.css new file mode 100644 index 0000000000..620db0f022 --- /dev/null +++ b/packages/svelte/tests/css/samples/clsx-can-prune/expected.css @@ -0,0 +1,12 @@ + + .used1.svelte-xyz { color: green; } + .used2.svelte-xyz { color: green; } + .used3.svelte-xyz { color: green; } + .used4.svelte-xyz { color: green; } + .used5.svelte-xyz { color: green; } + .used6.svelte-xyz { color: green; } + .used7.svelte-xyz { color: green; } + .used8.svelte-xyz { color: green; } + .used9.svelte-xyz { color: green; } + + /* (unused) .unused { color: red; }*/ diff --git a/packages/svelte/tests/css/samples/clsx-can-prune/input.svelte b/packages/svelte/tests/css/samples/clsx-can-prune/input.svelte new file mode 100644 index 0000000000..2c75a39f99 --- /dev/null +++ b/packages/svelte/tests/css/samples/clsx-can-prune/input.svelte @@ -0,0 +1,25 @@ + + +

+

+

+

+

+

+

+ + diff --git a/packages/svelte/tests/css/samples/clsx-cannot-prune-1/expected.css b/packages/svelte/tests/css/samples/clsx-cannot-prune-1/expected.css new file mode 100644 index 0000000000..243bdb2b82 --- /dev/null +++ b/packages/svelte/tests/css/samples/clsx-cannot-prune-1/expected.css @@ -0,0 +1,2 @@ + + .x.svelte-xyz { color: green; } diff --git a/packages/svelte/tests/css/samples/clsx-cannot-prune-1/input.svelte b/packages/svelte/tests/css/samples/clsx-cannot-prune-1/input.svelte new file mode 100644 index 0000000000..d9de0bdfd4 --- /dev/null +++ b/packages/svelte/tests/css/samples/clsx-cannot-prune-1/input.svelte @@ -0,0 +1,5 @@ +

hello world

+ + diff --git a/packages/svelte/tests/css/samples/clsx-cannot-prune-2/expected.css b/packages/svelte/tests/css/samples/clsx-cannot-prune-2/expected.css new file mode 100644 index 0000000000..243bdb2b82 --- /dev/null +++ b/packages/svelte/tests/css/samples/clsx-cannot-prune-2/expected.css @@ -0,0 +1,2 @@ + + .x.svelte-xyz { color: green; } diff --git a/packages/svelte/tests/css/samples/clsx-cannot-prune-2/input.svelte b/packages/svelte/tests/css/samples/clsx-cannot-prune-2/input.svelte new file mode 100644 index 0000000000..212deab4f0 --- /dev/null +++ b/packages/svelte/tests/css/samples/clsx-cannot-prune-2/input.svelte @@ -0,0 +1,5 @@ +

hello world

+ + diff --git a/packages/svelte/tests/css/samples/clsx-cannot-prune-3/expected.css b/packages/svelte/tests/css/samples/clsx-cannot-prune-3/expected.css new file mode 100644 index 0000000000..243bdb2b82 --- /dev/null +++ b/packages/svelte/tests/css/samples/clsx-cannot-prune-3/expected.css @@ -0,0 +1,2 @@ + + .x.svelte-xyz { color: green; } diff --git a/packages/svelte/tests/css/samples/clsx-cannot-prune-3/input.svelte b/packages/svelte/tests/css/samples/clsx-cannot-prune-3/input.svelte new file mode 100644 index 0000000000..2dfa1afd18 --- /dev/null +++ b/packages/svelte/tests/css/samples/clsx-cannot-prune-3/input.svelte @@ -0,0 +1,5 @@ +

hello world

+ + diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-null-classname-no-style/_config.js b/packages/svelte/tests/runtime-legacy/samples/attribute-null-classname-no-style/_config.js index a7518f7e6c..b2f0396181 100644 --- a/packages/svelte/tests/runtime-legacy/samples/attribute-null-classname-no-style/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-null-classname-no-style/_config.js @@ -40,7 +40,7 @@ export default test({ assert.equal(div.className, 'true'); component.testName = {}; - assert.equal(div.className, '[object Object]'); + assert.equal(div.className, ''); component.testName = ''; assert.equal(div.className, ''); diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-null-classname-with-style/_config.js b/packages/svelte/tests/runtime-legacy/samples/attribute-null-classname-with-style/_config.js index dbab9fd42b..c8710f9038 100644 --- a/packages/svelte/tests/runtime-legacy/samples/attribute-null-classname-with-style/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-null-classname-with-style/_config.js @@ -32,7 +32,7 @@ export default test({ assert.equal(div.className, 'true svelte-x1o6ra'); component.testName = {}; - assert.equal(div.className, '[object Object] svelte-x1o6ra'); + assert.equal(div.className, ' svelte-x1o6ra'); component.testName = ''; assert.equal(div.className, ' svelte-x1o6ra'); diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-null-func-classname-no-style/_config.js b/packages/svelte/tests/runtime-legacy/samples/attribute-null-func-classname-no-style/_config.js index a7518f7e6c..b2f0396181 100644 --- a/packages/svelte/tests/runtime-legacy/samples/attribute-null-func-classname-no-style/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-null-func-classname-no-style/_config.js @@ -40,7 +40,7 @@ export default test({ assert.equal(div.className, 'true'); component.testName = {}; - assert.equal(div.className, '[object Object]'); + assert.equal(div.className, ''); component.testName = ''; assert.equal(div.className, ''); diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-null-func-classname-with-style/_config.js b/packages/svelte/tests/runtime-legacy/samples/attribute-null-func-classname-with-style/_config.js index 20426dcf4b..8d0f411b8f 100644 --- a/packages/svelte/tests/runtime-legacy/samples/attribute-null-func-classname-with-style/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-null-func-classname-with-style/_config.js @@ -40,7 +40,7 @@ export default test({ assert.equal(div.className, 'true svelte-x1o6ra'); component.testName = {}; - assert.equal(div.className, '[object Object] svelte-x1o6ra'); + assert.equal(div.className, ' svelte-x1o6ra'); component.testName = ''; assert.equal(div.className, ' svelte-x1o6ra'); diff --git a/packages/svelte/tests/runtime-runes/samples/clsx/_config.js b/packages/svelte/tests/runtime-runes/samples/clsx/_config.js new file mode 100644 index 0000000000..e0813d0e6c --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/clsx/_config.js @@ -0,0 +1,43 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
+
+
+
+
+ +
child
+
child
+
child
+
child
+
child
+ + + `, + test({ assert, target }) { + const button = target.querySelector('button'); + + button?.click(); + + assert.htmlEqual( + target.innerHTML, + ` +
+
+
+
+
+ +
child
+
child
+
child
+
child
+
child
+ + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/clsx/child.svelte b/packages/svelte/tests/runtime-runes/samples/clsx/child.svelte new file mode 100644 index 0000000000..1b8be697c0 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/clsx/child.svelte @@ -0,0 +1,5 @@ + + +
child
diff --git a/packages/svelte/tests/runtime-runes/samples/clsx/main.svelte b/packages/svelte/tests/runtime-runes/samples/clsx/main.svelte new file mode 100644 index 0000000000..bf68b42e11 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/clsx/main.svelte @@ -0,0 +1,33 @@ + + +
+
+
+
+
+ + + + + + + + + + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f7f38700e4..8bf7bb4224 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -80,6 +80,9 @@ importers: axobject-query: specifier: ^4.1.0 version: 4.1.0 + clsx: + specifier: ^2.1.1 + version: 2.1.1 esm-env: specifier: ^1.2.1 version: 1.2.1 @@ -890,6 +893,10 @@ packages: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -3055,6 +3062,8 @@ snapshots: ci-info@3.9.0: {} + clsx@2.1.1: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 From 97f3aa91517cabb05ecf553b5be18bf38dcef1ae Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 24 Dec 2024 09:14:56 -0500 Subject: [PATCH 03/63] docs: fix links in some errors/warnings (#14825) * fix links in some errors/warnings * fix --- .../98-reference/.generated/client-errors.md | 8 ++++++-- .../98-reference/.generated/client-warnings.md | 2 +- .../98-reference/.generated/compile-warnings.md | 2 +- packages/svelte/messages/client-errors/errors.md | 8 ++++++-- .../svelte/messages/client-warnings/warnings.md | 2 +- .../svelte/messages/compile-warnings/a11y.md | 2 +- packages/svelte/src/compiler/warnings.js | 4 ++-- packages/svelte/src/internal/client/errors.js | 8 ++++---- .../warnings.json | 16 ++++++++-------- .../validator/samples/slot-warning/warnings.json | 2 +- .../samples/slot-warning2/warnings.json | 2 +- 11 files changed, 32 insertions(+), 24 deletions(-) diff --git a/documentation/docs/98-reference/.generated/client-errors.md b/documentation/docs/98-reference/.generated/client-errors.md index 90c9c1f9d1..2c2e0707ea 100644 --- a/documentation/docs/98-reference/.generated/client-errors.md +++ b/documentation/docs/98-reference/.generated/client-errors.md @@ -21,15 +21,19 @@ A component is attempting to bind to a non-bindable property `%key%` belonging t ### component_api_changed ``` -%parent% called `%method%` on an instance of %component%, which is no longer valid in Svelte 5. See https://svelte.dev/docs/svelte/v5-migration-guide#Components-are-no-longer-classes for more information +%parent% called `%method%` on an instance of %component%, which is no longer valid in Svelte 5 ``` +See the [migration guide](/docs/svelte/v5-migration-guide#Components-are-no-longer-classes) for more information. + ### component_api_invalid_new ``` -Attempted to instantiate %component% with `new %name%`, which is no longer valid in Svelte 5. If this component is not under your control, set the `compatibility.componentApi` compiler option to `4` to keep it working. See https://svelte.dev/docs/svelte/v5-migration-guide#Components-are-no-longer-classes for more information +Attempted to instantiate %component% with `new %name%`, which is no longer valid in Svelte 5. If this component is not under your control, set the `compatibility.componentApi` compiler option to `4` to keep it working. ``` +See the [migration guide](/docs/svelte/v5-migration-guide#Components-are-no-longer-classes) for more information. + ### derived_references_self ``` diff --git a/documentation/docs/98-reference/.generated/client-warnings.md b/documentation/docs/98-reference/.generated/client-warnings.md index 06ca578b76..5218ec4cb1 100644 --- a/documentation/docs/98-reference/.generated/client-warnings.md +++ b/documentation/docs/98-reference/.generated/client-warnings.md @@ -52,7 +52,7 @@ Your `console.%method%` contained `$state` proxies. Consider using `$inspect(... When logging a [proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy), browser devtools will log the proxy itself rather than the value it represents. In the case of Svelte, the 'target' of a `$state` proxy might not resemble its current value, which can be confusing. -The easiest way to log a value as it changes over time is to use the [`$inspect`](https://svelte.dev/docs/svelte/$inspect) rune. Alternatively, to log things on a one-off basis (for example, inside an event handler) you can use [`$state.snapshot`](https://svelte.dev/docs/svelte/$state#$state.snapshot) to take a snapshot of the current value. +The easiest way to log a value as it changes over time is to use the [`$inspect`](/docs/svelte/$inspect) rune. Alternatively, to log things on a one-off basis (for example, inside an event handler) you can use [`$state.snapshot`](/docs/svelte/$state#$state.snapshot) to take a snapshot of the current value. ### event_handler_invalid diff --git a/documentation/docs/98-reference/.generated/compile-warnings.md b/documentation/docs/98-reference/.generated/compile-warnings.md index 3d515305fe..57396bd7fd 100644 --- a/documentation/docs/98-reference/.generated/compile-warnings.md +++ b/documentation/docs/98-reference/.generated/compile-warnings.md @@ -62,7 +62,7 @@ Enforce that `autofocus` is not used on elements. Autofocusing elements can caus ### a11y_click_events_have_key_events ``` -Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as ` diff --git a/packages/svelte/tests/runtime-runes/samples/inspect-trace-null/_config.js b/packages/svelte/tests/runtime-runes/samples/inspect-trace-null/_config.js new file mode 100644 index 0000000000..e779a835c2 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/inspect-trace-null/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + test() {} +}); diff --git a/packages/svelte/tests/runtime-runes/samples/inspect-trace-null/main.svelte b/packages/svelte/tests/runtime-runes/samples/inspect-trace-null/main.svelte new file mode 100644 index 0000000000..30eb95f124 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/inspect-trace-null/main.svelte @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-runes/samples/inspect-trace-reassignment/_config.js b/packages/svelte/tests/runtime-runes/samples/inspect-trace-reassignment/_config.js new file mode 100644 index 0000000000..c9a66289a1 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/inspect-trace-reassignment/_config.js @@ -0,0 +1,72 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +/** + * @param {any[]} logs + */ +function normalise_trace_logs(logs) { + let normalised = []; + for (let i = 0; i < logs.length; i++) { + const log = logs[i]; + + if (typeof log === 'string' && log.includes('%c')) { + const split = log.split('%c'); + normalised.push({ + log: (split[0].length !== 0 ? split[0] : split[1]).trim(), + highlighted: logs[i + 1] === 'color: CornflowerBlue; font-weight: bold' + }); + i++; + } else if (log instanceof Error) { + continue; + } else { + normalised.push({ log }); + } + } + return normalised; +} + +export default test({ + compileOptions: { + dev: true + }, + + test({ assert, target, logs }) { + // initial log, everything is highlighted + + assert.deepEqual(normalise_trace_logs(logs), [ + { log: 'effect', highlighted: false }, + { log: '$state', highlighted: true }, + { log: false } + ]); + + logs.length = 0; + + const button = target.querySelector('button'); + button?.click(); + flushSync(); + + const input = target.querySelector('input'); + input?.click(); + flushSync(); + + // checked changed, effect reassign state, values should be correct and be correctly highlighted + + assert.deepEqual(normalise_trace_logs(logs), [ + { log: 'effect', highlighted: false }, + { log: '$state', highlighted: true }, + { log: true }, + { log: '$state', highlighted: true }, + { log: 1 }, + { log: 'effect', highlighted: false }, + { log: '$state', highlighted: false }, + { log: true }, + { log: '$state', highlighted: true }, + { log: 2 }, + { log: 'effect', highlighted: false }, + { log: '$state', highlighted: false }, + { log: true }, + { log: '$state', highlighted: true }, + { log: 3 } + ]); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/inspect-trace-reassignment/main.svelte b/packages/svelte/tests/runtime-runes/samples/inspect-trace-reassignment/main.svelte new file mode 100644 index 0000000000..5028c0f251 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/inspect-trace-reassignment/main.svelte @@ -0,0 +1,18 @@ + + + \ No newline at end of file diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index d422abebbc..b6b76b1cb7 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -3091,7 +3091,7 @@ declare namespace $inspect { * }); * */ - export function trace(name: string): void; + export function trace(name?: string): void; // prevent intellisense from being unhelpful /** @deprecated */ From 82db92f8707f593a0d14c2dab4089f6f36b3ada3 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Sun, 5 Jan 2025 20:25:27 +0000 Subject: [PATCH 10/63] fix: ensure disconnected deriveds correctly connect again (#14899) * fix: ensure disconnected deriveds correctly connect again * fix: ensure disconnected deriveds correctly connect again --- .changeset/happy-plums-greet.md | 5 + .../svelte/src/internal/client/runtime.js | 4 +- .../samples/derived-disconnect/_config.js | 96 +++++++++++++++++++ .../samples/derived-disconnect/main.svelte | 23 +++++ 4 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 .changeset/happy-plums-greet.md create mode 100644 packages/svelte/tests/runtime-runes/samples/derived-disconnect/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/derived-disconnect/main.svelte diff --git a/.changeset/happy-plums-greet.md b/.changeset/happy-plums-greet.md new file mode 100644 index 0000000000..695fbff8fd --- /dev/null +++ b/.changeset/happy-plums-greet.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: ensure disconnected deriveds correctly connect again diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index c5223a6ae4..0be91d78ba 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -207,7 +207,9 @@ export function check_dirtiness(reaction) { for (i = 0; i < length; i++) { dependency = dependencies[i]; - if (!dependency?.reactions?.includes(reaction)) { + // We always re-add all reactions (even duplicates) if the derived was + // previously disconnected + if (is_disconnected || !dependency?.reactions?.includes(reaction)) { (dependency.reactions ??= []).push(reaction); } } diff --git a/packages/svelte/tests/runtime-runes/samples/derived-disconnect/_config.js b/packages/svelte/tests/runtime-runes/samples/derived-disconnect/_config.js new file mode 100644 index 0000000000..76e60b7402 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/derived-disconnect/_config.js @@ -0,0 +1,96 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target, logs }) { + let [b1, b2, b3, b4, b5] = target.querySelectorAll('button'); + + b1?.click(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + `
Current ID: 1
+
Name: a

+
` + ); + + b2?.click(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + `
Current ID: 2
+
Name: b

+
` + ); + + b3?.click(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + `
Current ID: 3
+
Name: c

+
` + ); + + b4?.click(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + `
Current ID: 4
+
Name: d

+
` + ); + + b5?.click(); + flushSync(); + + b5?.click(); + flushSync(); + + [b1, b2, b3, b4, b5] = target.querySelectorAll('button'); + + b1?.click(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + `
Current ID: 1
+
Name: a

+
` + ); + + b2?.click(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + `
Current ID: 2
+
Name: b

+
` + ); + + b3?.click(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + `
Current ID: 3
+
Name: c

+
` + ); + + b4?.click(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + `
Current ID: 4
+
Name: d

+
` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/derived-disconnect/main.svelte b/packages/svelte/tests/runtime-runes/samples/derived-disconnect/main.svelte new file mode 100644 index 0000000000..8cb6ed2afd --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/derived-disconnect/main.svelte @@ -0,0 +1,23 @@ + + +
+ {#if visible} +
Current ID: {currentId}
+
Name: {currentItem.name}
+ {#each items as item} +
+ {/each} + {/if} +
+
+
From ed26c3f658acb0292f06e6a437d42bb64e804447 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 5 Jan 2025 20:38:17 +0000 Subject: [PATCH 11/63] Version Packages (#14888) Co-authored-by: github-actions[bot] --- .changeset/happy-plums-greet.md | 5 ----- .changeset/silver-shoes-rule.md | 5 ----- packages/svelte/CHANGELOG.md | 8 ++++++++ packages/svelte/package.json | 2 +- packages/svelte/src/version.js | 2 +- 5 files changed, 10 insertions(+), 12 deletions(-) delete mode 100644 .changeset/happy-plums-greet.md delete mode 100644 .changeset/silver-shoes-rule.md diff --git a/.changeset/happy-plums-greet.md b/.changeset/happy-plums-greet.md deleted file mode 100644 index 695fbff8fd..0000000000 --- a/.changeset/happy-plums-greet.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: ensure disconnected deriveds correctly connect again diff --git a/.changeset/silver-shoes-rule.md b/.changeset/silver-shoes-rule.md deleted file mode 100644 index b1c44c9007..0000000000 --- a/.changeset/silver-shoes-rule.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: correctly highlight sources reassigned inside `trace` diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index 277d1631cb..97aad73746 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,13 @@ # svelte +## 5.16.2 + +### Patch Changes + +- fix: ensure disconnected deriveds correctly connect again ([#14899](https://github.com/sveltejs/svelte/pull/14899)) + +- fix: correctly highlight sources reassigned inside `trace` ([#14811](https://github.com/sveltejs/svelte/pull/14811)) + ## 5.16.1 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index a054f6c6d9..f4b9a3faff 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -2,7 +2,7 @@ "name": "svelte", "description": "Cybernetically enhanced web apps", "license": "MIT", - "version": "5.16.1", + "version": "5.16.2", "type": "module", "types": "./types/index.d.ts", "engines": { diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js index 8a57832c96..add463faef 100644 --- a/packages/svelte/src/version.js +++ b/packages/svelte/src/version.js @@ -6,5 +6,5 @@ * https://svelte.dev/docs/svelte-compiler#svelte-version * @type {string} */ -export const VERSION = '5.16.1'; +export const VERSION = '5.16.2'; export const PUBLIC_VERSION = '5'; From c4e9faad52c09e143148a69c3643d36462175499 Mon Sep 17 00:00:00 2001 From: Paolo Ricciuti Date: Mon, 6 Jan 2025 11:08:07 +0100 Subject: [PATCH 12/63] fix: correctly parse `each` with loose parser (#14887) * fix: correctly parse `each` with loose parser * chore: fix lint * chore: remove unused imports * Apply suggestions from code review * chore: fix lint --------- Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com> --- .changeset/famous-scissors-begin.md | 5 + .../phases/1-parse/read/expression.js | 43 ++- .../src/compiler/phases/1-parse/state/tag.js | 22 +- .../samples/loose-valid-each-as/input.svelte | 7 + .../samples/loose-valid-each-as/output.json | 308 ++++++++++++++++++ 5 files changed, 364 insertions(+), 21 deletions(-) create mode 100644 .changeset/famous-scissors-begin.md create mode 100644 packages/svelte/tests/parser-modern/samples/loose-valid-each-as/input.svelte create mode 100644 packages/svelte/tests/parser-modern/samples/loose-valid-each-as/output.json diff --git a/.changeset/famous-scissors-begin.md b/.changeset/famous-scissors-begin.md new file mode 100644 index 0000000000..96075d0dac --- /dev/null +++ b/.changeset/famous-scissors-begin.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: correctly parse `each` with loose parser diff --git a/packages/svelte/src/compiler/phases/1-parse/read/expression.js b/packages/svelte/src/compiler/phases/1-parse/read/expression.js index 907608b11b..82a667d38c 100644 --- a/packages/svelte/src/compiler/phases/1-parse/read/expression.js +++ b/packages/svelte/src/compiler/phases/1-parse/read/expression.js @@ -8,9 +8,31 @@ import { find_matching_bracket } from '../utils/bracket.js'; /** * @param {Parser} parser * @param {string} [opening_token] + * @returns {Expression | undefined} + */ +export function get_loose_identifier(parser, opening_token) { + // Find the next } and treat it as the end of the expression + const end = find_matching_bracket(parser.template, parser.index, opening_token ?? '{'); + if (end) { + const start = parser.index; + parser.index = end; + // We don't know what the expression is and signal this by returning an empty identifier + return { + type: 'Identifier', + start, + end, + name: '' + }; + } +} + +/** + * @param {Parser} parser + * @param {string} [opening_token] + * @param {boolean} [disallow_loose] * @returns {Expression} */ -export default function read_expression(parser, opening_token) { +export default function read_expression(parser, opening_token, disallow_loose) { try { const node = parse_expression_at(parser.template, parser.ts, parser.index); @@ -41,19 +63,12 @@ export default function read_expression(parser, opening_token) { return /** @type {Expression} */ (node); } catch (err) { - if (parser.loose) { - // Find the next } and treat it as the end of the expression - const end = find_matching_bracket(parser.template, parser.index, opening_token ?? '{'); - if (end) { - const start = parser.index; - parser.index = end; - // We don't know what the expression is and signal this by returning an empty identifier - return { - type: 'Identifier', - start, - end, - name: '' - }; + // If we are in an each loop we need the error to be thrown in cases like + // `as { y = z }` so we still throw and handle the error there + if (parser.loose && !disallow_loose) { + const expression = get_loose_identifier(parser, opening_token); + if (expression) { + return expression; } } diff --git a/packages/svelte/src/compiler/phases/1-parse/state/tag.js b/packages/svelte/src/compiler/phases/1-parse/state/tag.js index 7996d64ded..95d7d00677 100644 --- a/packages/svelte/src/compiler/phases/1-parse/state/tag.js +++ b/packages/svelte/src/compiler/phases/1-parse/state/tag.js @@ -1,13 +1,13 @@ /** @import { ArrowFunctionExpression, Expression, Identifier, Pattern } from 'estree' */ /** @import { AST } from '#compiler' */ /** @import { Parser } from '../index.js' */ -import read_pattern from '../read/context.js'; -import read_expression from '../read/expression.js'; -import * as e from '../../../errors.js'; -import { create_fragment } from '../utils/create.js'; import { walk } from 'zimmerframe'; -import { parse_expression_at } from '../acorn.js'; +import * as e from '../../../errors.js'; import { create_expression_metadata } from '../../nodes.js'; +import { parse_expression_at } from '../acorn.js'; +import read_pattern from '../read/context.js'; +import read_expression, { get_loose_identifier } from '../read/expression.js'; +import { create_fragment } from '../utils/create.js'; const regex_whitespace_with_closing_curly_brace = /^\s*}/; @@ -87,7 +87,7 @@ function open(parser) { // we get a valid expression while (!expression) { try { - expression = read_expression(parser); + expression = read_expression(parser, undefined, true); } catch (err) { end = /** @type {any} */ (err).position[0] - 2; @@ -95,7 +95,15 @@ function open(parser) { end -= 1; } - if (end <= start) throw err; + if (end <= start) { + if (parser.loose) { + expression = get_loose_identifier(parser); + if (expression) { + break; + } + } + throw err; + } // @ts-expect-error parser.template is meant to be readonly, this is a special case parser.template = template.slice(0, end); diff --git a/packages/svelte/tests/parser-modern/samples/loose-valid-each-as/input.svelte b/packages/svelte/tests/parser-modern/samples/loose-valid-each-as/input.svelte new file mode 100644 index 0000000000..f2cc7f5e79 --- /dev/null +++ b/packages/svelte/tests/parser-modern/samples/loose-valid-each-as/input.svelte @@ -0,0 +1,7 @@ + + +{#each arr as [key, value = 'default']} +
{key}: {value}
+{/each} diff --git a/packages/svelte/tests/parser-modern/samples/loose-valid-each-as/output.json b/packages/svelte/tests/parser-modern/samples/loose-valid-each-as/output.json new file mode 100644 index 0000000000..181f1ba250 --- /dev/null +++ b/packages/svelte/tests/parser-modern/samples/loose-valid-each-as/output.json @@ -0,0 +1,308 @@ +{ + "css": null, + "js": [], + "start": 45, + "end": 119, + "type": "Root", + "fragment": { + "type": "Fragment", + "nodes": [ + { + "type": "Text", + "start": 43, + "end": 45, + "raw": "\n\n", + "data": "\n\n" + }, + { + "type": "EachBlock", + "start": 45, + "end": 119, + "expression": { + "type": "Identifier", + "start": 52, + "end": 55, + "loc": { + "start": { + "line": 5, + "column": 7 + }, + "end": { + "line": 5, + "column": 10 + } + }, + "name": "arr" + }, + "body": { + "type": "Fragment", + "nodes": [ + { + "type": "Text", + "start": 84, + "end": 86, + "raw": "\n\t", + "data": "\n\t" + }, + { + "type": "RegularElement", + "start": 86, + "end": 111, + "name": "div", + "attributes": [], + "fragment": { + "type": "Fragment", + "nodes": [ + { + "type": "ExpressionTag", + "start": 91, + "end": 96, + "expression": { + "type": "Identifier", + "start": 92, + "end": 95, + "loc": { + "start": { + "line": 6, + "column": 7 + }, + "end": { + "line": 6, + "column": 10 + } + }, + "name": "key" + } + }, + { + "type": "Text", + "start": 96, + "end": 98, + "raw": ": ", + "data": ": " + }, + { + "type": "ExpressionTag", + "start": 98, + "end": 105, + "expression": { + "type": "Identifier", + "start": 99, + "end": 104, + "loc": { + "start": { + "line": 6, + "column": 14 + }, + "end": { + "line": 6, + "column": 19 + } + }, + "name": "value" + } + } + ] + } + }, + { + "type": "Text", + "start": 111, + "end": 112, + "raw": "\n", + "data": "\n" + } + ] + }, + "context": { + "type": "ArrayPattern", + "start": 59, + "end": 83, + "loc": { + "start": { + "line": 5, + "column": 15 + }, + "end": { + "line": 5, + "column": 39 + } + }, + "elements": [ + { + "type": "Identifier", + "start": 60, + "end": 63, + "loc": { + "start": { + "line": 5, + "column": 16 + }, + "end": { + "line": 5, + "column": 19 + } + }, + "name": "key" + }, + { + "type": "AssignmentPattern", + "start": 65, + "end": 82, + "loc": { + "start": { + "line": 5, + "column": 21 + }, + "end": { + "line": 5, + "column": 38 + } + }, + "left": { + "type": "Identifier", + "start": 65, + "end": 70, + "loc": { + "start": { + "line": 5, + "column": 21 + }, + "end": { + "line": 5, + "column": 26 + } + }, + "name": "value" + }, + "right": { + "type": "Literal", + "start": 73, + "end": 82, + "loc": { + "start": { + "line": 5, + "column": 29 + }, + "end": { + "line": 5, + "column": 38 + } + }, + "value": "default", + "raw": "'default'" + } + } + ] + } + } + ] + }, + "options": null, + "instance": { + "type": "Script", + "start": 0, + "end": 43, + "context": "default", + "content": { + "type": "Program", + "start": 18, + "end": 34, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 0 + } + }, + "body": [ + { + "type": "VariableDeclaration", + "start": 20, + "end": 33, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 14 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 24, + "end": 32, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 13 + } + }, + "id": { + "type": "Identifier", + "start": 24, + "end": 27, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 8 + } + }, + "name": "arr" + }, + "init": { + "type": "ArrayExpression", + "start": 30, + "end": 32, + "loc": { + "start": { + "line": 2, + "column": 11 + }, + "end": { + "line": 2, + "column": 13 + } + }, + "elements": [] + } + } + ], + "kind": "let" + } + ], + "sourceType": "module" + }, + "attributes": [ + { + "type": "Attribute", + "start": 8, + "end": 17, + "name": "lang", + "value": [ + { + "start": 14, + "end": 16, + "type": "Text", + "raw": "ts", + "data": "ts" + } + ] + } + ] + } +} From 2e2b440954a783a836e803f7b2babc054a1a33ad Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Mon, 6 Jan 2025 16:51:32 +0100 Subject: [PATCH 13/63] fix: apply `clsx` logic to custom element `class` attributes (#14907) Fixes #14902 --- .changeset/happy-candles-clean.md | 5 +++++ .../3-transform/client/visitors/RegularElement.js | 12 +++++++++++- .../tests/runtime-runes/samples/clsx/_config.js | 14 ++++++++++---- .../tests/runtime-runes/samples/clsx/main.svelte | 2 ++ 4 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 .changeset/happy-candles-clean.md diff --git a/.changeset/happy-candles-clean.md b/.changeset/happy-candles-clean.md new file mode 100644 index 0000000000..d08f97a247 --- /dev/null +++ b/.changeset/happy-candles-clean.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: apply `clsx` logic to custom element `class` attributes diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js index 59a6fafbc5..ffd06dfd86 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js @@ -571,7 +571,9 @@ function build_element_attribute_update_assignment( is_svg ? '$.set_svg_class' : is_mathml ? '$.set_mathml_class' : '$.set_class', node_id, value, - attribute.metadata.needs_clsx ? b.literal(context.state.analysis.css.hash) : undefined + attribute.metadata.needs_clsx && context.state.analysis.css.hash + ? b.literal(context.state.analysis.css.hash) + : undefined ) ); } else if (name === 'value') { @@ -648,6 +650,14 @@ function build_custom_element_attribute_update_assignment(node_id, attribute, co const name = attribute.name; // don't lowercase, as we set the element's property, which might be case sensitive let { has_call, value } = build_attribute_value(attribute.value, context); + // We assume that noone's going to redefine the semantics of the class attribute on custom elements, i.e. it's still used for CSS classes + if (name === 'class' && attribute.metadata.needs_clsx) { + if (context.state.analysis.css.hash) { + value = b.array([value, b.literal(context.state.analysis.css.hash)]); + } + value = b.call('$.clsx', value); + } + const update = b.stmt(b.call('$.set_custom_element_data', node_id, b.literal(name), value)); if (attribute.metadata.expression.has_state) { diff --git a/packages/svelte/tests/runtime-runes/samples/clsx/_config.js b/packages/svelte/tests/runtime-runes/samples/clsx/_config.js index e0813d0e6c..202a13b1cb 100644 --- a/packages/svelte/tests/runtime-runes/samples/clsx/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/clsx/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ @@ -14,27 +15,32 @@ export default test({
child
child
+ + `, test({ assert, target }) { const button = target.querySelector('button'); button?.click(); + flushSync(); assert.htmlEqual( target.innerHTML, `
-
-
+
+
child
child
+
child
+
child
child
-
child
-
child
+ + ` diff --git a/packages/svelte/tests/runtime-runes/samples/clsx/main.svelte b/packages/svelte/tests/runtime-runes/samples/clsx/main.svelte index bf68b42e11..ebc0697f97 100644 --- a/packages/svelte/tests/runtime-runes/samples/clsx/main.svelte +++ b/packages/svelte/tests/runtime-runes/samples/clsx/main.svelte @@ -18,6 +18,8 @@ + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-runes/samples/bindable-prop-and-export/_config.js b/packages/svelte/tests/runtime-runes/samples/bindable-prop-and-export/_config.js new file mode 100644 index 0000000000..45cd58f55c --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/bindable-prop-and-export/_config.js @@ -0,0 +1,35 @@ +import { ok, test } from '../../test'; +import { flushSync } from 'svelte'; + +export default test({ + compileOptions: { + dev: true + }, + html: ``, + ssrHtml: ``, + + async test({ assert, target, instance }) { + const [btn1, btn2] = target.querySelectorAll('button'); + const input = target.querySelector('input'); + flushSync(() => { + btn1.click(); + }); + assert.equal(btn1.innerHTML, 'false'); + assert.equal(btn2.innerHTML, 'false'); + assert.equal(input?.checked, false); + + flushSync(() => { + btn2.click(); + }); + assert.equal(btn1.innerHTML, 'true'); + assert.equal(btn2.innerHTML, 'true'); + assert.equal(input?.checked, true); + + flushSync(() => { + input?.click(); + }); + assert.equal(btn1.innerHTML, 'false'); + assert.equal(btn2.innerHTML, 'false'); + assert.equal(input?.checked, false); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/bindable-prop-and-export/main.svelte b/packages/svelte/tests/runtime-runes/samples/bindable-prop-and-export/main.svelte new file mode 100644 index 0000000000..3b47eef156 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/bindable-prop-and-export/main.svelte @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file From fb67bad5b04a96e416b7896f031353e18b660acb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 18:28:50 -0500 Subject: [PATCH 23/63] Version Packages (#14921) Co-authored-by: github-actions[bot] --- .changeset/real-onions-confess.md | 5 ----- .changeset/tidy-dragons-thank.md | 5 ----- packages/svelte/CHANGELOG.md | 8 ++++++++ packages/svelte/package.json | 2 +- packages/svelte/src/version.js | 2 +- 5 files changed, 10 insertions(+), 12 deletions(-) delete mode 100644 .changeset/real-onions-confess.md delete mode 100644 .changeset/tidy-dragons-thank.md diff --git a/.changeset/real-onions-confess.md b/.changeset/real-onions-confess.md deleted file mode 100644 index 5f11b225ad..0000000000 --- a/.changeset/real-onions-confess.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: inherit correct namespace for `` elements diff --git a/.changeset/tidy-dragons-thank.md b/.changeset/tidy-dragons-thank.md deleted file mode 100644 index 1257ec0210..0000000000 --- a/.changeset/tidy-dragons-thank.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: don't throw `bind_invalid_export` if there's also a bindable prop with the same name diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index 43898eb107..cc834a7ca3 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,13 @@ # svelte +## 5.16.5 + +### Patch Changes + +- fix: inherit correct namespace for `<title>` elements ([#14817](https://github.com/sveltejs/svelte/pull/14817)) + +- fix: don't throw `bind_invalid_export` if there's also a bindable prop with the same name ([#14813](https://github.com/sveltejs/svelte/pull/14813)) + ## 5.16.4 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 59bc861560..682cf30fb3 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -2,7 +2,7 @@ "name": "svelte", "description": "Cybernetically enhanced web apps", "license": "MIT", - "version": "5.16.4", + "version": "5.16.5", "type": "module", "types": "./types/index.d.ts", "engines": { diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js index b51c659b31..d4fd729b38 100644 --- a/packages/svelte/src/version.js +++ b/packages/svelte/src/version.js @@ -4,5 +4,5 @@ * The current version, as set in package.json. * @type {string} */ -export const VERSION = '5.16.4'; +export const VERSION = '5.16.5'; export const PUBLIC_VERSION = '5'; From 8201d7ad8b4e90f420aefbfe5f0f94fe860a0578 Mon Sep 17 00:00:00 2001 From: Felipe <felipe.santoz2013@gmail.com> Date: Tue, 7 Jan 2025 00:41:06 +0000 Subject: [PATCH 24/63] docs: Switch typing of Action<Parameter> from null to undefined in 12-use.md (#14798) * Update 12-use.md - * Remove unecessary line in Action typing example * drive-by formatting fix --------- Co-authored-by: Rich Harris <rich.harris@vercel.com> --- documentation/docs/03-template-syntax/12-use.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/documentation/docs/03-template-syntax/12-use.md b/documentation/docs/03-template-syntax/12-use.md index f3db72a772..45de023578 100644 --- a/documentation/docs/03-template-syntax/12-use.md +++ b/documentation/docs/03-template-syntax/12-use.md @@ -50,17 +50,16 @@ The `Action` interface receives three optional type arguments — a node type (w ```svelte <!--- file: App.svelte ---> <script> - import { on } from 'svelte/events'; - /** * @type {import('svelte/action').Action< * HTMLDivElement, - * null, + * undefined, * { * onswiperight: (e: CustomEvent) => void; * onswipeleft: (e: CustomEvent) => void; * // ... - * }>} + * } + * >} */ function gestures(node) { $effect(() => { From 08a9d123e81725189e727b18b1f99662ec2a48c8 Mon Sep 17 00:00:00 2001 From: Rich Harris <rich.harris@vercel.com> Date: Tue, 7 Jan 2025 09:01:44 +0000 Subject: [PATCH 25/63] chore: use codePointAt instead of implementing it ourselves (#14923) seems to be some sort of codePointAt polyfill from ancient times before that was available on String.prototype --- .../src/compiler/phases/1-parse/index.js | 5 +- .../compiler/phases/1-parse/read/context.js | 44 ++++++++-------- .../compiler/phases/1-parse/utils/bracket.js | 50 +++++++------------ .../phases/1-parse/utils/full_char_code_at.js | 15 ------ 4 files changed, 41 insertions(+), 73 deletions(-) delete mode 100644 packages/svelte/src/compiler/phases/1-parse/utils/full_char_code_at.js diff --git a/packages/svelte/src/compiler/phases/1-parse/index.js b/packages/svelte/src/compiler/phases/1-parse/index.js index 390919f5cd..6cc5b58aa6 100644 --- a/packages/svelte/src/compiler/phases/1-parse/index.js +++ b/packages/svelte/src/compiler/phases/1-parse/index.js @@ -3,7 +3,6 @@ import { isIdentifierStart, isIdentifierChar } from 'acorn'; import fragment from './state/fragment.js'; import { regex_whitespace } from '../patterns.js'; -import full_char_code_at from './utils/full_char_code_at.js'; import * as e from '../../errors.js'; import { create_fragment } from './utils/create.js'; import read_options from './read/options.js'; @@ -230,13 +229,13 @@ export class Parser { let i = this.index; - const code = full_char_code_at(this.template, i); + const code = /** @type {number} */ (this.template.codePointAt(i)); if (!isIdentifierStart(code, true)) return null; i += code <= 0xffff ? 1 : 2; while (i < this.template.length) { - const code = full_char_code_at(this.template, i); + const code = /** @type {number} */ (this.template.codePointAt(i)); if (!isIdentifierChar(code, true)) break; i += code <= 0xffff ? 1 : 2; diff --git a/packages/svelte/src/compiler/phases/1-parse/read/context.js b/packages/svelte/src/compiler/phases/1-parse/read/context.js index e408b5024f..e206701500 100644 --- a/packages/svelte/src/compiler/phases/1-parse/read/context.js +++ b/packages/svelte/src/compiler/phases/1-parse/read/context.js @@ -1,15 +1,7 @@ /** @import { Location } from 'locate-character' */ /** @import { Pattern } from 'estree' */ /** @import { Parser } from '../index.js' */ -// @ts-expect-error acorn type definitions are borked in the release we use -import { isIdentifierStart } from 'acorn'; -import full_char_code_at from '../utils/full_char_code_at.js'; -import { - is_bracket_open, - is_bracket_close, - is_bracket_pair, - get_bracket_close -} from '../utils/bracket.js'; +import { is_bracket_open, is_bracket_close, get_bracket_close } from '../utils/bracket.js'; import { parse_expression_at } from '../acorn.js'; import { regex_not_newline_characters } from '../../patterns.js'; import * as e from '../../../errors.js'; @@ -23,9 +15,9 @@ export default function read_pattern(parser) { const start = parser.index; let i = parser.index; - const code = full_char_code_at(parser.template, i); - if (isIdentifierStart(code, true)) { - const name = /** @type {string} */ (parser.read_identifier()); + const name = parser.read_identifier(); + + if (name !== null) { const annotation = read_type_annotation(parser); return { @@ -41,28 +33,32 @@ export default function read_pattern(parser) { }; } - if (!is_bracket_open(code)) { + if (!is_bracket_open(parser.template[i])) { e.expected_pattern(i); } - const bracket_stack = [code]; - i += code <= 0xffff ? 1 : 2; + /** @type {string[]} */ + const bracket_stack = []; while (i < parser.template.length) { - const code = full_char_code_at(parser.template, i); - if (is_bracket_open(code)) { - bracket_stack.push(code); - } else if (is_bracket_close(code)) { - const popped = /** @type {number} */ (bracket_stack.pop()); - if (!is_bracket_pair(popped, code)) { - e.expected_token(i, String.fromCharCode(/** @type {number} */ (get_bracket_close(popped)))); + const char = parser.template[i]; + + if (is_bracket_open(char)) { + bracket_stack.push(char); + } else if (is_bracket_close(char)) { + const popped = /** @type {string} */ (bracket_stack.pop()); + const expected = /** @type {string} */ (get_bracket_close(popped)); + + if (char !== expected) { + e.expected_token(i, expected); } + if (bracket_stack.length === 0) { - i += code <= 0xffff ? 1 : 2; + i += 1; break; } } - i += code <= 0xffff ? 1 : 2; + i += 1; } parser.index = i; diff --git a/packages/svelte/src/compiler/phases/1-parse/utils/bracket.js b/packages/svelte/src/compiler/phases/1-parse/utils/bracket.js index e7576af955..b7c8cb43cd 100644 --- a/packages/svelte/src/compiler/phases/1-parse/utils/bracket.js +++ b/packages/svelte/src/compiler/phases/1-parse/utils/bracket.js @@ -1,41 +1,30 @@ -import full_char_code_at from './full_char_code_at.js'; +const SQUARE_BRACKET_OPEN = '['; +const SQUARE_BRACKET_CLOSE = ']'; +const CURLY_BRACKET_OPEN = '{'; +const CURLY_BRACKET_CLOSE = '}'; +const PARENTHESES_OPEN = '('; +const PARENTHESES_CLOSE = ')'; -const SQUARE_BRACKET_OPEN = '['.charCodeAt(0); -const SQUARE_BRACKET_CLOSE = ']'.charCodeAt(0); -const CURLY_BRACKET_OPEN = '{'.charCodeAt(0); -const CURLY_BRACKET_CLOSE = '}'.charCodeAt(0); -const PARENTHESES_OPEN = '('.charCodeAt(0); -const PARENTHESES_CLOSE = ')'.charCodeAt(0); - -/** @param {number} code */ -export function is_bracket_open(code) { - return code === SQUARE_BRACKET_OPEN || code === CURLY_BRACKET_OPEN; +/** @param {string} char */ +export function is_bracket_open(char) { + return char === SQUARE_BRACKET_OPEN || char === CURLY_BRACKET_OPEN; } -/** @param {number} code */ -export function is_bracket_close(code) { - return code === SQUARE_BRACKET_CLOSE || code === CURLY_BRACKET_CLOSE; +/** @param {string} char */ +export function is_bracket_close(char) { + return char === SQUARE_BRACKET_CLOSE || char === CURLY_BRACKET_CLOSE; } -/** - * @param {number} open - * @param {number} close - */ -export function is_bracket_pair(open, close) { - return ( - (open === SQUARE_BRACKET_OPEN && close === SQUARE_BRACKET_CLOSE) || - (open === CURLY_BRACKET_OPEN && close === CURLY_BRACKET_CLOSE) - ); -} - -/** @param {number} open */ +/** @param {string} open */ export function get_bracket_close(open) { if (open === SQUARE_BRACKET_OPEN) { return SQUARE_BRACKET_CLOSE; } + if (open === CURLY_BRACKET_OPEN) { return CURLY_BRACKET_CLOSE; } + if (open === PARENTHESES_OPEN) { return PARENTHESES_CLOSE; } @@ -132,8 +121,7 @@ function count_leading_backslashes(string, search_start_index) { * @returns {number | undefined} The index of the closing bracket, or undefined if not found. */ export function find_matching_bracket(template, index, open) { - const open_code = full_char_code_at(open, 0); - const close_code = get_bracket_close(open_code); + const close = get_bracket_close(open); let brackets = 1; let i = index; while (brackets > 0 && i < template.length) { @@ -159,10 +147,10 @@ export function find_matching_bracket(template, index, open) { continue; } default: { - const code = full_char_code_at(template, i); - if (code === open_code) { + const char = template[i]; + if (char === open) { brackets++; - } else if (code === close_code) { + } else if (char === close) { brackets--; } if (brackets === 0) { diff --git a/packages/svelte/src/compiler/phases/1-parse/utils/full_char_code_at.js b/packages/svelte/src/compiler/phases/1-parse/utils/full_char_code_at.js deleted file mode 100644 index 90e6b8def3..0000000000 --- a/packages/svelte/src/compiler/phases/1-parse/utils/full_char_code_at.js +++ /dev/null @@ -1,15 +0,0 @@ -// Adapted from https://github.com/acornjs/acorn/blob/6584815dca7440e00de841d1dad152302fdd7ca5/src/tokenize.js -// Reproduced under MIT License https://github.com/acornjs/acorn/blob/master/LICENSE - -/** - * @param {string} str - * @param {number} i - * @returns {number} - */ -export default function full_char_code_at(str, i) { - const code = str.charCodeAt(i); - if (code <= 0xd7ff || code >= 0xe000) return code; - - const next = str.charCodeAt(i + 1); - return (code << 10) + next - 0x35fdc00; -} From 77378688b9b3cb5047e0b33bf6ab630e2d62a85d Mon Sep 17 00:00:00 2001 From: Rich Harris <rich.harris@vercel.com> Date: Tue, 7 Jan 2025 10:06:11 +0000 Subject: [PATCH 26/63] fix: remove leading newline from `<pre>` contents (#14922) ... if it's not followed by another newline, according to the spec Fixes #14767 --------- Co-authored-by: Simon Holthausen <simon.holthausen@vercel.com> --- .changeset/tricky-radios-vanish.md | 5 ++++ .../src/compiler/phases/3-transform/utils.js | 17 ++++++++++++++ .../samples/pre-first-node-newline/_config.js | 5 ++++ .../pre-first-node-newline/_expected.html | 7 ++++++ .../pre-first-node-newline/main.svelte | 23 +++++++++++++++++++ .../runtime-legacy/samples/pre-tag/_config.js | 18 ++++----------- 6 files changed, 62 insertions(+), 13 deletions(-) create mode 100644 .changeset/tricky-radios-vanish.md create mode 100644 packages/svelte/tests/hydration/samples/pre-first-node-newline/_config.js create mode 100644 packages/svelte/tests/hydration/samples/pre-first-node-newline/_expected.html create mode 100644 packages/svelte/tests/hydration/samples/pre-first-node-newline/main.svelte diff --git a/.changeset/tricky-radios-vanish.md b/.changeset/tricky-radios-vanish.md new file mode 100644 index 0000000000..0935148fba --- /dev/null +++ b/.changeset/tricky-radios-vanish.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: remove leading newline from `<pre>` contents diff --git a/packages/svelte/src/compiler/phases/3-transform/utils.js b/packages/svelte/src/compiler/phases/3-transform/utils.js index b53a3110bd..62a635de35 100644 --- a/packages/svelte/src/compiler/phases/3-transform/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/utils.js @@ -5,6 +5,7 @@ import { regex_ends_with_whitespaces, regex_not_whitespace, + regex_starts_with_newline, regex_starts_with_whitespaces } from '../patterns.js'; import * as b from '../../utils/builders.js'; @@ -270,6 +271,22 @@ export function clean_nodes( var first = trimmed[0]; + // initial newline inside a `<pre>` is disregarded, if not followed by another newline + if (parent.type === 'RegularElement' && parent.name === 'pre' && first.type === 'Text') { + const text = first.data.replace(regex_starts_with_newline, ''); + if (text !== first.data) { + const tmp = text.replace(regex_starts_with_newline, ''); + if (text === tmp) { + first.data = text; + first.raw = first.raw.replace(regex_starts_with_newline, ''); + if (first.data === '') { + trimmed.shift(); + first = trimmed[0]; + } + } + } + } + // Special case: Add a comment if this is a lone script tag. This ensures that our run_scripts logic in template.js // will always be able to call node.replaceWith() on the script tag in order to make it run. If we don't add this // and would still call node.replaceWith() on the script tag, it would be a no-op because the script tag has no parent. diff --git a/packages/svelte/tests/hydration/samples/pre-first-node-newline/_config.js b/packages/svelte/tests/hydration/samples/pre-first-node-newline/_config.js new file mode 100644 index 0000000000..c838aab749 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/pre-first-node-newline/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +// A note about _expected.html: It is different from body.html because we're +// testing against target.innerHTML which already removed the redundant first newline +export default test({}); diff --git a/packages/svelte/tests/hydration/samples/pre-first-node-newline/_expected.html b/packages/svelte/tests/hydration/samples/pre-first-node-newline/_expected.html new file mode 100644 index 0000000000..26de34d1ed --- /dev/null +++ b/packages/svelte/tests/hydration/samples/pre-first-node-newline/_expected.html @@ -0,0 +1,7 @@ +<!--[--><pre>static content no line</pre> <pre> static content ignored line +</pre> <pre> + static content relevant line +</pre> <pre><div><span></span></div> +</pre> <pre> +<div><span></span></div> +</pre><!--]--> diff --git a/packages/svelte/tests/hydration/samples/pre-first-node-newline/main.svelte b/packages/svelte/tests/hydration/samples/pre-first-node-newline/main.svelte new file mode 100644 index 0000000000..9764b49e99 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/pre-first-node-newline/main.svelte @@ -0,0 +1,23 @@ +<script> + let name = $state(''); +</script> + +<pre>static content no line</pre> + +<pre> + static content ignored line +</pre> + +<pre> + + static content relevant line +</pre> + +<pre> +<div><span>{name}</span></div> +</pre> + +<pre> + +<div><span>{name}</span></div> +</pre> diff --git a/packages/svelte/tests/runtime-legacy/samples/pre-tag/_config.js b/packages/svelte/tests/runtime-legacy/samples/pre-tag/_config.js index f1a42e996a..d7e1fe9d43 100644 --- a/packages/svelte/tests/runtime-legacy/samples/pre-tag/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/pre-tag/_config.js @@ -2,17 +2,9 @@ import { test } from '../../test'; export default test({ mode: ['client', 'server'], // output is correct, but test suite chokes on the extra ssr comment which is harmless - withoutNormalizeHtml: true, - html: get_html(false), - ssrHtml: get_html(true) -}); - -/** @param {boolean} ssr */ -function get_html(ssr) { - // ssr rendered HTML has an extra newline prefixed within `<pre>` tag, - // if the <pre> tag starts with `\n` - // because when browser parses the SSR rendered HTML, it will ignore the 1st '\n' character - return `${ssr ? '<!--[-->' : ''}<pre id="pre"> A + withoutNormalizeHtml: 'only-strip-comments', // because whitespace inside pre tags is significant + // Note how we're testing against target.innerHTML which already removed the redundant first newline + html: `<pre id="pre"> A B <span> C @@ -35,5 +27,5 @@ function get_html(ssr) { leading newlines</pre></div> <div id="pre-without-leading-newline"><pre>without spaces</pre> <pre> with spaces </pre> <pre>${' '} newline after leading space</pre></div> <pre id="pre-with-multiple-leading-newlines"> -multiple leading newlines</pre>${ssr ? '<!--]-->' : ''}`; -} +multiple leading newlines</pre>` +}); From a1f371e78656f951ad75945493a798716ecc92c4 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Tue, 7 Jan 2025 18:06:12 +0100 Subject: [PATCH 27/63] docs: add code of files being tested (#14925) * docs: add code of files being tested closes #14900 * fix * Apply suggestions from code review Co-authored-by: Rich Harris <rich.harris@vercel.com> * Update documentation/docs/07-misc/02-testing.md Co-authored-by: Rich Harris <rich.harris@vercel.com> * Apply suggestions from code review Co-authored-by: Rich Harris <rich.harris@vercel.com> * rename import * from https://github.com/sveltejs/svelte.dev/pull/1094 --------- Co-authored-by: Rich Harris <rich.harris@vercel.com> --- documentation/docs/02-runes/02-$state.md | 7 +-- documentation/docs/07-misc/02-testing.md | 61 +++++++++++++++++++++++- 2 files changed, 60 insertions(+), 8 deletions(-) diff --git a/documentation/docs/02-runes/02-$state.md b/documentation/docs/02-runes/02-$state.md index 77140dc690..49e17cd08f 100644 --- a/documentation/docs/02-runes/02-$state.md +++ b/documentation/docs/02-runes/02-$state.md @@ -44,12 +44,7 @@ todos[0].done = !todos[0].done; If you push a new object to the array, it will also be proxified: ```js -// @filename: ambient.d.ts -declare global { - const todos: Array<{ done: boolean, text: string }> -} - -// @filename: index.js +let todos = [{ done: false, text: 'add more todos' }]; // ---cut--- todos.push({ done: false, diff --git a/documentation/docs/07-misc/02-testing.md b/documentation/docs/07-misc/02-testing.md index c8774e341f..0842019039 100644 --- a/documentation/docs/07-misc/02-testing.md +++ b/documentation/docs/07-misc/02-testing.md @@ -40,7 +40,7 @@ You can now write unit tests for code inside your `.js/.ts` files: /// file: multiplier.svelte.test.js import { flushSync } from 'svelte'; import { expect, test } from 'vitest'; -import { multiplier } from './multiplier.js'; +import { multiplier } from './multiplier.svelte.js'; test('Multiplier', () => { let double = multiplier(0, 2); @@ -53,9 +53,30 @@ test('Multiplier', () => { }); ``` +```js +/// file: multiplier.svelte.js +/** + * @param {number} initial + * @param {number} k + */ +export function multiplier(initial, k) { + let count = $state(initial); + + return { + get value() { + return count * k; + }, + /** @param {number} c */ + set: (c) => { + count = c; + } + }; +} +``` + ### Using runes inside your test files -It is possible to use runes inside your test files. First ensure your bundler knows to route the file through the Svelte compiler before running the test by adding `.svelte` to the filename (e.g `multiplier.svelte.test.js`). After that, you can use runes inside your tests. +Since Vitest processes your test files the same way as your source files, you can use runes inside your tests as long as the filename includes `.svelte`: ```js /// file: multiplier.svelte.test.js @@ -75,6 +96,21 @@ test('Multiplier', () => { }); ``` +```js +/// file: multiplier.svelte.js +/** + * @param {() => number} getCount + * @param {number} k + */ +export function multiplier(getCount, k) { + return { + get value() { + return getCount() * k; + } + }; +} +``` + If the code being tested uses effects, you need to wrap the test inside `$effect.root`: ```js @@ -105,6 +141,27 @@ test('Effect', () => { }); ``` +```js +/// file: logger.svelte.js +/** + * @param {() => any} getValue + */ +export function logger(getValue) { + /** @type {any[]} */ + let log = $state([]); + + $effect(() => { + log.push(getValue()); + }); + + return { + get value() { + return log; + } + }; +} +``` + ### Component testing It is possible to test your components in isolation using Vitest. From c8865bb4a70ac026b1e85c4f8e8491f2e354ce7b Mon Sep 17 00:00:00 2001 From: Matthijs <42407879+TheSpeedM@users.noreply.github.com> Date: Tue, 7 Jan 2025 20:24:26 +0100 Subject: [PATCH 28/63] fix: make Tween with duration 0 set current to target immediately (#14937) * fix: Make Tween duration 0 set current to target immediately * Run prettier on test file * tweak --------- Co-authored-by: Rich Harris <rich.harris@vercel.com> --- .changeset/cold-cups-act.md | 5 +++++ packages/svelte/src/motion/tweened.js | 11 ++++++++--- packages/svelte/tests/motion/test.ts | 18 +++++++++++++++++- 3 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 .changeset/cold-cups-act.md diff --git a/.changeset/cold-cups-act.md b/.changeset/cold-cups-act.md new file mode 100644 index 0000000000..6776d4eef3 --- /dev/null +++ b/.changeset/cold-cups-act.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: Make Tween duration 0 set current to target immediately diff --git a/packages/svelte/src/motion/tweened.js b/packages/svelte/src/motion/tweened.js index 8aaefe5a2c..36d32d1f72 100644 --- a/packages/svelte/src/motion/tweened.js +++ b/packages/svelte/src/motion/tweened.js @@ -230,9 +230,6 @@ export class Tween { set(value, options) { set(this.#target, value); - let previous_task = this.#task; - - let started = false; let { delay = 0, duration = 400, @@ -240,10 +237,18 @@ export class Tween { interpolate = get_interpolator } = { ...this.#defaults, ...options }; + if (duration === 0) { + this.#task?.abort(); + set(this.#current, value); + return Promise.resolve(); + } + const start = raf.now() + delay; /** @type {(t: number) => T} */ let fn; + let started = false; + let previous_task = this.#task; this.#task = loop((now) => { if (now < start) { diff --git a/packages/svelte/tests/motion/test.ts b/packages/svelte/tests/motion/test.ts index b6554e5e56..7d845bac3d 100644 --- a/packages/svelte/tests/motion/test.ts +++ b/packages/svelte/tests/motion/test.ts @@ -2,7 +2,7 @@ import '../helpers.js'; // for the matchMedia polyfill import { describe, it, assert } from 'vitest'; import { get } from 'svelte/store'; -import { spring, tweened } from 'svelte/motion'; +import { spring, tweened, Tween } from 'svelte/motion'; describe('motion', () => { describe('spring', () => { @@ -39,4 +39,20 @@ describe('motion', () => { assert.equal(get(size), 20); }); }); + + describe('Tween', () => { + it('sets immediately when duration is 0', () => { + const size = new Tween(0); + + size.set(100, { duration: 0 }); + assert.equal(size.current, 100); + }); + }); + + it('updates correctly when initialized with a `null`-ish value', () => { + const size = new Tween(undefined as unknown as number, { duration: 0 }); + + size.set(10); + assert.equal(size.current, 10); + }); }); From 8241096b06d5dfb2fc5374ce704e6b30c01e26dd Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Tue, 7 Jan 2025 20:24:53 +0100 Subject: [PATCH 29/63] fix: treat `inert` as a boolean attribute (#14935) * fix: treat `inert` as a boolean attribute fixes #14731 * remove solo: true --------- Co-authored-by: Rich Harris <rich.harris@vercel.com> --- .changeset/quiet-planets-carry.md | 5 +++++ packages/svelte/src/utils.js | 2 +- .../samples/attribute-boolean-inert/_config.js | 17 ++++++++++++----- .../samples/attribute-boolean-inert/main.svelte | 1 + 4 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 .changeset/quiet-planets-carry.md diff --git a/.changeset/quiet-planets-carry.md b/.changeset/quiet-planets-carry.md new file mode 100644 index 0000000000..0abeffa2e8 --- /dev/null +++ b/.changeset/quiet-planets-carry.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: treat `inert` as a boolean attribute diff --git a/packages/svelte/src/utils.js b/packages/svelte/src/utils.js index e42721b4f4..76486d32ac 100644 --- a/packages/svelte/src/utils.js +++ b/packages/svelte/src/utils.js @@ -156,6 +156,7 @@ const DOM_BOOLEAN_ATTRIBUTES = [ 'formnovalidate', 'hidden', 'indeterminate', + 'inert', 'ismap', 'loop', 'multiple', @@ -214,7 +215,6 @@ const DOM_PROPERTIES = [ 'playsInline', 'readOnly', 'value', - 'inert', 'volume', 'defaultValue', 'defaultChecked', diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-inert/_config.js b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-inert/_config.js index 1322d63b7a..26fbbc955b 100644 --- a/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-inert/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-inert/_config.js @@ -1,14 +1,21 @@ -import { ok, test } from '../../test'; +import { test } from '../../test'; export default test({ + ssrHtml: ` + <div></div> + <div inert="">some div <button>click</button></div> + `, + get props() { return { inert: true }; }, + test({ assert, target, component }) { - const div = target.querySelector('div'); - ok(div); - assert.ok(div.inert); + const [div1, div2] = target.querySelectorAll('div'); + assert.ok(!div1.inert); + assert.ok(div2.inert); + component.inert = false; - assert.ok(!div.inert); + assert.ok(!div2.inert); } }); diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-inert/main.svelte b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-inert/main.svelte index 6c3df7e31e..3b97923713 100644 --- a/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-inert/main.svelte +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-inert/main.svelte @@ -2,4 +2,5 @@ export let inert; </script> +<div inert={false}></div> <div {inert}>some div <button>click</button></div> From 34628b9c90170cf84be64bfcc18adf88623a8aa4 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Tue, 7 Jan 2025 20:25:29 +0100 Subject: [PATCH 30/63] docs: note custom elements on caveat (#14934) closes #14727 --- documentation/docs/07-misc/04-custom-elements.md | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/docs/07-misc/04-custom-elements.md b/documentation/docs/07-misc/04-custom-elements.md index 71c66f7edc..a8e0c81763 100644 --- a/documentation/docs/07-misc/04-custom-elements.md +++ b/documentation/docs/07-misc/04-custom-elements.md @@ -125,3 +125,4 @@ Custom elements can be a useful way to package components for consumption in a n - The deprecated `let:` directive has no effect, because custom elements do not have a way to pass data to the parent component that fills the slot - Polyfills are required to support older browsers - You can use Svelte's context feature between regular Svelte components within a custom element, but you can't use them across custom elements. In other words, you can't use `setContext` on a parent custom element and read that with `getContext` in a child custom element. +- Don't declare properties or attributes starting with `on`, as their usage will be interpreted as an event listener. In other words, Svelte treats `<custom-element oneworld={true}></custom-element>` as `customElement.addEventListener('eworld', true)` (and not as `customElement.oneworld = true`) From 08061c85da6c2c2d5d11d6cdad0a9d387042a784 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Tue, 7 Jan 2025 20:26:13 +0100 Subject: [PATCH 31/63] fix: guard against `customElements` being unavailable in browser extension contexts (#14933) fixes #14739 --- .changeset/forty-books-taste.md | 5 +++++ .../svelte/src/internal/client/dom/elements/attributes.js | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 .changeset/forty-books-taste.md diff --git a/.changeset/forty-books-taste.md b/.changeset/forty-books-taste.md new file mode 100644 index 0000000000..e2474c635f --- /dev/null +++ b/.changeset/forty-books-taste.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: guard against `customElements` being unavailable in browser extension contexts diff --git a/packages/svelte/src/internal/client/dom/elements/attributes.js b/packages/svelte/src/internal/client/dom/elements/attributes.js index 6656532986..a2fffe8696 100644 --- a/packages/svelte/src/internal/client/dom/elements/attributes.js +++ b/packages/svelte/src/internal/client/dom/elements/attributes.js @@ -221,7 +221,10 @@ export function set_custom_element_data(node, prop, value) { // Don't compute setters for custom elements while they aren't registered yet, // because during their upgrade/instantiation they might add more setters. // Instead, fall back to a simple "an object, then set as property" heuristic. - setters_cache.has(node.nodeName) || customElements.get(node.tagName.toLowerCase()) + setters_cache.has(node.nodeName) || + // customElements may not be available in browser extension contexts + !customElements || + customElements.get(node.tagName.toLowerCase()) ? get_setters(node).includes(prop) : value && typeof value === 'object' ) { From 19038d19cb89cb100a6820069447e6d6eb22b612 Mon Sep 17 00:00:00 2001 From: Rich Harris <rich.harris@vercel.com> Date: Tue, 7 Jan 2025 20:27:03 +0000 Subject: [PATCH 32/63] docs: add section on update propagation (#14938) --- documentation/docs/02-runes/03-$derived.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/documentation/docs/02-runes/03-$derived.md b/documentation/docs/02-runes/03-$derived.md index 6b38f99746..24ab643b68 100644 --- a/documentation/docs/02-runes/03-$derived.md +++ b/documentation/docs/02-runes/03-$derived.md @@ -51,3 +51,20 @@ In essence, `$derived(expression)` is equivalent to `$derived.by(() => expressio Anything read synchronously inside the `$derived` expression (or `$derived.by` function body) is considered a _dependency_ of the derived state. When the state changes, the derived will be marked as _dirty_ and recalculated when it is next read. To exempt a piece of state from being treated as a dependency, use [`untrack`](svelte#untrack). + +## Update propagation + +Svelte uses something called _push-pull reactivity_ — when state is updated, everything that depends on the state (whether directly or indirectly) is immediately notified of the change (the 'push'), but derived values are not re-evaluated until they are actually read (the 'pull'). + +If the new value of a derived is referentially identical to its previous value, downstream updates will be skipped. In other words, Svelte will only update the text inside the button when `large` changes, not when `count` changes, even though `large` depends on `count`: + +```svelte +<script> + let count = $state(0); + let large = $derived(count > 10); +</script> + +<button onclick={() => count++}> + {large} +</button> +``` From 4aadb34c02dc6afce56bb0f66bbac117ac56c4e8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 7 Jan 2025 15:30:56 -0500 Subject: [PATCH 33/63] Version Packages (#14924) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> --- .changeset/cold-cups-act.md | 5 ----- .changeset/forty-books-taste.md | 5 ----- .changeset/quiet-planets-carry.md | 5 ----- .changeset/tricky-radios-vanish.md | 5 ----- packages/svelte/CHANGELOG.md | 12 ++++++++++++ packages/svelte/package.json | 2 +- packages/svelte/src/version.js | 2 +- 7 files changed, 14 insertions(+), 22 deletions(-) delete mode 100644 .changeset/cold-cups-act.md delete mode 100644 .changeset/forty-books-taste.md delete mode 100644 .changeset/quiet-planets-carry.md delete mode 100644 .changeset/tricky-radios-vanish.md diff --git a/.changeset/cold-cups-act.md b/.changeset/cold-cups-act.md deleted file mode 100644 index 6776d4eef3..0000000000 --- a/.changeset/cold-cups-act.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: Make Tween duration 0 set current to target immediately diff --git a/.changeset/forty-books-taste.md b/.changeset/forty-books-taste.md deleted file mode 100644 index e2474c635f..0000000000 --- a/.changeset/forty-books-taste.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: guard against `customElements` being unavailable in browser extension contexts diff --git a/.changeset/quiet-planets-carry.md b/.changeset/quiet-planets-carry.md deleted file mode 100644 index 0abeffa2e8..0000000000 --- a/.changeset/quiet-planets-carry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: treat `inert` as a boolean attribute diff --git a/.changeset/tricky-radios-vanish.md b/.changeset/tricky-radios-vanish.md deleted file mode 100644 index 0935148fba..0000000000 --- a/.changeset/tricky-radios-vanish.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: remove leading newline from `<pre>` contents diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index cc834a7ca3..4a2cca8280 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,17 @@ # svelte +## 5.16.6 + +### Patch Changes + +- fix: Make Tween duration 0 set current to target immediately ([#14937](https://github.com/sveltejs/svelte/pull/14937)) + +- fix: guard against `customElements` being unavailable in browser extension contexts ([#14933](https://github.com/sveltejs/svelte/pull/14933)) + +- fix: treat `inert` as a boolean attribute ([#14935](https://github.com/sveltejs/svelte/pull/14935)) + +- fix: remove leading newline from `<pre>` contents ([#14922](https://github.com/sveltejs/svelte/pull/14922)) + ## 5.16.5 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 682cf30fb3..26907c2a5b 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -2,7 +2,7 @@ "name": "svelte", "description": "Cybernetically enhanced web apps", "license": "MIT", - "version": "5.16.5", + "version": "5.16.6", "type": "module", "types": "./types/index.d.ts", "engines": { diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js index d4fd729b38..c7ad6fcf63 100644 --- a/packages/svelte/src/version.js +++ b/packages/svelte/src/version.js @@ -4,5 +4,5 @@ * The current version, as set in package.json. * @type {string} */ -export const VERSION = '5.16.5'; +export const VERSION = '5.16.6'; export const PUBLIC_VERSION = '5'; From 48e3db21c187d1f4eb2aa10b417628e9ce6d17c3 Mon Sep 17 00:00:00 2001 From: Caique Torres <56696506+caiquetorres@users.noreply.github.com> Date: Tue, 7 Jan 2025 20:31:41 -0300 Subject: [PATCH 34/63] fix: default values in object destructuring (#14554) * fix: enhance string/expression length check and fix closing character issues * docs: add documentation for unterminated_string_constant error * test: add tests for object destructuring with default values in "each" blocks * Update .changeset/clean-planets-rush.md * refactor: clean up unnecessary comments and whitespace * fix: resolve formatting issues * simplify * tweak * regenerate --------- Co-authored-by: Rich Harris <rich.harris@vercel.com> --- .changeset/clean-planets-rush.md | 5 + .../98-reference/.generated/compile-errors.md | 6 + .../messages/compile-errors/template.md | 4 + packages/svelte/src/compiler/errors.js | 9 + .../compiler/phases/1-parse/read/context.js | 95 +- .../input.svelte | 9 + .../output.json | 826 +++++++++++++++++ .../each-block-object-pattern/input.svelte | 8 + .../each-block-object-pattern/output.json | 869 +++++++++++++++++- 9 files changed, 1806 insertions(+), 25 deletions(-) create mode 100644 .changeset/clean-planets-rush.md create mode 100644 packages/svelte/tests/parser-modern/samples/each-block-object-pattern-special-characters/input.svelte create mode 100644 packages/svelte/tests/parser-modern/samples/each-block-object-pattern-special-characters/output.json diff --git a/.changeset/clean-planets-rush.md b/.changeset/clean-planets-rush.md new file mode 100644 index 0000000000..d8500d4315 --- /dev/null +++ b/.changeset/clean-planets-rush.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: handle default values in object destructuring within "each" blocks when using characters like "}" and "]" diff --git a/documentation/docs/98-reference/.generated/compile-errors.md b/documentation/docs/98-reference/.generated/compile-errors.md index 298363f78d..c498920007 100644 --- a/documentation/docs/98-reference/.generated/compile-errors.md +++ b/documentation/docs/98-reference/.generated/compile-errors.md @@ -1012,6 +1012,12 @@ Unexpected end of input '%word%' is a reserved word in JavaScript and cannot be used here ``` +### unterminated_string_constant + +``` +Unterminated string constant +``` + ### void_element_invalid_content ``` diff --git a/packages/svelte/messages/compile-errors/template.md b/packages/svelte/messages/compile-errors/template.md index 02961b61fc..287178ef87 100644 --- a/packages/svelte/messages/compile-errors/template.md +++ b/packages/svelte/messages/compile-errors/template.md @@ -418,6 +418,10 @@ See https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-ele > '%word%' is a reserved word in JavaScript and cannot be used here +## unterminated_string_constant + +> Unterminated string constant + ## void_element_invalid_content > Void elements cannot have children or closing tags diff --git a/packages/svelte/src/compiler/errors.js b/packages/svelte/src/compiler/errors.js index 9ea13e811e..870cd9ac09 100644 --- a/packages/svelte/src/compiler/errors.js +++ b/packages/svelte/src/compiler/errors.js @@ -1574,6 +1574,15 @@ export function unexpected_reserved_word(node, word) { e(node, "unexpected_reserved_word", `'${word}' is a reserved word in JavaScript and cannot be used here\nhttps://svelte.dev/e/unexpected_reserved_word`); } +/** + * Unterminated string constant + * @param {null | number | NodeLike} node + * @returns {never} + */ +export function unterminated_string_constant(node) { + e(node, "unterminated_string_constant", `Unterminated string constant\nhttps://svelte.dev/e/unterminated_string_constant`); +} + /** * Void elements cannot have children or closing tags * @param {null | number | NodeLike} node diff --git a/packages/svelte/src/compiler/phases/1-parse/read/context.js b/packages/svelte/src/compiler/phases/1-parse/read/context.js index e206701500..f4c73dcf40 100644 --- a/packages/svelte/src/compiler/phases/1-parse/read/context.js +++ b/packages/svelte/src/compiler/phases/1-parse/read/context.js @@ -37,33 +37,11 @@ export default function read_pattern(parser) { e.expected_pattern(i); } - /** @type {string[]} */ - const bracket_stack = []; - - while (i < parser.template.length) { - const char = parser.template[i]; - - if (is_bracket_open(char)) { - bracket_stack.push(char); - } else if (is_bracket_close(char)) { - const popped = /** @type {string} */ (bracket_stack.pop()); - const expected = /** @type {string} */ (get_bracket_close(popped)); - - if (char !== expected) { - e.expected_token(i, expected); - } - - if (bracket_stack.length === 0) { - i += 1; - break; - } - } - i += 1; - } - + i = match_bracket(parser, start); parser.index = i; const pattern_string = parser.template.slice(start, i); + try { // the length of the `space_with_newline` has to be start - 1 // because we added a `(` in front of the pattern_string, @@ -93,6 +71,75 @@ export default function read_pattern(parser) { } } +/** + * @param {Parser} parser + * @param {number} start + */ +function match_bracket(parser, start) { + const bracket_stack = []; + + let i = start; + + while (i < parser.template.length) { + let char = parser.template[i++]; + + if (char === "'" || char === '"' || char === '`') { + i = match_quote(parser, i, char); + continue; + } + + if (is_bracket_open(char)) { + bracket_stack.push(char); + } else if (is_bracket_close(char)) { + const popped = /** @type {string} */ (bracket_stack.pop()); + const expected = /** @type {string} */ (get_bracket_close(popped)); + + if (char !== expected) { + e.expected_token(i - 1, expected); + } + + if (bracket_stack.length === 0) { + return i; + } + } + } + + e.unexpected_eof(parser.template.length); +} + +/** + * @param {Parser} parser + * @param {number} start + * @param {string} quote + */ +function match_quote(parser, start, quote) { + let is_escaped = false; + let i = start; + + while (i < parser.template.length) { + const char = parser.template[i++]; + + if (is_escaped) { + is_escaped = false; + continue; + } + + if (char === quote) { + return i; + } + + if (char === '\\') { + is_escaped = true; + } + + if (quote === '`' && char === '$' && parser.template[i] === '{') { + i = match_bracket(parser, i); + } + } + + e.unterminated_string_constant(start); +} + /** * @param {Parser} parser * @returns {any} diff --git a/packages/svelte/tests/parser-modern/samples/each-block-object-pattern-special-characters/input.svelte b/packages/svelte/tests/parser-modern/samples/each-block-object-pattern-special-characters/input.svelte new file mode 100644 index 0000000000..bc83f8e57f --- /dev/null +++ b/packages/svelte/tests/parser-modern/samples/each-block-object-pattern-special-characters/input.svelte @@ -0,0 +1,9 @@ +{#each x as { y = 'z' }}{/each} + +{#each x as { y = '{' }}{/each} + +{#each x as { y = ']' }}{/each} + +{#each x as { y = `${`"`}` }}{/each} + +{#each x as { y = `${`John`}` }}{/each} diff --git a/packages/svelte/tests/parser-modern/samples/each-block-object-pattern-special-characters/output.json b/packages/svelte/tests/parser-modern/samples/each-block-object-pattern-special-characters/output.json new file mode 100644 index 0000000000..b962db3226 --- /dev/null +++ b/packages/svelte/tests/parser-modern/samples/each-block-object-pattern-special-characters/output.json @@ -0,0 +1,826 @@ +{ + "css": null, + "js": [], + "start": 0, + "end": 176, + "type": "Root", + "fragment": { + "type": "Fragment", + "nodes": [ + { + "type": "EachBlock", + "start": 0, + "end": 31, + "expression": { + "type": "Identifier", + "start": 7, + "end": 8, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 8 + } + }, + "name": "x" + }, + "body": { + "type": "Fragment", + "nodes": [] + }, + "context": { + "type": "ObjectPattern", + "start": 12, + "end": 23, + "loc": { + "start": { + "line": 1, + "column": 12 + }, + "end": { + "line": 1, + "column": 23 + } + }, + "properties": [ + { + "type": "Property", + "start": 14, + "end": 21, + "loc": { + "start": { + "line": 1, + "column": 14 + }, + "end": { + "line": 1, + "column": 21 + } + }, + "method": false, + "shorthand": true, + "computed": false, + "key": { + "type": "Identifier", + "start": 14, + "end": 15, + "loc": { + "start": { + "line": 1, + "column": 14 + }, + "end": { + "line": 1, + "column": 15 + } + }, + "name": "y" + }, + "kind": "init", + "value": { + "type": "AssignmentPattern", + "start": 14, + "end": 21, + "loc": { + "start": { + "line": 1, + "column": 14 + }, + "end": { + "line": 1, + "column": 21 + } + }, + "left": { + "type": "Identifier", + "start": 14, + "end": 15, + "loc": { + "start": { + "line": 1, + "column": 14 + }, + "end": { + "line": 1, + "column": 15 + } + }, + "name": "y" + }, + "right": { + "type": "Literal", + "start": 18, + "end": 21, + "loc": { + "start": { + "line": 1, + "column": 18 + }, + "end": { + "line": 1, + "column": 21 + } + }, + "value": "z", + "raw": "'z'" + } + } + } + ] + } + }, + { + "type": "Text", + "start": 31, + "end": 33, + "raw": "\n\n", + "data": "\n\n" + }, + { + "type": "EachBlock", + "start": 33, + "end": 64, + "expression": { + "type": "Identifier", + "start": 40, + "end": 41, + "loc": { + "start": { + "line": 3, + "column": 7 + }, + "end": { + "line": 3, + "column": 8 + } + }, + "name": "x" + }, + "body": { + "type": "Fragment", + "nodes": [] + }, + "context": { + "type": "ObjectPattern", + "start": 45, + "end": 56, + "loc": { + "start": { + "line": 3, + "column": 13 + }, + "end": { + "line": 3, + "column": 24 + } + }, + "properties": [ + { + "type": "Property", + "start": 47, + "end": 54, + "loc": { + "start": { + "line": 3, + "column": 15 + }, + "end": { + "line": 3, + "column": 22 + } + }, + "method": false, + "shorthand": true, + "computed": false, + "key": { + "type": "Identifier", + "start": 47, + "end": 48, + "loc": { + "start": { + "line": 3, + "column": 15 + }, + "end": { + "line": 3, + "column": 16 + } + }, + "name": "y" + }, + "kind": "init", + "value": { + "type": "AssignmentPattern", + "start": 47, + "end": 54, + "loc": { + "start": { + "line": 3, + "column": 15 + }, + "end": { + "line": 3, + "column": 22 + } + }, + "left": { + "type": "Identifier", + "start": 47, + "end": 48, + "loc": { + "start": { + "line": 3, + "column": 15 + }, + "end": { + "line": 3, + "column": 16 + } + }, + "name": "y" + }, + "right": { + "type": "Literal", + "start": 51, + "end": 54, + "loc": { + "start": { + "line": 3, + "column": 19 + }, + "end": { + "line": 3, + "column": 22 + } + }, + "value": "{", + "raw": "'{'" + } + } + } + ] + } + }, + { + "type": "Text", + "start": 64, + "end": 66, + "raw": "\n\n", + "data": "\n\n" + }, + { + "type": "EachBlock", + "start": 66, + "end": 97, + "expression": { + "type": "Identifier", + "start": 73, + "end": 74, + "loc": { + "start": { + "line": 5, + "column": 7 + }, + "end": { + "line": 5, + "column": 8 + } + }, + "name": "x" + }, + "body": { + "type": "Fragment", + "nodes": [] + }, + "context": { + "type": "ObjectPattern", + "start": 78, + "end": 89, + "loc": { + "start": { + "line": 5, + "column": 13 + }, + "end": { + "line": 5, + "column": 24 + } + }, + "properties": [ + { + "type": "Property", + "start": 80, + "end": 87, + "loc": { + "start": { + "line": 5, + "column": 15 + }, + "end": { + "line": 5, + "column": 22 + } + }, + "method": false, + "shorthand": true, + "computed": false, + "key": { + "type": "Identifier", + "start": 80, + "end": 81, + "loc": { + "start": { + "line": 5, + "column": 15 + }, + "end": { + "line": 5, + "column": 16 + } + }, + "name": "y" + }, + "kind": "init", + "value": { + "type": "AssignmentPattern", + "start": 80, + "end": 87, + "loc": { + "start": { + "line": 5, + "column": 15 + }, + "end": { + "line": 5, + "column": 22 + } + }, + "left": { + "type": "Identifier", + "start": 80, + "end": 81, + "loc": { + "start": { + "line": 5, + "column": 15 + }, + "end": { + "line": 5, + "column": 16 + } + }, + "name": "y" + }, + "right": { + "type": "Literal", + "start": 84, + "end": 87, + "loc": { + "start": { + "line": 5, + "column": 19 + }, + "end": { + "line": 5, + "column": 22 + } + }, + "value": "]", + "raw": "']'" + } + } + } + ] + } + }, + { + "type": "Text", + "start": 97, + "end": 99, + "raw": "\n\n", + "data": "\n\n" + }, + { + "type": "EachBlock", + "start": 99, + "end": 135, + "expression": { + "type": "Identifier", + "start": 106, + "end": 107, + "loc": { + "start": { + "line": 7, + "column": 7 + }, + "end": { + "line": 7, + "column": 8 + } + }, + "name": "x" + }, + "body": { + "type": "Fragment", + "nodes": [] + }, + "context": { + "type": "ObjectPattern", + "start": 111, + "end": 127, + "loc": { + "start": { + "line": 7, + "column": 13 + }, + "end": { + "line": 7, + "column": 29 + } + }, + "properties": [ + { + "type": "Property", + "start": 113, + "end": 125, + "loc": { + "start": { + "line": 7, + "column": 15 + }, + "end": { + "line": 7, + "column": 27 + } + }, + "method": false, + "shorthand": true, + "computed": false, + "key": { + "type": "Identifier", + "start": 113, + "end": 114, + "loc": { + "start": { + "line": 7, + "column": 15 + }, + "end": { + "line": 7, + "column": 16 + } + }, + "name": "y" + }, + "kind": "init", + "value": { + "type": "AssignmentPattern", + "start": 113, + "end": 125, + "loc": { + "start": { + "line": 7, + "column": 15 + }, + "end": { + "line": 7, + "column": 27 + } + }, + "left": { + "type": "Identifier", + "start": 113, + "end": 114, + "loc": { + "start": { + "line": 7, + "column": 15 + }, + "end": { + "line": 7, + "column": 16 + } + }, + "name": "y" + }, + "right": { + "type": "TemplateLiteral", + "start": 117, + "end": 125, + "loc": { + "start": { + "line": 7, + "column": 19 + }, + "end": { + "line": 7, + "column": 27 + } + }, + "expressions": [ + { + "type": "TemplateLiteral", + "start": 120, + "end": 123, + "loc": { + "start": { + "line": 7, + "column": 22 + }, + "end": { + "line": 7, + "column": 25 + } + }, + "expressions": [], + "quasis": [ + { + "type": "TemplateElement", + "start": 121, + "end": 122, + "loc": { + "start": { + "line": 7, + "column": 23 + }, + "end": { + "line": 7, + "column": 24 + } + }, + "value": { + "raw": "\"", + "cooked": "\"" + }, + "tail": true + } + ] + } + ], + "quasis": [ + { + "type": "TemplateElement", + "start": 118, + "end": 118, + "loc": { + "start": { + "line": 7, + "column": 20 + }, + "end": { + "line": 7, + "column": 20 + } + }, + "value": { + "raw": "", + "cooked": "" + }, + "tail": false + }, + { + "type": "TemplateElement", + "start": 124, + "end": 124, + "loc": { + "start": { + "line": 7, + "column": 26 + }, + "end": { + "line": 7, + "column": 26 + } + }, + "value": { + "raw": "", + "cooked": "" + }, + "tail": true + } + ] + } + } + } + ] + } + }, + { + "type": "Text", + "start": 135, + "end": 137, + "raw": "\n\n", + "data": "\n\n" + }, + { + "type": "EachBlock", + "start": 137, + "end": 176, + "expression": { + "type": "Identifier", + "start": 144, + "end": 145, + "loc": { + "start": { + "line": 9, + "column": 7 + }, + "end": { + "line": 9, + "column": 8 + } + }, + "name": "x" + }, + "body": { + "type": "Fragment", + "nodes": [] + }, + "context": { + "type": "ObjectPattern", + "start": 149, + "end": 168, + "loc": { + "start": { + "line": 9, + "column": 13 + }, + "end": { + "line": 9, + "column": 32 + } + }, + "properties": [ + { + "type": "Property", + "start": 151, + "end": 166, + "loc": { + "start": { + "line": 9, + "column": 15 + }, + "end": { + "line": 9, + "column": 30 + } + }, + "method": false, + "shorthand": true, + "computed": false, + "key": { + "type": "Identifier", + "start": 151, + "end": 152, + "loc": { + "start": { + "line": 9, + "column": 15 + }, + "end": { + "line": 9, + "column": 16 + } + }, + "name": "y" + }, + "kind": "init", + "value": { + "type": "AssignmentPattern", + "start": 151, + "end": 166, + "loc": { + "start": { + "line": 9, + "column": 15 + }, + "end": { + "line": 9, + "column": 30 + } + }, + "left": { + "type": "Identifier", + "start": 151, + "end": 152, + "loc": { + "start": { + "line": 9, + "column": 15 + }, + "end": { + "line": 9, + "column": 16 + } + }, + "name": "y" + }, + "right": { + "type": "TemplateLiteral", + "start": 155, + "end": 166, + "loc": { + "start": { + "line": 9, + "column": 19 + }, + "end": { + "line": 9, + "column": 30 + } + }, + "expressions": [ + { + "type": "TemplateLiteral", + "start": 158, + "end": 164, + "loc": { + "start": { + "line": 9, + "column": 22 + }, + "end": { + "line": 9, + "column": 28 + } + }, + "expressions": [], + "quasis": [ + { + "type": "TemplateElement", + "start": 159, + "end": 163, + "loc": { + "start": { + "line": 9, + "column": 23 + }, + "end": { + "line": 9, + "column": 27 + } + }, + "value": { + "raw": "John", + "cooked": "John" + }, + "tail": true + } + ] + } + ], + "quasis": [ + { + "type": "TemplateElement", + "start": 156, + "end": 156, + "loc": { + "start": { + "line": 9, + "column": 20 + }, + "end": { + "line": 9, + "column": 20 + } + }, + "value": { + "raw": "", + "cooked": "" + }, + "tail": false + }, + { + "type": "TemplateElement", + "start": 165, + "end": 165, + "loc": { + "start": { + "line": 9, + "column": 29 + }, + "end": { + "line": 9, + "column": 29 + } + }, + "value": { + "raw": "", + "cooked": "" + }, + "tail": true + } + ] + } + } + } + ] + } + } + ] + }, + "options": null +} diff --git a/packages/svelte/tests/parser-modern/samples/each-block-object-pattern/input.svelte b/packages/svelte/tests/parser-modern/samples/each-block-object-pattern/input.svelte index 8ffe8a7287..c3bfdb46a6 100644 --- a/packages/svelte/tests/parser-modern/samples/each-block-object-pattern/input.svelte +++ b/packages/svelte/tests/parser-modern/samples/each-block-object-pattern/input.svelte @@ -1,3 +1,11 @@ {#each people as { name, cool = true }} <p>{name} is {cool ? 'cool' : 'not cool'}</p> {/each} + +{#each people as { name = `Jane ${"Doe"}`, cool = true }} + <p>{name} is {cool ? 'cool' : 'not cool'}</p> +{/each} + +{#each people as { name = (() => { return `Jane ${"Doe"}`; })(), cool = true }} + <p>{name} is {cool ? 'cool' : 'not cool'}</p> +{/each} diff --git a/packages/svelte/tests/parser-modern/samples/each-block-object-pattern/output.json b/packages/svelte/tests/parser-modern/samples/each-block-object-pattern/output.json index 8fc3feb916..144016417b 100644 --- a/packages/svelte/tests/parser-modern/samples/each-block-object-pattern/output.json +++ b/packages/svelte/tests/parser-modern/samples/each-block-object-pattern/output.json @@ -2,7 +2,7 @@ "css": null, "js": [], "start": 0, - "end": 94, + "end": 344, "type": "Root", "fragment": { "type": "Fragment", @@ -307,6 +307,873 @@ } ] } + }, + { + "type": "Text", + "start": 94, + "end": 96, + "raw": "\n\n", + "data": "\n\n" + }, + { + "type": "EachBlock", + "start": 96, + "end": 208, + "expression": { + "type": "Identifier", + "start": 103, + "end": 109, + "loc": { + "start": { + "line": 5, + "column": 7 + }, + "end": { + "line": 5, + "column": 13 + } + }, + "name": "people" + }, + "body": { + "type": "Fragment", + "nodes": [ + { + "type": "Text", + "start": 153, + "end": 155, + "raw": "\n\t", + "data": "\n\t" + }, + { + "type": "RegularElement", + "start": 155, + "end": 200, + "name": "p", + "attributes": [], + "fragment": { + "type": "Fragment", + "nodes": [ + { + "type": "ExpressionTag", + "start": 158, + "end": 164, + "expression": { + "type": "Identifier", + "start": 159, + "end": 163, + "loc": { + "start": { + "line": 6, + "column": 5 + }, + "end": { + "line": 6, + "column": 9 + } + }, + "name": "name" + } + }, + { + "type": "Text", + "start": 164, + "end": 168, + "raw": " is ", + "data": " is " + }, + { + "type": "ExpressionTag", + "start": 168, + "end": 196, + "expression": { + "type": "ConditionalExpression", + "start": 169, + "end": 195, + "loc": { + "start": { + "line": 6, + "column": 15 + }, + "end": { + "line": 6, + "column": 41 + } + }, + "test": { + "type": "Identifier", + "start": 169, + "end": 173, + "loc": { + "start": { + "line": 6, + "column": 15 + }, + "end": { + "line": 6, + "column": 19 + } + }, + "name": "cool" + }, + "consequent": { + "type": "Literal", + "start": 176, + "end": 182, + "loc": { + "start": { + "line": 6, + "column": 22 + }, + "end": { + "line": 6, + "column": 28 + } + }, + "value": "cool", + "raw": "'cool'" + }, + "alternate": { + "type": "Literal", + "start": 185, + "end": 195, + "loc": { + "start": { + "line": 6, + "column": 31 + }, + "end": { + "line": 6, + "column": 41 + } + }, + "value": "not cool", + "raw": "'not cool'" + } + } + } + ] + } + }, + { + "type": "Text", + "start": 200, + "end": 201, + "raw": "\n", + "data": "\n" + } + ] + }, + "context": { + "type": "ObjectPattern", + "start": 113, + "end": 152, + "loc": { + "start": { + "line": 5, + "column": 18 + }, + "end": { + "line": 5, + "column": 57 + } + }, + "properties": [ + { + "type": "Property", + "start": 115, + "end": 137, + "loc": { + "start": { + "line": 5, + "column": 20 + }, + "end": { + "line": 5, + "column": 42 + } + }, + "method": false, + "shorthand": true, + "computed": false, + "key": { + "type": "Identifier", + "start": 115, + "end": 119, + "loc": { + "start": { + "line": 5, + "column": 20 + }, + "end": { + "line": 5, + "column": 24 + } + }, + "name": "name" + }, + "kind": "init", + "value": { + "type": "AssignmentPattern", + "start": 115, + "end": 137, + "loc": { + "start": { + "line": 5, + "column": 20 + }, + "end": { + "line": 5, + "column": 42 + } + }, + "left": { + "type": "Identifier", + "start": 115, + "end": 119, + "loc": { + "start": { + "line": 5, + "column": 20 + }, + "end": { + "line": 5, + "column": 24 + } + }, + "name": "name" + }, + "right": { + "type": "TemplateLiteral", + "start": 122, + "end": 137, + "loc": { + "start": { + "line": 5, + "column": 27 + }, + "end": { + "line": 5, + "column": 42 + } + }, + "expressions": [ + { + "type": "Literal", + "start": 130, + "end": 135, + "loc": { + "start": { + "line": 5, + "column": 35 + }, + "end": { + "line": 5, + "column": 40 + } + }, + "value": "Doe", + "raw": "\"Doe\"" + } + ], + "quasis": [ + { + "type": "TemplateElement", + "start": 123, + "end": 128, + "loc": { + "start": { + "line": 5, + "column": 28 + }, + "end": { + "line": 5, + "column": 33 + } + }, + "value": { + "raw": "Jane ", + "cooked": "Jane " + }, + "tail": false + }, + { + "type": "TemplateElement", + "start": 136, + "end": 136, + "loc": { + "start": { + "line": 5, + "column": 41 + }, + "end": { + "line": 5, + "column": 41 + } + }, + "value": { + "raw": "", + "cooked": "" + }, + "tail": true + } + ] + } + } + }, + { + "type": "Property", + "start": 139, + "end": 150, + "loc": { + "start": { + "line": 5, + "column": 44 + }, + "end": { + "line": 5, + "column": 55 + } + }, + "method": false, + "shorthand": true, + "computed": false, + "key": { + "type": "Identifier", + "start": 139, + "end": 143, + "loc": { + "start": { + "line": 5, + "column": 44 + }, + "end": { + "line": 5, + "column": 48 + } + }, + "name": "cool" + }, + "kind": "init", + "value": { + "type": "AssignmentPattern", + "start": 139, + "end": 150, + "loc": { + "start": { + "line": 5, + "column": 44 + }, + "end": { + "line": 5, + "column": 55 + } + }, + "left": { + "type": "Identifier", + "start": 139, + "end": 143, + "loc": { + "start": { + "line": 5, + "column": 44 + }, + "end": { + "line": 5, + "column": 48 + } + }, + "name": "cool" + }, + "right": { + "type": "Literal", + "start": 146, + "end": 150, + "loc": { + "start": { + "line": 5, + "column": 51 + }, + "end": { + "line": 5, + "column": 55 + } + }, + "value": true, + "raw": "true" + } + } + } + ] + } + }, + { + "type": "Text", + "start": 208, + "end": 210, + "raw": "\n\n", + "data": "\n\n" + }, + { + "type": "EachBlock", + "start": 210, + "end": 344, + "expression": { + "type": "Identifier", + "start": 217, + "end": 223, + "loc": { + "start": { + "line": 9, + "column": 7 + }, + "end": { + "line": 9, + "column": 13 + } + }, + "name": "people" + }, + "body": { + "type": "Fragment", + "nodes": [ + { + "type": "Text", + "start": 289, + "end": 291, + "raw": "\n\t", + "data": "\n\t" + }, + { + "type": "RegularElement", + "start": 291, + "end": 336, + "name": "p", + "attributes": [], + "fragment": { + "type": "Fragment", + "nodes": [ + { + "type": "ExpressionTag", + "start": 294, + "end": 300, + "expression": { + "type": "Identifier", + "start": 295, + "end": 299, + "loc": { + "start": { + "line": 10, + "column": 5 + }, + "end": { + "line": 10, + "column": 9 + } + }, + "name": "name" + } + }, + { + "type": "Text", + "start": 300, + "end": 304, + "raw": " is ", + "data": " is " + }, + { + "type": "ExpressionTag", + "start": 304, + "end": 332, + "expression": { + "type": "ConditionalExpression", + "start": 305, + "end": 331, + "loc": { + "start": { + "line": 10, + "column": 15 + }, + "end": { + "line": 10, + "column": 41 + } + }, + "test": { + "type": "Identifier", + "start": 305, + "end": 309, + "loc": { + "start": { + "line": 10, + "column": 15 + }, + "end": { + "line": 10, + "column": 19 + } + }, + "name": "cool" + }, + "consequent": { + "type": "Literal", + "start": 312, + "end": 318, + "loc": { + "start": { + "line": 10, + "column": 22 + }, + "end": { + "line": 10, + "column": 28 + } + }, + "value": "cool", + "raw": "'cool'" + }, + "alternate": { + "type": "Literal", + "start": 321, + "end": 331, + "loc": { + "start": { + "line": 10, + "column": 31 + }, + "end": { + "line": 10, + "column": 41 + } + }, + "value": "not cool", + "raw": "'not cool'" + } + } + } + ] + } + }, + { + "type": "Text", + "start": 336, + "end": 337, + "raw": "\n", + "data": "\n" + } + ] + }, + "context": { + "type": "ObjectPattern", + "start": 227, + "end": 288, + "loc": { + "start": { + "line": 9, + "column": 18 + }, + "end": { + "line": 9, + "column": 79 + } + }, + "properties": [ + { + "type": "Property", + "start": 229, + "end": 273, + "loc": { + "start": { + "line": 9, + "column": 20 + }, + "end": { + "line": 9, + "column": 64 + } + }, + "method": false, + "shorthand": true, + "computed": false, + "key": { + "type": "Identifier", + "start": 229, + "end": 233, + "loc": { + "start": { + "line": 9, + "column": 20 + }, + "end": { + "line": 9, + "column": 24 + } + }, + "name": "name" + }, + "kind": "init", + "value": { + "type": "AssignmentPattern", + "start": 229, + "end": 273, + "loc": { + "start": { + "line": 9, + "column": 20 + }, + "end": { + "line": 9, + "column": 64 + } + }, + "left": { + "type": "Identifier", + "start": 229, + "end": 233, + "loc": { + "start": { + "line": 9, + "column": 20 + }, + "end": { + "line": 9, + "column": 24 + } + }, + "name": "name" + }, + "right": { + "type": "CallExpression", + "start": 236, + "end": 273, + "loc": { + "start": { + "line": 9, + "column": 27 + }, + "end": { + "line": 9, + "column": 64 + } + }, + "callee": { + "type": "ArrowFunctionExpression", + "start": 237, + "end": 270, + "loc": { + "start": { + "line": 9, + "column": 28 + }, + "end": { + "line": 9, + "column": 61 + } + }, + "id": null, + "expression": false, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start": 243, + "end": 270, + "loc": { + "start": { + "line": 9, + "column": 34 + }, + "end": { + "line": 9, + "column": 61 + } + }, + "body": [ + { + "type": "ReturnStatement", + "start": 245, + "end": 268, + "loc": { + "start": { + "line": 9, + "column": 36 + }, + "end": { + "line": 9, + "column": 59 + } + }, + "argument": { + "type": "TemplateLiteral", + "start": 252, + "end": 267, + "loc": { + "start": { + "line": 9, + "column": 43 + }, + "end": { + "line": 9, + "column": 58 + } + }, + "expressions": [ + { + "type": "Literal", + "start": 260, + "end": 265, + "loc": { + "start": { + "line": 9, + "column": 51 + }, + "end": { + "line": 9, + "column": 56 + } + }, + "value": "Doe", + "raw": "\"Doe\"" + } + ], + "quasis": [ + { + "type": "TemplateElement", + "start": 253, + "end": 258, + "loc": { + "start": { + "line": 9, + "column": 44 + }, + "end": { + "line": 9, + "column": 49 + } + }, + "value": { + "raw": "Jane ", + "cooked": "Jane " + }, + "tail": false + }, + { + "type": "TemplateElement", + "start": 266, + "end": 266, + "loc": { + "start": { + "line": 9, + "column": 57 + }, + "end": { + "line": 9, + "column": 57 + } + }, + "value": { + "raw": "", + "cooked": "" + }, + "tail": true + } + ] + } + } + ] + } + }, + "arguments": [], + "optional": false + } + } + }, + { + "type": "Property", + "start": 275, + "end": 286, + "loc": { + "start": { + "line": 9, + "column": 66 + }, + "end": { + "line": 9, + "column": 77 + } + }, + "method": false, + "shorthand": true, + "computed": false, + "key": { + "type": "Identifier", + "start": 275, + "end": 279, + "loc": { + "start": { + "line": 9, + "column": 66 + }, + "end": { + "line": 9, + "column": 70 + } + }, + "name": "cool" + }, + "kind": "init", + "value": { + "type": "AssignmentPattern", + "start": 275, + "end": 286, + "loc": { + "start": { + "line": 9, + "column": 66 + }, + "end": { + "line": 9, + "column": 77 + } + }, + "left": { + "type": "Identifier", + "start": 275, + "end": 279, + "loc": { + "start": { + "line": 9, + "column": 66 + }, + "end": { + "line": 9, + "column": 70 + } + }, + "name": "cool" + }, + "right": { + "type": "Literal", + "start": 282, + "end": 286, + "loc": { + "start": { + "line": 9, + "column": 73 + }, + "end": { + "line": 9, + "column": 77 + } + }, + "value": true, + "raw": "true" + } + } + } + ] + } } ] }, From deb362fe517c6fac3b77bfb4ec0b0dc9df16a971 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway <trueadm@users.noreply.github.com> Date: Wed, 8 Jan 2025 01:37:53 +0000 Subject: [PATCH 35/63] chore: expand benchmark iterations (#14944) --- benchmarking/benchmarks/reactivity/kairo/kairo_avoidable.js | 4 ++-- benchmarking/benchmarks/reactivity/kairo/kairo_broad.js | 4 ++-- benchmarking/benchmarks/reactivity/kairo/kairo_deep.js | 4 ++-- benchmarking/benchmarks/reactivity/kairo/kairo_diamond.js | 4 ++-- benchmarking/benchmarks/reactivity/kairo/kairo_mux.js | 4 ++-- benchmarking/benchmarks/reactivity/kairo/kairo_repeated.js | 4 ++-- benchmarking/benchmarks/reactivity/kairo/kairo_triangle.js | 4 ++-- benchmarking/benchmarks/reactivity/kairo/kairo_unstable.js | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_avoidable.js b/benchmarking/benchmarks/reactivity/kairo/kairo_avoidable.js index 1237547ebe..6b058cdc3c 100644 --- a/benchmarking/benchmarks/reactivity/kairo/kairo_avoidable.js +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_avoidable.js @@ -45,7 +45,7 @@ export async function kairo_avoidable_unowned() { const { run, destroy } = setup(); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); @@ -74,7 +74,7 @@ export async function kairo_avoidable_owned() { }); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_broad.js b/benchmarking/benchmarks/reactivity/kairo/kairo_broad.js index 8148a743ea..d1cde5958e 100644 --- a/benchmarking/benchmarks/reactivity/kairo/kairo_broad.js +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_broad.js @@ -51,7 +51,7 @@ export async function kairo_broad_unowned() { const { run, destroy } = setup(); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); @@ -80,7 +80,7 @@ export async function kairo_broad_owned() { }); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_deep.js b/benchmarking/benchmarks/reactivity/kairo/kairo_deep.js index 806042cc72..149457ede1 100644 --- a/benchmarking/benchmarks/reactivity/kairo/kairo_deep.js +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_deep.js @@ -51,7 +51,7 @@ export async function kairo_deep_unowned() { const { run, destroy } = setup(); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); @@ -80,7 +80,7 @@ export async function kairo_deep_owned() { }); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_diamond.js b/benchmarking/benchmarks/reactivity/kairo/kairo_diamond.js index deb9482de9..958a1bcd78 100644 --- a/benchmarking/benchmarks/reactivity/kairo/kairo_diamond.js +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_diamond.js @@ -55,7 +55,7 @@ export async function kairo_diamond_unowned() { const { run, destroy } = setup(); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); @@ -84,7 +84,7 @@ export async function kairo_diamond_owned() { }); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_mux.js b/benchmarking/benchmarks/reactivity/kairo/kairo_mux.js index 8eafacc9eb..b645051c09 100644 --- a/benchmarking/benchmarks/reactivity/kairo/kairo_mux.js +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_mux.js @@ -48,7 +48,7 @@ export async function kairo_mux_unowned() { const { run, destroy } = setup(); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); @@ -77,7 +77,7 @@ export async function kairo_mux_owned() { }); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_repeated.js b/benchmarking/benchmarks/reactivity/kairo/kairo_repeated.js index 2bddf879c9..53b85acd37 100644 --- a/benchmarking/benchmarks/reactivity/kairo/kairo_repeated.js +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_repeated.js @@ -52,7 +52,7 @@ export async function kairo_repeated_unowned() { const { run, destroy } = setup(); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); @@ -81,7 +81,7 @@ export async function kairo_repeated_owned() { }); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_triangle.js b/benchmarking/benchmarks/reactivity/kairo/kairo_triangle.js index 9d99b7815b..b9e2ad9fa4 100644 --- a/benchmarking/benchmarks/reactivity/kairo/kairo_triangle.js +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_triangle.js @@ -65,7 +65,7 @@ export async function kairo_triangle_unowned() { const { run, destroy } = setup(); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); @@ -94,7 +94,7 @@ export async function kairo_triangle_owned() { }); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_unstable.js b/benchmarking/benchmarks/reactivity/kairo/kairo_unstable.js index c30c007561..0e783732dc 100644 --- a/benchmarking/benchmarks/reactivity/kairo/kairo_unstable.js +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_unstable.js @@ -51,7 +51,7 @@ export async function kairo_unstable_unowned() { const { run, destroy } = setup(); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); @@ -80,7 +80,7 @@ export async function kairo_unstable_owned() { }); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); From 9c20eb4815bf86147746012453a2cfd8b407c61b Mon Sep 17 00:00:00 2001 From: Dominic Gannaway <trueadm@users.noreply.github.com> Date: Wed, 8 Jan 2025 09:46:26 +0000 Subject: [PATCH 36/63] chore: improve signal performance by reducing duplicate deps (#14945) * chore: expand benchmark iterations * chore: improve signal performance by reducing duplicate deps * feedback * oops --- .changeset/tame-students-retire.md | 5 ++ .../svelte/src/internal/client/dev/tracing.js | 7 +-- .../internal/client/reactivity/deriveds.js | 7 ++- .../src/internal/client/reactivity/effects.js | 2 +- .../src/internal/client/reactivity/sources.js | 7 ++- .../src/internal/client/reactivity/types.d.ts | 8 ++- .../svelte/src/internal/client/runtime.js | 63 +++++++++++-------- packages/svelte/tests/signals/test.ts | 3 +- 8 files changed, 59 insertions(+), 43 deletions(-) create mode 100644 .changeset/tame-students-retire.md diff --git a/.changeset/tame-students-retire.md b/.changeset/tame-students-retire.md new file mode 100644 index 0000000000..121c3690d0 --- /dev/null +++ b/.changeset/tame-students-retire.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +chore: improve signal performance by reducing duplicate deps diff --git a/packages/svelte/src/internal/client/dev/tracing.js b/packages/svelte/src/internal/client/dev/tracing.js index 6e759ecd59..3881ef3442 100644 --- a/packages/svelte/src/internal/client/dev/tracing.js +++ b/packages/svelte/src/internal/client/dev/tracing.js @@ -42,15 +42,12 @@ function log_entry(signal, entry) { const type = (signal.f & DERIVED) !== 0 ? '$derived' : '$state'; const current_reaction = /** @type {Reaction} */ (active_reaction); - const status = - signal.version > current_reaction.version || current_reaction.version === 0 ? 'dirty' : 'clean'; + const dirty = signal.wv > current_reaction.wv || current_reaction.wv === 0; // eslint-disable-next-line no-console console.groupCollapsed( `%c${type}`, - status !== 'clean' - ? 'color: CornflowerBlue; font-weight: bold' - : 'color: grey; font-weight: bold', + dirty ? 'color: CornflowerBlue; font-weight: bold' : 'color: grey; font-weight: bold', typeof value === 'object' && value !== null && STATE_SYMBOL in value ? snapshot(value, true) : value diff --git a/packages/svelte/src/internal/client/reactivity/deriveds.js b/packages/svelte/src/internal/client/reactivity/deriveds.js index 5e045920bf..7ec1ed30bd 100644 --- a/packages/svelte/src/internal/client/reactivity/deriveds.js +++ b/packages/svelte/src/internal/client/reactivity/deriveds.js @@ -16,7 +16,7 @@ import { set_signal_status, skip_reaction, update_reaction, - increment_version, + increment_write_version, set_active_effect, component_context } from '../runtime.js'; @@ -58,8 +58,9 @@ export function derived(fn) { f: flags, fn, reactions: null, + rv: 0, v: /** @type {V} */ (null), - version: 0, + wv: 0, parent: parent_derived ?? active_effect }; @@ -182,7 +183,7 @@ export function update_derived(derived) { if (!derived.equals(value)) { derived.v = value; - derived.version = increment_version(); + derived.wv = increment_write_version(); } } diff --git a/packages/svelte/src/internal/client/reactivity/effects.js b/packages/svelte/src/internal/client/reactivity/effects.js index bf890627f7..16f076edde 100644 --- a/packages/svelte/src/internal/client/reactivity/effects.js +++ b/packages/svelte/src/internal/client/reactivity/effects.js @@ -110,7 +110,7 @@ function create_effect(type, fn, sync, push = true) { prev: null, teardown: null, transitions: null, - version: 0 + wv: 0 }; if (DEV) { diff --git a/packages/svelte/src/internal/client/reactivity/sources.js b/packages/svelte/src/internal/client/reactivity/sources.js index fedf5b5070..e0facf3b55 100644 --- a/packages/svelte/src/internal/client/reactivity/sources.js +++ b/packages/svelte/src/internal/client/reactivity/sources.js @@ -12,7 +12,7 @@ import { set_untracked_writes, set_signal_status, untrack, - increment_version, + increment_write_version, update_effect, derived_sources, set_derived_sources, @@ -57,7 +57,8 @@ export function source(v, stack) { v, reactions: null, equals, - version: 0 + rv: 0, + wv: 0 }; if (DEV && tracing_mode_flag) { @@ -169,7 +170,7 @@ export function internal_set(source, value) { if (!source.equals(value)) { var old_value = source.v; source.v = value; - source.version = increment_version(); + source.wv = increment_write_version(); if (DEV && tracing_mode_flag) { source.updated = get_stack('UpdatedAt'); diff --git a/packages/svelte/src/internal/client/reactivity/types.d.ts b/packages/svelte/src/internal/client/reactivity/types.d.ts index 9a6e5d8bf0..3a76a3ff83 100644 --- a/packages/svelte/src/internal/client/reactivity/types.d.ts +++ b/packages/svelte/src/internal/client/reactivity/types.d.ts @@ -4,14 +4,16 @@ export interface Signal { /** Flags bitmask */ f: number; /** Write version */ - version: number; + wv: number; } export interface Value<V = unknown> extends Signal { - /** Signals that read from this signal */ - reactions: null | Reaction[]; /** Equality function */ equals: Equals; + /** Signals that read from this signal */ + reactions: null | Reaction[]; + /** Read version */ + rv: number; /** The latest value for this signal */ v: V; /** Dev only */ diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index a066f1c11a..202608ce06 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -127,8 +127,14 @@ export function set_untracked_writes(value) { untracked_writes = value; } -/** @type {number} Used by sources and deriveds for handling updates to unowned deriveds it starts from 1 to differentiate between a created effect and a run one for tracing */ -let current_version = 1; +/** + * @type {number} Used by sources and deriveds for handling updates. + * Version starts from 1 so that unowned deriveds differentiate between a created effect and a run one for tracing + **/ +let write_version = 1; + +/** @type {number} Used to version each read of a source of derived to avoid duplicating depedencies inside a reaction */ +let read_version = 0; // If we are working with a get() chain that has no active container, // to prevent memory leaks, we skip adding the reaction. @@ -168,8 +174,8 @@ export function set_dev_current_component_function(fn) { dev_current_component_function = fn; } -export function increment_version() { - return ++current_version; +export function increment_write_version() { + return ++write_version; } /** @returns {boolean} */ @@ -226,7 +232,7 @@ export function check_dirtiness(reaction) { update_derived(/** @type {Derived} */ (dependency)); } - if (dependency.version > reaction.version) { + if (dependency.wv > reaction.wv) { return true; } } @@ -398,6 +404,7 @@ export function update_reaction(reaction) { skip_reaction = !is_flushing_effect && (flags & UNOWNED) !== 0; derived_sources = null; component_context = reaction.ctx; + read_version++; try { var result = /** @type {Function} */ (0, reaction.fn)(); @@ -528,7 +535,7 @@ export function update_effect(effect) { execute_effect_teardown(effect); var teardown = update_reaction(effect); effect.teardown = typeof teardown === 'function' ? teardown : null; - effect.version = current_version; + effect.wv = write_version; var deps = effect.deps; @@ -540,7 +547,7 @@ export function update_effect(effect) { for (let i = 0; i < deps.length; i++) { var dep = deps[i]; if (dep.trace_need_increase) { - dep.version = increment_version(); + dep.wv = increment_write_version(); dep.trace_need_increase = undefined; dep.trace_v = undefined; } @@ -880,27 +887,29 @@ export function get(signal) { e.state_unsafe_local_read(); } var deps = active_reaction.deps; + if (signal.rv < read_version) { + signal.rv = read_version; + // If the signal is accessing the same dependencies in the same + // order as it did last time, increment `skipped_deps` + // rather than updating `new_deps`, which creates GC cost + if (new_deps === null && deps !== null && deps[skipped_deps] === signal) { + skipped_deps++; + } else if (new_deps === null) { + new_deps = [signal]; + } else { + new_deps.push(signal); + } - // If the signal is accessing the same dependencies in the same - // order as it did last time, increment `skipped_deps` - // rather than updating `new_deps`, which creates GC cost - if (new_deps === null && deps !== null && deps[skipped_deps] === signal) { - skipped_deps++; - } else if (new_deps === null) { - new_deps = [signal]; - } else { - new_deps.push(signal); - } - - if ( - untracked_writes !== null && - active_effect !== null && - (active_effect.f & CLEAN) !== 0 && - (active_effect.f & BRANCH_EFFECT) === 0 && - untracked_writes.includes(signal) - ) { - set_signal_status(active_effect, DIRTY); - schedule_effect(active_effect); + if ( + untracked_writes !== null && + active_effect !== null && + (active_effect.f & CLEAN) !== 0 && + (active_effect.f & BRANCH_EFFECT) === 0 && + untracked_writes.includes(signal) + ) { + set_signal_status(active_effect, DIRTY); + schedule_effect(active_effect); + } } } else if (is_derived && /** @type {Derived} */ (signal).deps === null) { var derived = /** @type {Derived} */ (signal); diff --git a/packages/svelte/tests/signals/test.ts b/packages/svelte/tests/signals/test.ts index 0a22e30286..e198a5a89d 100644 --- a/packages/svelte/tests/signals/test.ts +++ b/packages/svelte/tests/signals/test.ts @@ -296,6 +296,7 @@ describe('signals', () => { const destroy = effect_root(() => { user_effect(() => { log.push($.get(calc)); + $.get(calc); }); }); @@ -306,7 +307,7 @@ describe('signals', () => { flushSync(() => set(count, 4)); flushSync(() => set(count, 0)); // Ensure we're not leaking consumers - assert.deepEqual(count.reactions?.length, 2); + assert.deepEqual(count.reactions?.length, 1); assert.deepEqual(calc.reactions?.length, 1); assert.deepEqual(log, [0, 2, 'limit', 0]); destroy(); From ce2566d4c41c24546a697aa5feac07a617f806c0 Mon Sep 17 00:00:00 2001 From: Rich Harris <rich.harris@vercel.com> Date: Wed, 8 Jan 2025 09:47:24 +0000 Subject: [PATCH 37/63] docs: simplify `$effect.tracking()` docs (#14939) --- documentation/docs/02-runes/04-$effect.md | 48 +---------------------- 1 file changed, 1 insertion(+), 47 deletions(-) diff --git a/documentation/docs/02-runes/04-$effect.md b/documentation/docs/02-runes/04-$effect.md index b338795220..c48a82f9a5 100644 --- a/documentation/docs/02-runes/04-$effect.md +++ b/documentation/docs/02-runes/04-$effect.md @@ -193,53 +193,7 @@ The `$effect.tracking` rune is an advanced feature that tells you whether or not <p>in template: {$effect.tracking()}</p> <!-- true --> ``` -This allows you to (for example) add things like subscriptions without causing memory leaks, by putting them in child effects. Here's a `readable` function that listens to changes from a callback function as long as it's inside a tracking context: - -```ts -import { tick } from 'svelte'; - -export default function readable<T>( - initial_value: T, - start: (callback: (update: (v: T) => T) => T) => () => void -) { - let value = $state(initial_value); - - let subscribers = 0; - let stop: null | (() => void) = null; - - return { - get value() { - // If in a tracking context ... - if ($effect.tracking()) { - $effect(() => { - // ...and there's no subscribers yet... - if (subscribers === 0) { - // ...invoke the function and listen to changes to update state - stop = start((fn) => (value = fn(value))); - } - - subscribers++; - - // The return callback is called once a listener unlistens - return () => { - tick().then(() => { - subscribers--; - // If it was the last subscriber... - if (subscribers === 0) { - // ...stop listening to changes - stop?.(); - stop = null; - } - }); - }; - }); - } - - return value; - } - }; -} -``` +It is used to implement abstractions like [`createSubscriber`](/docs/svelte/svelte-reactivity#createSubscriber), which will create listeners to update reactive values but _only_ if those values are being tracked (rather than, for example, read inside an event handler). ## `$effect.root` From adee13d98c09c5bddc0da41cd38c429498880a09 Mon Sep 17 00:00:00 2001 From: Rich Harris <rich.harris@vercel.com> Date: Wed, 8 Jan 2025 09:49:04 +0000 Subject: [PATCH 38/63] fix: account for min-width/height in `slide` transition (#14942) --- .changeset/gold-olives-care.md | 5 +++++ packages/svelte/src/transition/index.js | 3 ++- .../samples/class-shortcut-with-transition/_config.js | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 .changeset/gold-olives-care.md diff --git a/.changeset/gold-olives-care.md b/.changeset/gold-olives-care.md new file mode 100644 index 0000000000..9f7357c6da --- /dev/null +++ b/.changeset/gold-olives-care.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: account for min-width/height in `slide` transition diff --git a/packages/svelte/src/transition/index.js b/packages/svelte/src/transition/index.js index 4123106211..aacc6b6cf3 100644 --- a/packages/svelte/src/transition/index.js +++ b/packages/svelte/src/transition/index.js @@ -131,7 +131,8 @@ export function slide(node, { delay = 0, duration = 400, easing = cubic_out, axi `margin-${secondary_properties[0]}: ${t * margin_start_value}px;` + `margin-${secondary_properties[1]}: ${t * margin_end_value}px;` + `border-${secondary_properties[0]}-width: ${t * border_width_start_value}px;` + - `border-${secondary_properties[1]}-width: ${t * border_width_end_value}px;` + `border-${secondary_properties[1]}-width: ${t * border_width_end_value}px;` + + `min-${primary_property}: 0` }; } diff --git a/packages/svelte/tests/runtime-legacy/samples/class-shortcut-with-transition/_config.js b/packages/svelte/tests/runtime-legacy/samples/class-shortcut-with-transition/_config.js index 6e3f7a3cb7..e58e8c53c5 100644 --- a/packages/svelte/tests/runtime-legacy/samples/class-shortcut-with-transition/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/class-shortcut-with-transition/_config.js @@ -18,7 +18,7 @@ export default test({ raf.tick(150); assert.htmlEqual( target.innerHTML, - '<p>foo</p><p class="red svelte-1yszte8 border" style="overflow: hidden; opacity: 0; border-top-width: 0.5px; border-bottom-width: 0.5px;">bar</p>' + '<p>foo</p><p class="red svelte-1yszte8 border" style="overflow: hidden; opacity: 0; border-top-width: 0.5px; border-bottom-width: 0.5px; min-height: 0;">bar</p>' ); component.open = true; raf.tick(250); From d245bab63a3fd4fbe3d0a03d51581db5b794564e Mon Sep 17 00:00:00 2001 From: Rich Harris <rich.harris@vercel.com> Date: Wed, 8 Jan 2025 09:49:49 +0000 Subject: [PATCH 39/63] feat: allow non-numeric values to be tweened by snapping immediately to new value (#14941) --- .changeset/cool-apples-report.md | 5 +++++ packages/svelte/src/motion/tweened.js | 3 ++- packages/svelte/tests/motion/test.ts | 21 +++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 .changeset/cool-apples-report.md diff --git a/.changeset/cool-apples-report.md b/.changeset/cool-apples-report.md new file mode 100644 index 0000000000..fa76c036d1 --- /dev/null +++ b/.changeset/cool-apples-report.md @@ -0,0 +1,5 @@ +--- +'svelte': minor +--- + +feat: allow non-numeric values to be tweened by snapping immediately to new value diff --git a/packages/svelte/src/motion/tweened.js b/packages/svelte/src/motion/tweened.js index 36d32d1f72..31cddf8f30 100644 --- a/packages/svelte/src/motion/tweened.js +++ b/packages/svelte/src/motion/tweened.js @@ -72,7 +72,8 @@ function get_interpolator(a, b) { return (t) => a + t * delta; } - throw new Error(`Cannot interpolate ${type} values`); + // for non-numeric values, snap to the final value immediately + return () => b; } /** diff --git a/packages/svelte/tests/motion/test.ts b/packages/svelte/tests/motion/test.ts index 7d845bac3d..7d0403983a 100644 --- a/packages/svelte/tests/motion/test.ts +++ b/packages/svelte/tests/motion/test.ts @@ -3,6 +3,7 @@ import '../helpers.js'; // for the matchMedia polyfill import { describe, it, assert } from 'vitest'; import { get } from 'svelte/store'; import { spring, tweened, Tween } from 'svelte/motion'; +import { raf } from '../animation-helpers.js'; describe('motion', () => { describe('spring', () => { @@ -38,6 +39,16 @@ describe('motion', () => { size.update((v) => v + 10); assert.equal(get(size), 20); }); + + it('updates non-numeric values immediately', () => { + raf.reset(); + const boolean = tweened(false); + + boolean.set(true, { duration: 100 }); + + raf.tick(1); + assert.equal(get(boolean), true); + }); }); describe('Tween', () => { @@ -47,6 +58,16 @@ describe('motion', () => { size.set(100, { duration: 0 }); assert.equal(size.current, 100); }); + + it('updates non-numeric values immediately', () => { + raf.reset(); + const boolean = new Tween(false); + + boolean.set(true, { duration: 100 }); + + raf.tick(1); + assert.equal(boolean.current, true); + }); }); it('updates correctly when initialized with a `null`-ish value', () => { From 4d2cb2734b94902225a3b960985976a81b6aa584 Mon Sep 17 00:00:00 2001 From: Rich Harris <rich.harris@vercel.com> Date: Wed, 8 Jan 2025 09:53:27 +0000 Subject: [PATCH 40/63] fix: prevent long delays causing erratic spring behaviour (#14940) --- .changeset/modern-wasps-punch.md | 5 +++++ packages/svelte/src/motion/spring.js | 13 +++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 .changeset/modern-wasps-punch.md diff --git a/.changeset/modern-wasps-punch.md b/.changeset/modern-wasps-punch.md new file mode 100644 index 0000000000..1fa0b41300 --- /dev/null +++ b/.changeset/modern-wasps-punch.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: prevent long delays causing erratic spring behaviour diff --git a/packages/svelte/src/motion/spring.js b/packages/svelte/src/motion/spring.js index bc30ce9578..1c8e5f15c0 100644 --- a/packages/svelte/src/motion/spring.js +++ b/packages/svelte/src/motion/spring.js @@ -108,12 +108,17 @@ export function spring(value, opts = {}) { return false; } inv_mass = Math.min(inv_mass + inv_mass_recovery_rate, 1); + + // clamp elapsed time to 1/30th of a second, so that longer pauses + // (blocked thread or inactive tab) don't cause the spring to go haywire + const elapsed = Math.min(now - last_time, 1000 / 30); + /** @type {TickContext} */ const ctx = { inv_mass, opts: spring, settled: true, - dt: ((now - last_time) * 60) / 1000 + dt: (elapsed * 60) / 1000 }; // @ts-ignore const next_value = tick_spring(ctx, last_value, value, target_value); @@ -236,6 +241,10 @@ export class Spring { this.#task ??= loop((now) => { this.#inverse_mass = Math.min(this.#inverse_mass + inv_mass_recovery_rate, 1); + // clamp elapsed time to 1/30th of a second, so that longer pauses + // (blocked thread or inactive tab) don't cause the spring to go haywire + const elapsed = Math.min(now - this.#last_time, 1000 / 30); + /** @type {import('./private').TickContext} */ const ctx = { inv_mass: this.#inverse_mass, @@ -245,7 +254,7 @@ export class Spring { precision: this.#precision.v }, settled: true, - dt: ((now - this.#last_time) * 60) / 1000 + dt: (elapsed * 60) / 1000 }; var next = tick_spring(ctx, this.#last_value, this.#current.v, this.#target.v); From d41801c75f2a232387229d2a45324affd0310808 Mon Sep 17 00:00:00 2001 From: Rich Harris <rich.harris@vercel.com> Date: Wed, 8 Jan 2025 09:54:52 +0000 Subject: [PATCH 41/63] feat: warn on using `slide` transition with invalid `display` styles (#14936) * feat: warn on using `slide` transition with table elements * more generic * more generic --- .changeset/silver-humans-yawn.md | 5 +++++ .../docs/98-reference/.generated/client-warnings.md | 12 ++++++++++++ .../svelte/messages/client-warnings/warnings.md | 10 ++++++++++ packages/svelte/src/internal/client/warnings.js | 12 ++++++++++++ packages/svelte/src/transition/index.js | 13 +++++++++++++ 5 files changed, 52 insertions(+) create mode 100644 .changeset/silver-humans-yawn.md diff --git a/.changeset/silver-humans-yawn.md b/.changeset/silver-humans-yawn.md new file mode 100644 index 0000000000..e274341079 --- /dev/null +++ b/.changeset/silver-humans-yawn.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +feat: warn on using `slide` transition with table elements diff --git a/documentation/docs/98-reference/.generated/client-warnings.md b/documentation/docs/98-reference/.generated/client-warnings.md index 5218ec4cb1..284e9a7c3e 100644 --- a/documentation/docs/98-reference/.generated/client-warnings.md +++ b/documentation/docs/98-reference/.generated/client-warnings.md @@ -222,3 +222,15 @@ Reactive `$state(...)` proxies and the values they proxy have different identiti ``` To resolve this, ensure you're comparing values where both values were created with `$state(...)`, or neither were. Note that `$state.raw(...)` will _not_ create a state proxy. + +### transition_slide_display + +``` +The `slide` transition does not work correctly for elements with `display: %value%` +``` + +The [slide](/docs/svelte/svelte-transition#slide) transition works by animating the `height` of the element, which requires a `display` style like `block`, `flex` or `grid`. It does not work for: + +- `display: inline` (which is the default for elements like `<span>`), and its variants like `inline-block`, `inline-flex` and `inline-grid` +- `display: table` and `table-[name]`, which are the defaults for elements like `<table>` and `<tr>` +- `display: contents` diff --git a/packages/svelte/messages/client-warnings/warnings.md b/packages/svelte/messages/client-warnings/warnings.md index 21db506dc9..943cf6f01f 100644 --- a/packages/svelte/messages/client-warnings/warnings.md +++ b/packages/svelte/messages/client-warnings/warnings.md @@ -186,3 +186,13 @@ To fix it, either create callback props to communicate changes, or mark `person` ``` To resolve this, ensure you're comparing values where both values were created with `$state(...)`, or neither were. Note that `$state.raw(...)` will _not_ create a state proxy. + +## transition_slide_display + +> The `slide` transition does not work correctly for elements with `display: %value%` + +The [slide](/docs/svelte/svelte-transition#slide) transition works by animating the `height` of the element, which requires a `display` style like `block`, `flex` or `grid`. It does not work for: + +- `display: inline` (which is the default for elements like `<span>`), and its variants like `inline-block`, `inline-flex` and `inline-grid` +- `display: table` and `table-[name]`, which are the defaults for elements like `<table>` and `<tr>` +- `display: contents` diff --git a/packages/svelte/src/internal/client/warnings.js b/packages/svelte/src/internal/client/warnings.js index 24d86e2e0b..78d457f48f 100644 --- a/packages/svelte/src/internal/client/warnings.js +++ b/packages/svelte/src/internal/client/warnings.js @@ -165,4 +165,16 @@ export function state_proxy_equality_mismatch(operator) { } else { console.warn(`https://svelte.dev/e/state_proxy_equality_mismatch`); } +} + +/** + * The `slide` transition does not work correctly for elements with `display: %value%` + * @param {string} value + */ +export function transition_slide_display(value) { + if (DEV) { + console.warn(`%c[svelte] transition_slide_display\n%cThe \`slide\` transition does not work correctly for elements with \`display: ${value}\`\nhttps://svelte.dev/e/transition_slide_display`, bold, normal); + } else { + console.warn(`https://svelte.dev/e/transition_slide_display`); + } } \ No newline at end of file diff --git a/packages/svelte/src/transition/index.js b/packages/svelte/src/transition/index.js index aacc6b6cf3..898a929eb1 100644 --- a/packages/svelte/src/transition/index.js +++ b/packages/svelte/src/transition/index.js @@ -1,4 +1,8 @@ /** @import { BlurParams, CrossfadeParams, DrawParams, FadeParams, FlyParams, ScaleParams, SlideParams, TransitionConfig } from './public' */ + +import { DEV } from 'esm-env'; +import * as w from '../internal/client/warnings.js'; + /** @param {number} x */ const linear = (x) => x; @@ -92,6 +96,8 @@ export function fly( }; } +var slide_warning = false; + /** * Slides an element in and out. * @@ -101,6 +107,13 @@ export function fly( */ export function slide(node, { delay = 0, duration = 400, easing = cubic_out, axis = 'y' } = {}) { const style = getComputedStyle(node); + + if (DEV && !slide_warning && /(contents|inline|table)/.test(style.display)) { + slide_warning = true; + Promise.resolve().then(() => (slide_warning = false)); + w.transition_slide_display(style.display); + } + const opacity = +style.opacity; const primary_property = axis === 'y' ? 'height' : 'width'; const primary_property_value = parseFloat(style[primary_property]); From 9b71eea35d8e62e7ef008565bf23fe25c4f47ed9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 8 Jan 2025 09:57:21 +0000 Subject: [PATCH 42/63] Version Packages (#14943) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> --- .changeset/clean-planets-rush.md | 5 ----- .changeset/cool-apples-report.md | 5 ----- .changeset/gold-olives-care.md | 5 ----- .changeset/modern-wasps-punch.md | 5 ----- .changeset/silver-humans-yawn.md | 5 ----- .changeset/tame-students-retire.md | 5 ----- packages/svelte/CHANGELOG.md | 18 ++++++++++++++++++ packages/svelte/package.json | 2 +- packages/svelte/src/version.js | 2 +- 9 files changed, 20 insertions(+), 32 deletions(-) delete mode 100644 .changeset/clean-planets-rush.md delete mode 100644 .changeset/cool-apples-report.md delete mode 100644 .changeset/gold-olives-care.md delete mode 100644 .changeset/modern-wasps-punch.md delete mode 100644 .changeset/silver-humans-yawn.md delete mode 100644 .changeset/tame-students-retire.md diff --git a/.changeset/clean-planets-rush.md b/.changeset/clean-planets-rush.md deleted file mode 100644 index d8500d4315..0000000000 --- a/.changeset/clean-planets-rush.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: handle default values in object destructuring within "each" blocks when using characters like "}" and "]" diff --git a/.changeset/cool-apples-report.md b/.changeset/cool-apples-report.md deleted file mode 100644 index fa76c036d1..0000000000 --- a/.changeset/cool-apples-report.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': minor ---- - -feat: allow non-numeric values to be tweened by snapping immediately to new value diff --git a/.changeset/gold-olives-care.md b/.changeset/gold-olives-care.md deleted file mode 100644 index 9f7357c6da..0000000000 --- a/.changeset/gold-olives-care.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: account for min-width/height in `slide` transition diff --git a/.changeset/modern-wasps-punch.md b/.changeset/modern-wasps-punch.md deleted file mode 100644 index 1fa0b41300..0000000000 --- a/.changeset/modern-wasps-punch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: prevent long delays causing erratic spring behaviour diff --git a/.changeset/silver-humans-yawn.md b/.changeset/silver-humans-yawn.md deleted file mode 100644 index e274341079..0000000000 --- a/.changeset/silver-humans-yawn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -feat: warn on using `slide` transition with table elements diff --git a/.changeset/tame-students-retire.md b/.changeset/tame-students-retire.md deleted file mode 100644 index 121c3690d0..0000000000 --- a/.changeset/tame-students-retire.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -chore: improve signal performance by reducing duplicate deps diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index 4a2cca8280..daf8ed209a 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,23 @@ # svelte +## 5.17.0 + +### Minor Changes + +- feat: allow non-numeric values to be tweened by snapping immediately to new value ([#14941](https://github.com/sveltejs/svelte/pull/14941)) + +### Patch Changes + +- fix: handle default values in object destructuring within "each" blocks when using characters like "}" and "]" ([#14554](https://github.com/sveltejs/svelte/pull/14554)) + +- fix: account for min-width/height in `slide` transition ([#14942](https://github.com/sveltejs/svelte/pull/14942)) + +- fix: prevent long delays causing erratic spring behaviour ([#14940](https://github.com/sveltejs/svelte/pull/14940)) + +- feat: warn on using `slide` transition with table elements ([#14936](https://github.com/sveltejs/svelte/pull/14936)) + +- chore: improve signal performance by reducing duplicate deps ([#14945](https://github.com/sveltejs/svelte/pull/14945)) + ## 5.16.6 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 26907c2a5b..5cd078bf77 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -2,7 +2,7 @@ "name": "svelte", "description": "Cybernetically enhanced web apps", "license": "MIT", - "version": "5.16.6", + "version": "5.17.0", "type": "module", "types": "./types/index.d.ts", "engines": { diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js index c7ad6fcf63..396c2b07ef 100644 --- a/packages/svelte/src/version.js +++ b/packages/svelte/src/version.js @@ -4,5 +4,5 @@ * The current version, as set in package.json. * @type {string} */ -export const VERSION = '5.16.6'; +export const VERSION = '5.17.0'; export const PUBLIC_VERSION = '5'; From ce4f9722dab8d99140d410a9d1f71ec19d16535e Mon Sep 17 00:00:00 2001 From: Rich Harris <rich.harris@vercel.com> Date: Wed, 8 Jan 2025 09:54:29 -0500 Subject: [PATCH 43/63] fix: remove bindable prop validation (#14946) --- .changeset/flat-otters-cheer.md | 5 ++++ .../3-transform/client/transform-client.js | 22 ---------------- packages/svelte/src/internal/client/index.js | 2 +- .../src/internal/client/reactivity/props.js | 6 +++-- .../svelte/src/internal/client/validate.js | 25 +------------------ .../samples/export-binding/_config.js | 10 -------- .../export-binding/counter/index.svelte | 8 ------ .../samples/export-binding/main.svelte | 7 ------ .../props-not-bindable-spread/Counter.svelte | 5 ---- .../props-not-bindable-spread/_config.js | 13 ---------- .../props-not-bindable-spread/main.svelte | 7 ------ .../samples/props-not-bindable/Counter.svelte | 5 ---- .../samples/props-not-bindable/_config.js | 13 ---------- .../samples/props-not-bindable/main.svelte | 7 ------ 14 files changed, 11 insertions(+), 124 deletions(-) create mode 100644 .changeset/flat-otters-cheer.md delete mode 100644 packages/svelte/tests/runtime-runes/samples/export-binding/_config.js delete mode 100644 packages/svelte/tests/runtime-runes/samples/export-binding/counter/index.svelte delete mode 100644 packages/svelte/tests/runtime-runes/samples/export-binding/main.svelte delete mode 100644 packages/svelte/tests/runtime-runes/samples/props-not-bindable-spread/Counter.svelte delete mode 100644 packages/svelte/tests/runtime-runes/samples/props-not-bindable-spread/_config.js delete mode 100644 packages/svelte/tests/runtime-runes/samples/props-not-bindable-spread/main.svelte delete mode 100644 packages/svelte/tests/runtime-runes/samples/props-not-bindable/Counter.svelte delete mode 100644 packages/svelte/tests/runtime-runes/samples/props-not-bindable/_config.js delete mode 100644 packages/svelte/tests/runtime-runes/samples/props-not-bindable/main.svelte diff --git a/.changeset/flat-otters-cheer.md b/.changeset/flat-otters-cheer.md new file mode 100644 index 0000000000..3f84de8242 --- /dev/null +++ b/.changeset/flat-otters-cheer.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: remove bindable prop validation diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js index 90901d29ce..a969117ed3 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js @@ -299,28 +299,6 @@ export function client_component(analysis, options) { (binding.kind === 'prop' || binding.kind === 'bindable_prop') && !name.startsWith('$$') ); - if (dev && analysis.runes) { - const exports = analysis.exports.map(({ name, alias }) => b.literal(alias ?? name)); - /** @type {ESTree.Literal[]} */ - const bindable = []; - for (const [name, binding] of properties) { - if (binding.kind === 'bindable_prop') { - bindable.push(b.literal(binding.prop_alias ?? name)); - } - } - instance.body.unshift( - b.stmt( - b.call( - '$.validate_prop_bindings', - b.id('$$props'), - b.array(bindable), - b.array(exports), - b.id(`${analysis.name}`) - ) - ) - ); - } - if (analysis.accessors) { for (const [name, binding] of properties) { const key = binding.prop_alias ?? name; diff --git a/packages/svelte/src/internal/client/index.js b/packages/svelte/src/internal/client/index.js index 3b85ae1816..2bf58c51f7 100644 --- a/packages/svelte/src/internal/client/index.js +++ b/packages/svelte/src/internal/client/index.js @@ -150,7 +150,7 @@ export { setContext, hasContext } from './runtime.js'; -export { validate_binding, validate_each_keys, validate_prop_bindings } from './validate.js'; +export { validate_binding, validate_each_keys } from './validate.js'; export { raf } from './timing.js'; export { proxy } from './proxy.js'; export { create_custom_element } from './dom/elements/custom-element.js'; diff --git a/packages/svelte/src/internal/client/reactivity/props.js b/packages/svelte/src/internal/client/reactivity/props.js index 8fb13f7e2c..3e5a0258c7 100644 --- a/packages/svelte/src/internal/client/reactivity/props.js +++ b/packages/svelte/src/internal/client/reactivity/props.js @@ -297,8 +297,10 @@ export function prop(props, key, flags, fallback) { var is_entry_props = STATE_SYMBOL in props || LEGACY_PROPS in props; var setter = - get_descriptor(props, key)?.set ?? - (is_entry_props && bindable && key in props ? (v) => (props[key] = v) : undefined); + (bindable && + (get_descriptor(props, key)?.set ?? + (is_entry_props && key in props && ((v) => (props[key] = v))))) || + undefined; var fallback_value = /** @type {V} */ (fallback); var fallback_dirty = true; diff --git a/packages/svelte/src/internal/client/validate.js b/packages/svelte/src/internal/client/validate.js index 417c145eb2..24e280edf8 100644 --- a/packages/svelte/src/internal/client/validate.js +++ b/packages/svelte/src/internal/client/validate.js @@ -1,5 +1,5 @@ import { dev_current_component_function } from './runtime.js'; -import { get_descriptor, is_array } from '../shared/utils.js'; +import { is_array } from '../shared/utils.js'; import * as e from './errors.js'; import { FILENAME } from '../../constants.js'; import { render_effect } from './reactivity/effects.js'; @@ -38,29 +38,6 @@ export function validate_each_keys(collection, key_fn) { }); } -/** - * @param {Record<string, any>} $$props - * @param {string[]} bindable - * @param {string[]} exports - * @param {Function & { [FILENAME]: string }} component - */ -export function validate_prop_bindings($$props, bindable, exports, component) { - for (const key in $$props) { - var setter = get_descriptor($$props, key)?.set; - var name = component.name; - - if (setter) { - if (exports.includes(key) && !bindable.includes(key)) { - e.bind_invalid_export(component[FILENAME], key, name); - } - - if (!bindable.includes(key)) { - e.bind_not_bindable(key, component[FILENAME], name); - } - } - } -} - /** * @param {string} binding * @param {() => Record<string, any>} get_object diff --git a/packages/svelte/tests/runtime-runes/samples/export-binding/_config.js b/packages/svelte/tests/runtime-runes/samples/export-binding/_config.js deleted file mode 100644 index d3b9c8e4eb..0000000000 --- a/packages/svelte/tests/runtime-runes/samples/export-binding/_config.js +++ /dev/null @@ -1,10 +0,0 @@ -import { test } from '../../test'; - -export default test({ - compileOptions: { - dev: true // to ensure we we catch the error - }, - error: - 'bind_invalid_export\n' + - 'Component counter/index.svelte has an export named `increment` that a consumer component is trying to access using `bind:increment`, which is disallowed. Instead, use `bind:this` (e.g. `<Counter bind:this={component} />`) and then access the property on the bound component instance (e.g. `component.increment`)' -}); diff --git a/packages/svelte/tests/runtime-runes/samples/export-binding/counter/index.svelte b/packages/svelte/tests/runtime-runes/samples/export-binding/counter/index.svelte deleted file mode 100644 index 14e0de961b..0000000000 --- a/packages/svelte/tests/runtime-runes/samples/export-binding/counter/index.svelte +++ /dev/null @@ -1,8 +0,0 @@ -<script> - let count = $state(0); - export function increment() { - count++; - } -</script> - -{count} diff --git a/packages/svelte/tests/runtime-runes/samples/export-binding/main.svelte b/packages/svelte/tests/runtime-runes/samples/export-binding/main.svelte deleted file mode 100644 index 4ad1684701..0000000000 --- a/packages/svelte/tests/runtime-runes/samples/export-binding/main.svelte +++ /dev/null @@ -1,7 +0,0 @@ -<script> - import Counter from './counter/index.svelte'; - let increment; -</script> - -<Counter bind:increment={increment} /> -<button onclick={increment}>increment</button> diff --git a/packages/svelte/tests/runtime-runes/samples/props-not-bindable-spread/Counter.svelte b/packages/svelte/tests/runtime-runes/samples/props-not-bindable-spread/Counter.svelte deleted file mode 100644 index f22fd6e976..0000000000 --- a/packages/svelte/tests/runtime-runes/samples/props-not-bindable-spread/Counter.svelte +++ /dev/null @@ -1,5 +0,0 @@ -<script> - let { ...rest } = $props(); -</script> - -{rest.count} diff --git a/packages/svelte/tests/runtime-runes/samples/props-not-bindable-spread/_config.js b/packages/svelte/tests/runtime-runes/samples/props-not-bindable-spread/_config.js deleted file mode 100644 index fa0994c370..0000000000 --- a/packages/svelte/tests/runtime-runes/samples/props-not-bindable-spread/_config.js +++ /dev/null @@ -1,13 +0,0 @@ -import { test } from '../../test'; - -export default test({ - compileOptions: { - dev: true - }, - - html: '0', - - error: - 'bind_not_bindable\n' + - 'A component is attempting to bind to a non-bindable property `count` belonging to Counter.svelte (i.e. `<Counter bind:count={...}>`). To mark a property as bindable: `let { count = $bindable() } = $props()`' -}); diff --git a/packages/svelte/tests/runtime-runes/samples/props-not-bindable-spread/main.svelte b/packages/svelte/tests/runtime-runes/samples/props-not-bindable-spread/main.svelte deleted file mode 100644 index 80242b75c6..0000000000 --- a/packages/svelte/tests/runtime-runes/samples/props-not-bindable-spread/main.svelte +++ /dev/null @@ -1,7 +0,0 @@ -<script> - import Counter from './Counter.svelte'; - - let count = $state(0); -</script> - -<Counter bind:count /> diff --git a/packages/svelte/tests/runtime-runes/samples/props-not-bindable/Counter.svelte b/packages/svelte/tests/runtime-runes/samples/props-not-bindable/Counter.svelte deleted file mode 100644 index 4bc2db3968..0000000000 --- a/packages/svelte/tests/runtime-runes/samples/props-not-bindable/Counter.svelte +++ /dev/null @@ -1,5 +0,0 @@ -<script> - let { count } = $props(); -</script> - -{count} diff --git a/packages/svelte/tests/runtime-runes/samples/props-not-bindable/_config.js b/packages/svelte/tests/runtime-runes/samples/props-not-bindable/_config.js deleted file mode 100644 index fa0994c370..0000000000 --- a/packages/svelte/tests/runtime-runes/samples/props-not-bindable/_config.js +++ /dev/null @@ -1,13 +0,0 @@ -import { test } from '../../test'; - -export default test({ - compileOptions: { - dev: true - }, - - html: '0', - - error: - 'bind_not_bindable\n' + - 'A component is attempting to bind to a non-bindable property `count` belonging to Counter.svelte (i.e. `<Counter bind:count={...}>`). To mark a property as bindable: `let { count = $bindable() } = $props()`' -}); diff --git a/packages/svelte/tests/runtime-runes/samples/props-not-bindable/main.svelte b/packages/svelte/tests/runtime-runes/samples/props-not-bindable/main.svelte deleted file mode 100644 index 80242b75c6..0000000000 --- a/packages/svelte/tests/runtime-runes/samples/props-not-bindable/main.svelte +++ /dev/null @@ -1,7 +0,0 @@ -<script> - import Counter from './Counter.svelte'; - - let count = $state(0); -</script> - -<Counter bind:count /> From a2565efa37dfbba2e462eb5cdbb6c47424ce98ad Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Wed, 8 Jan 2025 19:37:26 +0100 Subject: [PATCH 44/63] docs: tweak "invalid assignment" compiler error message (#14955) * docs: tweak "invalid assignment" compiler error message fixes #14702 * tweak wording --------- Co-authored-by: Rich Harris <rich.harris@vercel.com> --- .changeset/sharp-dryers-try.md | 5 +++ .../98-reference/.generated/compile-errors.md | 34 ++++++++++++++++++- .../svelte/messages/compile-errors/script.md | 34 ++++++++++++++++++- packages/svelte/src/compiler/errors.js | 4 +-- .../_config.js | 2 +- .../runes-invalid-each-binding/_config.js | 2 +- .../runes-invalid-each-mutation/_config.js | 2 +- 7 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 .changeset/sharp-dryers-try.md diff --git a/.changeset/sharp-dryers-try.md b/.changeset/sharp-dryers-try.md new file mode 100644 index 0000000000..dcdbd99d02 --- /dev/null +++ b/.changeset/sharp-dryers-try.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +chore: tweak "invalid assignment" compiler error message diff --git a/documentation/docs/98-reference/.generated/compile-errors.md b/documentation/docs/98-reference/.generated/compile-errors.md index c498920007..a867cfe88c 100644 --- a/documentation/docs/98-reference/.generated/compile-errors.md +++ b/documentation/docs/98-reference/.generated/compile-errors.md @@ -331,7 +331,39 @@ The $ prefix is reserved, and cannot be used for variables and imports ### each_item_invalid_assignment ``` -Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. `array[i] = value` instead of `entry = value`) +Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. `array[i] = value` instead of `entry = value`, or `bind:value={array[i]}` instead of `bind:value={entry}`) +``` + +In legacy mode, it was possible to reassign or bind to the each block argument itself: + +```svelte +<script> + let array = [1, 2, 3]; +</script> + +{#each array as entry} + <!-- reassignment --> + <button on:click={() => entry = 4}>change</button> + + <!-- binding --> + <input bind:value={entry}> +{/each} +``` + +This turned out to be buggy and unpredictable, particularly when working with derived values (such as `array.map(...)`), and as such is forbidden in runes mode. You can achieve the same outcome by using the index instead: + +```svelte +<script> + let array = $state([1, 2, 3]); +</script> + +{#each array as entry, i} + <!-- reassignment --> + <button onclick={() => array[i] = 4}>change</button> + + <!-- binding --> + <input bind:value={array[i]}> +{/each} ``` ### effect_invalid_placement diff --git a/packages/svelte/messages/compile-errors/script.md b/packages/svelte/messages/compile-errors/script.md index fa851cec89..0aa6fbed90 100644 --- a/packages/svelte/messages/compile-errors/script.md +++ b/packages/svelte/messages/compile-errors/script.md @@ -32,7 +32,39 @@ ## each_item_invalid_assignment -> Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. `array[i] = value` instead of `entry = value`) +> Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. `array[i] = value` instead of `entry = value`, or `bind:value={array[i]}` instead of `bind:value={entry}`) + +In legacy mode, it was possible to reassign or bind to the each block argument itself: + +```svelte +<script> + let array = [1, 2, 3]; +</script> + +{#each array as entry} + <!-- reassignment --> + <button on:click={() => entry = 4}>change</button> + + <!-- binding --> + <input bind:value={entry}> +{/each} +``` + +This turned out to be buggy and unpredictable, particularly when working with derived values (such as `array.map(...)`), and as such is forbidden in runes mode. You can achieve the same outcome by using the index instead: + +```svelte +<script> + let array = $state([1, 2, 3]); +</script> + +{#each array as entry, i} + <!-- reassignment --> + <button onclick={() => array[i] = 4}>change</button> + + <!-- binding --> + <input bind:value={array[i]}> +{/each} +``` ## effect_invalid_placement diff --git a/packages/svelte/src/compiler/errors.js b/packages/svelte/src/compiler/errors.js index 870cd9ac09..a997eeef8d 100644 --- a/packages/svelte/src/compiler/errors.js +++ b/packages/svelte/src/compiler/errors.js @@ -151,12 +151,12 @@ export function dollar_prefix_invalid(node) { } /** - * Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. `array[i] = value` instead of `entry = value`) + * Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. `array[i] = value` instead of `entry = value`, or `bind:value={array[i]}` instead of `bind:value={entry}`) * @param {null | number | NodeLike} node * @returns {never} */ export function each_item_invalid_assignment(node) { - e(node, "each_item_invalid_assignment", `Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. \`array[i] = value\` instead of \`entry = value\`)\nhttps://svelte.dev/e/each_item_invalid_assignment`); + e(node, "each_item_invalid_assignment", `Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. \`array[i] = value\` instead of \`entry = value\`, or \`bind:value={array[i]}\` instead of \`bind:value={entry}\`)\nhttps://svelte.dev/e/each_item_invalid_assignment`); } /** diff --git a/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-binding-this/_config.js b/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-binding-this/_config.js index 524c2f161c..ed02e0960d 100644 --- a/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-binding-this/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-binding-this/_config.js @@ -4,6 +4,6 @@ export default test({ error: { code: 'each_item_invalid_assignment', message: - 'Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. `array[i] = value` instead of `entry = value`)' + 'Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. `array[i] = value` instead of `entry = value`, or `bind:value={array[i]}` instead of `bind:value={entry}`)' } }); diff --git a/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-binding/_config.js b/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-binding/_config.js index 524c2f161c..ed02e0960d 100644 --- a/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-binding/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-binding/_config.js @@ -4,6 +4,6 @@ export default test({ error: { code: 'each_item_invalid_assignment', message: - 'Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. `array[i] = value` instead of `entry = value`)' + 'Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. `array[i] = value` instead of `entry = value`, or `bind:value={array[i]}` instead of `bind:value={entry}`)' } }); diff --git a/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-mutation/_config.js b/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-mutation/_config.js index 524c2f161c..ed02e0960d 100644 --- a/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-mutation/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/runes-invalid-each-mutation/_config.js @@ -4,6 +4,6 @@ export default test({ error: { code: 'each_item_invalid_assignment', message: - 'Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. `array[i] = value` instead of `entry = value`)' + 'Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. `array[i] = value` instead of `entry = value`, or `bind:value={array[i]}` instead of `bind:value={entry}`)' } }); From 9aae463ae1be27a75e876a7a6f6bcfe5b023c19f Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Wed, 8 Jan 2025 20:03:04 +0100 Subject: [PATCH 45/63] fix: silence false-positive statel value warning (#14958) fixes #14687 --- .changeset/tough-guests-sniff.md | 5 ++++ .../client/visitors/AssignmentExpression.js | 1 + .../_config.js | 24 ++++++++++++++----- .../main.svelte | 4 +++- 4 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 .changeset/tough-guests-sniff.md diff --git a/.changeset/tough-guests-sniff.md b/.changeset/tough-guests-sniff.md new file mode 100644 index 0000000000..fcb7b67c1a --- /dev/null +++ b/.changeset/tough-guests-sniff.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: silence false-positive stale value warning diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/AssignmentExpression.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/AssignmentExpression.js index 3d8b9aaa96..0c70f7e00c 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/AssignmentExpression.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/AssignmentExpression.js @@ -171,6 +171,7 @@ function build_assignment(operator, left, right, context) { // special case — ignore `bind:prop={getter, (v) => (...)}` / `bind:value={x.y}` if ( + path.at(-1) === 'BindDirective' || path.at(-1) === 'Component' || path.at(-1) === 'SvelteComponent' || (path.at(-1) === 'ArrowFunctionExpression' && diff --git a/packages/svelte/tests/runtime-runes/samples/proxy-coercive-assignment-warning/_config.js b/packages/svelte/tests/runtime-runes/samples/proxy-coercive-assignment-warning/_config.js index ad7bdc654a..f029227472 100644 --- a/packages/svelte/tests/runtime-runes/samples/proxy-coercive-assignment-warning/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/proxy-coercive-assignment-warning/_config.js @@ -1,21 +1,33 @@ import { flushSync } from 'svelte'; -import { test } from '../../test'; +import { ok, test } from '../../test'; export default test({ compileOptions: { dev: true }, - html: `<button>items: null</button> <div>x</div>`, + html: `<button>items: null</button> <div>x</div> <input type="checkbox" value="1"><input type="checkbox" value="2">`, test({ assert, target, warnings }) { const btn = target.querySelector('button'); + ok(btn); - flushSync(() => btn?.click()); - assert.htmlEqual(target.innerHTML, `<button>items: []</button> <div>x</div>`); + flushSync(() => btn.click()); + assert.htmlEqual( + target.innerHTML, + `<button>items: []</button> <div>x</div> <input type="checkbox" value="1"><input type="checkbox" value="2">` + ); - flushSync(() => btn?.click()); - assert.htmlEqual(target.innerHTML, `<button>items: [0]</button> <div>x</div>`); + flushSync(() => btn.click()); + assert.htmlEqual( + target.innerHTML, + `<button>items: [0]</button> <div>x</div> <input type="checkbox" value="1"><input type="checkbox" value="2">` + ); + + const input = target.querySelector('input'); + ok(input); + input.checked = true; + flushSync(() => input.dispatchEvent(new Event('change', { bubbles: true }))); assert.deepEqual(warnings, [ 'Assignment to `items` property (main.svelte:8:24) will evaluate to the right-hand side, not the value of `items` following the assignment. This may result in unexpected behaviour.' diff --git a/packages/svelte/tests/runtime-runes/samples/proxy-coercive-assignment-warning/main.svelte b/packages/svelte/tests/runtime-runes/samples/proxy-coercive-assignment-warning/main.svelte index 40592e08b8..ad94c4e56e 100644 --- a/packages/svelte/tests/runtime-runes/samples/proxy-coercive-assignment-warning/main.svelte +++ b/packages/svelte/tests/runtime-runes/samples/proxy-coercive-assignment-warning/main.svelte @@ -2,7 +2,7 @@ import Test from './Test.svelte'; let entries = $state([]); - let object = $state({ items: null }); + let object = $state({ items: null, group: [] }); </script> <button onclick={() => (object.items ??= []).push(object.items.length)}> @@ -11,6 +11,8 @@ <!-- these should not emit warnings --> <div bind:this={entries[0]}>x</div> +<input type="checkbox" value=1 bind:group={object.group}> +<input type="checkbox" value=2 bind:group={object.group}> <Test bind:this={entries[1]}></Test> <Test bind:this={() => entries[2], (v) => (entries[2] = v)}></Test> <Test bind:x={entries[3]}></Test> From 80d9f9996f4aec24e6ab4542225a5dffa297b5c7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 8 Jan 2025 14:12:06 -0500 Subject: [PATCH 46/63] Version Packages (#14953) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> --- .changeset/flat-otters-cheer.md | 5 ----- .changeset/sharp-dryers-try.md | 5 ----- .changeset/tough-guests-sniff.md | 5 ----- packages/svelte/CHANGELOG.md | 10 ++++++++++ packages/svelte/package.json | 2 +- packages/svelte/src/version.js | 2 +- 6 files changed, 12 insertions(+), 17 deletions(-) delete mode 100644 .changeset/flat-otters-cheer.md delete mode 100644 .changeset/sharp-dryers-try.md delete mode 100644 .changeset/tough-guests-sniff.md diff --git a/.changeset/flat-otters-cheer.md b/.changeset/flat-otters-cheer.md deleted file mode 100644 index 3f84de8242..0000000000 --- a/.changeset/flat-otters-cheer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: remove bindable prop validation diff --git a/.changeset/sharp-dryers-try.md b/.changeset/sharp-dryers-try.md deleted file mode 100644 index dcdbd99d02..0000000000 --- a/.changeset/sharp-dryers-try.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -chore: tweak "invalid assignment" compiler error message diff --git a/.changeset/tough-guests-sniff.md b/.changeset/tough-guests-sniff.md deleted file mode 100644 index fcb7b67c1a..0000000000 --- a/.changeset/tough-guests-sniff.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: silence false-positive stale value warning diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index daf8ed209a..72fa09bf96 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,15 @@ # svelte +## 5.17.1 + +### Patch Changes + +- fix: remove bindable prop validation ([#14946](https://github.com/sveltejs/svelte/pull/14946)) + +- chore: tweak "invalid assignment" compiler error message ([#14955](https://github.com/sveltejs/svelte/pull/14955)) + +- fix: silence false-positive stale value warning ([#14958](https://github.com/sveltejs/svelte/pull/14958)) + ## 5.17.0 ### Minor Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 5cd078bf77..ce6e4ffc42 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -2,7 +2,7 @@ "name": "svelte", "description": "Cybernetically enhanced web apps", "license": "MIT", - "version": "5.17.0", + "version": "5.17.1", "type": "module", "types": "./types/index.d.ts", "engines": { diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js index 396c2b07ef..bb772687fb 100644 --- a/packages/svelte/src/version.js +++ b/packages/svelte/src/version.js @@ -4,5 +4,5 @@ * The current version, as set in package.json. * @type {string} */ -export const VERSION = '5.17.0'; +export const VERSION = '5.17.1'; export const PUBLIC_VERSION = '5'; From 79a67c95618a631129997e542fca66266a63d500 Mon Sep 17 00:00:00 2001 From: Rich Harris <rich.harris@vercel.com> Date: Wed, 8 Jan 2025 15:04:41 -0500 Subject: [PATCH 47/63] fix: account for parent scale when animating elements (#14957) * WIP fix flip * fix: account for parent scale when animating elements --- .changeset/long-weeks-brush.md | 5 +++++ packages/svelte/src/animate/index.js | 32 ++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 .changeset/long-weeks-brush.md diff --git a/.changeset/long-weeks-brush.md b/.changeset/long-weeks-brush.md new file mode 100644 index 0000000000..b0e184caa0 --- /dev/null +++ b/.changeset/long-weeks-brush.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: account for parent scale when animating elements diff --git a/packages/svelte/src/animate/index.js b/packages/svelte/src/animate/index.js index fbf2ac83e2..2ce7708bc7 100644 --- a/packages/svelte/src/animate/index.js +++ b/packages/svelte/src/animate/index.js @@ -11,18 +11,37 @@ import { cubicOut } from '../easing/index.js'; * @returns {AnimationConfig} */ export function flip(node, { from, to }, params = {}) { + var { delay = 0, duration = (d) => Math.sqrt(d) * 120, easing = cubicOut } = params; + var style = getComputedStyle(node); - var zoom = get_zoom(node); // https://drafts.csswg.org/css-viewport/#effective-zoom + // find the transform origin, expressed as a pair of values between 0 and 1 var transform = style.transform === 'none' ? '' : style.transform; var [ox, oy] = style.transformOrigin.split(' ').map(parseFloat); + ox /= node.clientWidth; + oy /= node.clientHeight; + + // calculate effect of parent transforms and zoom + var zoom = get_zoom(node); // https://drafts.csswg.org/css-viewport/#effective-zoom + var sx = node.clientWidth / to.width / zoom; + var sy = node.clientHeight / to.height / zoom; + + // find the starting position of the transform origin + var fx = from.left + from.width * ox; + var fy = from.top + from.height * oy; + + // find the ending position of the transform origin + var tx = to.left + to.width * ox; + var ty = to.top + to.height * oy; + + // find the translation at the start of the transform + var dx = (fx - tx) * sx; + var dy = (fy - ty) * sy; + + // find the relative scale at the start of the transform var dsx = from.width / to.width; var dsy = from.height / to.height; - var dx = (from.left + dsx * ox - (to.left + ox)) / zoom; - var dy = (from.top + dsy * oy - (to.top + oy)) / zoom; - var { delay = 0, duration = (d) => Math.sqrt(d) * 120, easing = cubicOut } = params; - return { delay, duration: typeof duration === 'function' ? duration(Math.sqrt(dx * dx + dy * dy)) : duration, @@ -32,7 +51,8 @@ export function flip(node, { from, to }, params = {}) { var y = u * dy; var sx = t + u * dsx; var sy = t + u * dsy; - return `transform: ${transform} scale(${sx}, ${sy}) translate(${x}px, ${y}px);`; + + return `transform: ${transform} translate(${x}px, ${y}px) scale(${sx}, ${sy});`; } }; } From bf80c10625d488a479bf0c69bd3e7c0fa7fe82bb Mon Sep 17 00:00:00 2001 From: Basti Ortiz <39114273+BastiDood@users.noreply.github.com> Date: Thu, 9 Jan 2025 04:16:53 +0800 Subject: [PATCH 48/63] docs: clarify example on dynamic dependency tracking (#13767) * docs(effect): clarify example on dynamic dependency tracking * use an if block, it's clearer * fix * toggle --------- Co-authored-by: Rich Harris <rich.harris@vercel.com> --- documentation/docs/02-runes/04-$effect.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/documentation/docs/02-runes/04-$effect.md b/documentation/docs/02-runes/04-$effect.md index c48a82f9a5..1ea960de70 100644 --- a/documentation/docs/02-runes/04-$effect.md +++ b/documentation/docs/02-runes/04-$effect.md @@ -125,7 +125,11 @@ An effect only reruns when the object it reads changes, not when a property insi <p>{state.value} doubled is {derived.value}</p> ``` -An effect only depends on the values that it read the last time it ran. If `a` is true, changes to `b` will [not cause this effect to rerun](/playground/untitled#H4sIAAAAAAAAE3WQ0WrDMAxFf0U1hTow1vcsMfQ7lj3YjlxEXTvEymC4_vfFC6Ewtidxde8RkrJw5DGJ9j2LoO8oWnGZJvEi-GuqIn2iZ1x1istsa6dLdqaJ1RAG9sigoYdjYs0onfYJm7fdMX85q3dE59CylA30CnJtDWxjSNHjq49XeZqXEChcT9usLUAOpIbHA0yzM78oColGhDVofLS3neZSS6mqOz-XD51ZmGOAGKwne-vztk-956CL0kAJsi7decupf4l658EUZX4I8yTWt93jSI5wFC3PC5aP8g0Aje5DcQEAAA==): +An effect only depends on the values that it read the last time it ran. This has interesting implications for effects that have conditional code. + +For instance, if `a` is `true` in the code snippet below, the code inside the `if` block will run and `b` will be evaluated. As such, changes to either `a` or `b` [will cause the effect to re-run](/playground/untitled#H4sIAAAAAAAAE3VQzWrDMAx-FdUU4kBp71li6EPstOxge0ox8-QQK2PD-N1nLy2F0Z2Evj9_chKkP1B04pnYscc3cRCT8xhF95IEf8-Vq0DBr8rzPB_jJ3qumNERH-E2ECNxiRF9tIubWY00lgcYNAywj6wZJS8rtk83wjwgCrXHaULLUrYwKEgVGrnkx-Dx6MNFNstK5OjSbFGbwE0gdXuT_zGYrjmAuco515Hr1p_uXak3K3MgCGS9s-9D2grU-judlQYXIencnzad-tdR79qZrMyvw9wd5Z8Yv1h09dz8mn8AkM7Pfo0BAAA=). + +Conversely, if `a` is `false`, `b` will not be evaluated, and the effect will _only_ re-run when `a` changes. ```ts let a = false; @@ -134,8 +138,8 @@ let b = false; $effect(() => { console.log('running'); - if (a || b) { - console.log('inside if block'); + if (a) { + console.log('b:', b); } }); ``` From d15aea4e187a9ef05297fd04a83023d3ccbc0bef Mon Sep 17 00:00:00 2001 From: Gonzalo Ruiz <rgon@outlook.com> Date: Wed, 8 Jan 2025 21:32:57 +0100 Subject: [PATCH 49/63] docs: clarify svelte:component migration, avoids common gotcha (#13835) * docs: clarify svelte:component migration to avoid lowercase component name gotcha * docs: move <svelte:component> section out of Breaking Changes, since it is not breaking. Change links. * docs: move migration dot notation component initialization notes to svelte:component section * tweaks * fix link --------- Co-authored-by: Gonzalo Ruiz <rgon@rgon.es> Co-authored-by: Rich Harris <rich.harris@vercel.com> --- .../docs/07-misc/07-v5-migration-guide.md | 93 +++++++++---------- .../99-legacy/30-legacy-svelte-component.md | 2 +- 2 files changed, 45 insertions(+), 50 deletions(-) diff --git a/documentation/docs/07-misc/07-v5-migration-guide.md b/documentation/docs/07-misc/07-v5-migration-guide.md index 09ea84f26c..29179cd849 100644 --- a/documentation/docs/07-misc/07-v5-migration-guide.md +++ b/documentation/docs/07-misc/07-v5-migration-guide.md @@ -597,29 +597,58 @@ export declare const MyComponent: Component<{ To declare that a component of a certain type is required: -```svelte -<script lang="ts"> - import type { ---SvelteComponent--- +++Component+++ } from 'svelte'; - import { - ComponentA, - ComponentB - } from 'component-library'; - - ---let component: typeof SvelteComponent<{ foo: string }>--- - +++let component: Component<{ foo: string }>+++ = $state( - Math.random() ? ComponentA : ComponentB - ); -</script> +```js +import { ComponentA, ComponentB } from 'component-library'; +---import type { SvelteComponent } from 'svelte';--- ++++import type { Component } from 'svelte';+++ -<svelte:component this={component} foo="bar" /> +---let C: typeof SvelteComponent<{ foo: string }> = $state(--- ++++let C: Component<{ foo: string }> = $state(+++ + Math.random() ? ComponentA : ComponentB +); ``` -The two utility types `ComponentEvents` and `ComponentType` are also deprecated. `ComponentEvents` is obsolete because events are defined as callback props now, and `ComponentType` is obsolete because the new `Component` type is the component type already (e.g. `ComponentType<SvelteComponent<{ prop: string }>>` == `Component<{ prop: string }>`). +The two utility types `ComponentEvents` and `ComponentType` are also deprecated. `ComponentEvents` is obsolete because events are defined as callback props now, and `ComponentType` is obsolete because the new `Component` type is the component type already (i.e. `ComponentType<SvelteComponent<{ prop: string }>>` is equivalent to `Component<{ prop: string }>`). ### bind:this changes Because components are no longer classes, using `bind:this` no longer returns a class instance with `$set`, `$on` and `$destroy` methods on it. It only returns the instance exports (`export function/const`) and, if you're using the `accessors` option, a getter/setter-pair for each property. +## `<svelte:component>` is no longer necessary + +In Svelte 4, components are _static_ — if you render `<Thing>`, and the value of `Thing` changes, [nothing happens](/playground/7f1fa24f0ab44c1089dcbb03568f8dfa?version=4.2.18). To make it dynamic you had to use `<svelte:component>`. + +This is no longer true in Svelte 5: + +```svelte +<script> + import A from './A.svelte'; + import B from './B.svelte'; + + let Thing = $state(); +</script> + +<select bind:value={Thing}> + <option value={A}>A</option> + <option value={B}>B</option> +</select> + +<!-- these are equivalent --> +<Thing /> +<svelte:component this={Thing} /> +``` +While migrating, keep in mind that your component's name should be capitalized (`Thing`) to distinguish it from elements, unless using dot notation. + +### Dot notation indicates a component + +In Svelte 4, `<foo.bar>` would create an element with a tag name of `"foo.bar"`. In Svelte 5, `foo.bar` is treated as a component instead. This is particularly useful inside `each` blocks: + +```svelte +{#each items as item} + <item.component {...item.props} /> +{/each} +``` + ## Whitespace handling changed Previously, Svelte employed a very complicated algorithm to determine if whitespace should be kept or not. Svelte 5 simplifies this which makes it easier to reason about as a developer. The rules are: @@ -653,16 +682,6 @@ The `legacy` compiler option, which generated bulkier but IE-friendly code, no l Content inside component tags becomes a snippet prop called `children`. You cannot have a separate prop by that name. -## Dot notation indicates a component - -In Svelte 4, `<foo.bar>` would create an element with a tag name of `"foo.bar"`. In Svelte 5, `foo.bar` is treated as a component instead. This is particularly useful inside `each` blocks: - -```svelte -{#each items as item} - <item.component {...item.props} /> -{/each} -``` - ## Breaking changes in runes mode Some breaking changes only apply once your component is in runes mode. @@ -700,30 +719,6 @@ In Svelte 4, doing the following triggered reactivity: This is because the Svelte compiler treated the assignment to `foo.value` as an instruction to update anything that referenced `foo`. In Svelte 5, reactivity is determined at runtime rather than compile time, so you should define `value` as a reactive `$state` field on the `Foo` class. Wrapping `new Foo()` with `$state(...)` will have no effect — only vanilla objects and arrays are made deeply reactive. -### `<svelte:component>` is no longer necessary - -In Svelte 4, components are _static_ — if you render `<Thing>`, and the value of `Thing` changes, [nothing happens](/playground/7f1fa24f0ab44c1089dcbb03568f8dfa?version=4.2.18). To make it dynamic you must use `<svelte:component>`. - -This is no longer true in Svelte 5: - -```svelte -<script> - import A from './A.svelte'; - import B from './B.svelte'; - - let Thing = $state(); -</script> - -<select bind:value={Thing}> - <option value={A}>A</option> - <option value={B}>B</option> -</select> - -<!-- these are equivalent --> -<Thing /> -<svelte:component this={Thing} /> -``` - ### Touch and wheel events are passive When using `onwheel`, `onmousewheel`, `ontouchstart` and `ontouchmove` event attributes, the handlers are [passive](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#using_passive_listeners) to align with browser defaults. This greatly improves responsiveness by allowing the browser to scroll the document immediately, rather than waiting to see if the event handler calls `event.preventDefault()`. diff --git a/documentation/docs/99-legacy/30-legacy-svelte-component.md b/documentation/docs/99-legacy/30-legacy-svelte-component.md index 3da2e3350e..a0407e58bf 100644 --- a/documentation/docs/99-legacy/30-legacy-svelte-component.md +++ b/documentation/docs/99-legacy/30-legacy-svelte-component.md @@ -2,7 +2,7 @@ title: <svelte:component> --- -In runes mode, `<MyComponent>` will re-render if the value of `MyComponent` changes. See the [Svelte 5 migration guide](/docs/svelte/v5-migration-guide#Breaking-changes-in-runes-mode-svelte:component-is-no-longer-necessary) for an example. +In runes mode, `<MyComponent>` will re-render if the value of `MyComponent` changes. See the [Svelte 5 migration guide](/docs/svelte/v5-migration-guide#svelte:component-is-no-longer-necessary) for an example. In legacy mode, it won't — we must use `<svelte:component>`, which destroys and recreates the component instance when the value of its `this` expression changes: From 3e11b892447a466c95ed85d6a7fd14c54b9c5200 Mon Sep 17 00:00:00 2001 From: Matei Trandafir <catalin_trand2@yahoo.com> Date: Wed, 8 Jan 2025 22:54:41 +0200 Subject: [PATCH 50/63] docs: improve section for snippets-slots interop (#13869) * docs: improve section for snippets-slots interop * tweak --------- Co-authored-by: Rich Harris <rich.harris@vercel.com> --- .../docs/07-misc/07-v5-migration-guide.md | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/documentation/docs/07-misc/07-v5-migration-guide.md b/documentation/docs/07-misc/07-v5-migration-guide.md index 29179cd849..ce95bf6ac7 100644 --- a/documentation/docs/07-misc/07-v5-migration-guide.md +++ b/documentation/docs/07-misc/07-v5-migration-guide.md @@ -339,7 +339,31 @@ When spreading props, local event handlers must go _after_ the spread, or they r In Svelte 4, content can be passed to components using slots. Svelte 5 replaces them with snippets which are more powerful and flexible, and as such slots are deprecated in Svelte 5. -They continue to work, however, and you can mix and match snippets and slots in your components. +They continue to work, however, and you can pass snippets to a component that uses slots: + +```svelte +<!--- file: Child.svelte ---> +<slot /> +<hr /> +<slot name="foo" message="hello" /> +``` + +```svelte +<!--- file: Parent.svelte ---> +<script> + import Child from './Child.svelte'; +</script> + +<Child> + default child content + + {#snippet foo({ message })} + message from child: {message} + {/snippet} +</Child> +``` + +(The reverse is not true — you cannot pass slotted content to a component that uses [`{@render ...}`](/docs/svelte/@render) tags.) When using custom elements, you should still use `<slot />` like before. In a future version, when Svelte removes its internal version of slots, it will leave those slots as-is, i.e. output a regular DOM tag instead of transforming it. From 68cffa84892c20717dc7d0e49a3a3af2f403f689 Mon Sep 17 00:00:00 2001 From: Rich Harris <rich.harris@vercel.com> Date: Wed, 8 Jan 2025 16:17:32 -0500 Subject: [PATCH 51/63] fix: apply `overflow: hidden` style when transitioning elements, where necessary (#14930) * fix: apply `overflow: hidden` style when transitioning elements, where necessary * notes to self --- .changeset/sixty-paws-compete.md | 5 ++++ .../client/dom/elements/transitions.js | 26 +++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 .changeset/sixty-paws-compete.md diff --git a/.changeset/sixty-paws-compete.md b/.changeset/sixty-paws-compete.md new file mode 100644 index 0000000000..2fa3f9e84f --- /dev/null +++ b/.changeset/sixty-paws-compete.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: apply `overflow: hidden` style when transitioning elements, where necessary diff --git a/packages/svelte/src/internal/client/dom/elements/transitions.js b/packages/svelte/src/internal/client/dom/elements/transitions.js index dee029e88f..b3c16cdd08 100644 --- a/packages/svelte/src/internal/client/dom/elements/transitions.js +++ b/packages/svelte/src/internal/client/dom/elements/transitions.js @@ -192,6 +192,13 @@ export function transition(flags, element, get_fn, get_params) { var inert = element.inert; + /** + * The default overflow style, stashed so we can revert changes during the transition + * that are necessary to work around a Safari <18 bug + * TODO 6.0 remove this, if older versions of Safari have died out enough + */ + var overflow = element.style.overflow; + /** @type {Animation | undefined} */ var intro; @@ -242,6 +249,8 @@ export function transition(flags, element, get_fn, get_params) { // Ensure we cancel the animation to prevent leaking intro?.abort(); intro = current_options = undefined; + + element.style.overflow = overflow; }); }, out(fn) { @@ -382,16 +391,29 @@ function animate(element, options, counterpart, t2, on_finish) { var keyframes = []; if (duration > 0) { + /** + * Whether or not the CSS includes `overflow: hidden`, in which case we need to + * add it as an inline style to work around a Safari <18 bug + * TODO 6.0 remove this, if possible + */ + var needs_overflow_hidden = false; + if (css) { var n = Math.ceil(duration / (1000 / 60)); // `n` must be an integer, or we risk missing the `t2` value for (var i = 0; i <= n; i += 1) { var t = t1 + delta * easing(i / n); - var styles = css(t, 1 - t); - keyframes.push(css_to_keyframe(styles)); + var styles = css_to_keyframe(css(t, 1 - t)); + keyframes.push(styles); + + needs_overflow_hidden ||= styles.overflow === 'hidden'; } } + if (needs_overflow_hidden) { + /** @type {HTMLElement} */ (element).style.overflow = 'hidden'; + } + get_t = () => { var time = /** @type {number} */ ( /** @type {globalThis.Animation} */ (animation).currentTime From c0842d14596dff8a26b487dc6a75207d45198261 Mon Sep 17 00:00:00 2001 From: Rich Harris <rich.harris@vercel.com> Date: Thu, 9 Jan 2025 05:49:07 -0500 Subject: [PATCH 52/63] fix: properly add owners to function bindings (#14962) Closes #14956 --- .changeset/yellow-dodos-smell.md | 5 ++++ .../client/visitors/shared/component.js | 29 ++++++++++++------- .../ownership-function-bindings/Child.svelte | 5 ++++ .../ownership-function-bindings/_config.js | 20 +++++++++++++ .../ownership-function-bindings/main.svelte | 10 +++++++ 5 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 .changeset/yellow-dodos-smell.md create mode 100644 packages/svelte/tests/runtime-runes/samples/ownership-function-bindings/Child.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/ownership-function-bindings/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/ownership-function-bindings/main.svelte diff --git a/.changeset/yellow-dodos-smell.md b/.changeset/yellow-dodos-smell.md new file mode 100644 index 0000000000..ea2aead662 --- /dev/null +++ b/.changeset/yellow-dodos-smell.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: properly add owners to function bindings diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js index 068971145c..f509cb41a7 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js @@ -174,23 +174,32 @@ export function build_component(node, component_name, context, anchor = context. } else if (attribute.type === 'BindDirective') { const expression = /** @type {Expression} */ (context.visit(attribute.expression)); - if (dev && attribute.name !== 'this' && attribute.expression.type !== 'SequenceExpression') { - const left = object(attribute.expression); - let binding; + if (dev && attribute.name !== 'this') { + let should_add_owner = true; - if (left?.type === 'Identifier') { - binding = context.state.scope.get(left.name); + if (attribute.expression.type !== 'SequenceExpression') { + const left = object(attribute.expression); + + if (left?.type === 'Identifier') { + const binding = context.state.scope.get(left.name); + + // Only run ownership addition on $state fields. + // Theoretically someone could create a `$state` while creating `$state.raw` or inside a `$derived.by`, + // but that feels so much of an edge case that it doesn't warrant a perf hit for the common case. + if (binding?.kind === 'derived' || binding?.kind === 'raw_state') { + should_add_owner = false; + } + } } - // Only run ownership addition on $state fields. - // Theoretically someone could create a `$state` while creating `$state.raw` or inside a `$derived.by`, - // but that feels so much of an edge case that it doesn't warrant a perf hit for the common case. - if (binding?.kind !== 'derived' && binding?.kind !== 'raw_state') { + if (should_add_owner) { binding_initializers.push( b.stmt( b.call( b.id('$.add_owner_effect'), - b.thunk(expression), + expression.type === 'SequenceExpression' + ? expression.expressions[0] + : b.thunk(expression), b.id(component_name), is_ignored(node, 'ownership_invalid_binding') && b.true ) diff --git a/packages/svelte/tests/runtime-runes/samples/ownership-function-bindings/Child.svelte b/packages/svelte/tests/runtime-runes/samples/ownership-function-bindings/Child.svelte new file mode 100644 index 0000000000..ef91b0756d --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/ownership-function-bindings/Child.svelte @@ -0,0 +1,5 @@ +<script> + let { arr = $bindable() } = $props(); +</script> + +<button onclick={() => arr.push(arr.length)}></button> \ No newline at end of file diff --git a/packages/svelte/tests/runtime-runes/samples/ownership-function-bindings/_config.js b/packages/svelte/tests/runtime-runes/samples/ownership-function-bindings/_config.js new file mode 100644 index 0000000000..4c77aea206 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/ownership-function-bindings/_config.js @@ -0,0 +1,20 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + test({ target, warnings, assert }) { + const btn = target.querySelector('button'); + flushSync(() => { + btn?.click(); + }); + assert.deepEqual(warnings, []); + + flushSync(() => { + btn?.click(); + }); + assert.deepEqual(warnings, []); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/ownership-function-bindings/main.svelte b/packages/svelte/tests/runtime-runes/samples/ownership-function-bindings/main.svelte new file mode 100644 index 0000000000..4a3ce82726 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/ownership-function-bindings/main.svelte @@ -0,0 +1,10 @@ +<script> + import Child from './Child.svelte'; + + let arr = $state([]); + let arr2 = $state([]); + + let len = $derived(arr.length + arr2.length); +</script> + +<Child bind:arr={() => len % 2 === 0 ? arr : arr2, (v) => {}} /> \ No newline at end of file From b7400ae93b21f74030bd80a58f3d1e23edd1a5cf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 9 Jan 2025 08:41:06 -0500 Subject: [PATCH 53/63] Version Packages (#14959) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> --- .changeset/long-weeks-brush.md | 5 ----- .changeset/sixty-paws-compete.md | 5 ----- .changeset/yellow-dodos-smell.md | 5 ----- packages/svelte/CHANGELOG.md | 10 ++++++++++ packages/svelte/package.json | 2 +- packages/svelte/src/version.js | 2 +- 6 files changed, 12 insertions(+), 17 deletions(-) delete mode 100644 .changeset/long-weeks-brush.md delete mode 100644 .changeset/sixty-paws-compete.md delete mode 100644 .changeset/yellow-dodos-smell.md diff --git a/.changeset/long-weeks-brush.md b/.changeset/long-weeks-brush.md deleted file mode 100644 index b0e184caa0..0000000000 --- a/.changeset/long-weeks-brush.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: account for parent scale when animating elements diff --git a/.changeset/sixty-paws-compete.md b/.changeset/sixty-paws-compete.md deleted file mode 100644 index 2fa3f9e84f..0000000000 --- a/.changeset/sixty-paws-compete.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: apply `overflow: hidden` style when transitioning elements, where necessary diff --git a/.changeset/yellow-dodos-smell.md b/.changeset/yellow-dodos-smell.md deleted file mode 100644 index ea2aead662..0000000000 --- a/.changeset/yellow-dodos-smell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: properly add owners to function bindings diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index 72fa09bf96..6226fa851d 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,15 @@ # svelte +## 5.17.2 + +### Patch Changes + +- fix: account for parent scale when animating elements ([#14957](https://github.com/sveltejs/svelte/pull/14957)) + +- fix: apply `overflow: hidden` style when transitioning elements, where necessary ([#14930](https://github.com/sveltejs/svelte/pull/14930)) + +- fix: properly add owners to function bindings ([#14962](https://github.com/sveltejs/svelte/pull/14962)) + ## 5.17.1 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index ce6e4ffc42..3d5e350af0 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -2,7 +2,7 @@ "name": "svelte", "description": "Cybernetically enhanced web apps", "license": "MIT", - "version": "5.17.1", + "version": "5.17.2", "type": "module", "types": "./types/index.d.ts", "engines": { diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js index bb772687fb..99bf940854 100644 --- a/packages/svelte/src/version.js +++ b/packages/svelte/src/version.js @@ -4,5 +4,5 @@ * The current version, as set in package.json. * @type {string} */ -export const VERSION = '5.17.1'; +export const VERSION = '5.17.2'; export const PUBLIC_VERSION = '5'; From bdc02008e4f8012b439d4ee1c05be0cdbf4dad80 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway <trueadm@users.noreply.github.com> Date: Thu, 9 Jan 2025 16:26:27 +0000 Subject: [PATCH 54/63] fix: reset dependency read versions after reaction execution (#14964) * fix: reset dependency read versions after reaction execution * fix: reset dependency read versions after reaction execution * fix: reset dependency read versions after reaction execution * fix: reset dependency read versions after reaction execution * fix: reset dependency read versions after reaction execution * chore: add test * changeset --------- Co-authored-by: paoloricciuti <ricciutipaolo@gmail.com> Co-authored-by: Rich Harris <rich.harris@vercel.com> --- .changeset/fifty-chefs-invent.md | 5 +++++ .../svelte/src/internal/client/runtime.js | 8 ++++++++ .../Component.svelte | 7 +++++++ .../read-version-previous-reaction/_config.js | 19 +++++++++++++++++++ .../main.svelte | 18 ++++++++++++++++++ 5 files changed, 57 insertions(+) create mode 100644 .changeset/fifty-chefs-invent.md create mode 100644 packages/svelte/tests/runtime-runes/samples/read-version-previous-reaction/Component.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/read-version-previous-reaction/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/read-version-previous-reaction/main.svelte diff --git a/.changeset/fifty-chefs-invent.md b/.changeset/fifty-chefs-invent.md new file mode 100644 index 0000000000..eb151f67e2 --- /dev/null +++ b/.changeset/fifty-chefs-invent.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: reset dependency read versions after reaction execution diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index 202608ce06..3c8879eb31 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -434,6 +434,14 @@ export function update_reaction(reaction) { deps.length = skipped_deps; } + // If we are returning to an previous reaction then + // we need to increment the read version to ensure that + // any dependencies in this reaction aren't marked with + // the same version + if (previous_reaction !== null) { + read_version++; + } + return result; } finally { new_deps = previous_deps; diff --git a/packages/svelte/tests/runtime-runes/samples/read-version-previous-reaction/Component.svelte b/packages/svelte/tests/runtime-runes/samples/read-version-previous-reaction/Component.svelte new file mode 100644 index 0000000000..afb62ced2f --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/read-version-previous-reaction/Component.svelte @@ -0,0 +1,7 @@ +<script> + const { label = 0, size = 0 } = $props(); + + const title = $derived(size.toString()); +</script> + +<p {title}>{label}</p> diff --git a/packages/svelte/tests/runtime-runes/samples/read-version-previous-reaction/_config.js b/packages/svelte/tests/runtime-runes/samples/read-version-previous-reaction/_config.js new file mode 100644 index 0000000000..650e48e84c --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/read-version-previous-reaction/_config.js @@ -0,0 +1,19 @@ +import { ok, test } from '../../test'; +import { flushSync } from 'svelte'; + +export default test({ + html: `<button></button><p title="0">0</p>`, + + async test({ assert, target }) { + const p = target.querySelector('p'); + const btn = target.querySelector('button'); + flushSync(() => { + btn?.click(); + }); + assert.equal(p?.innerHTML, '1'); + flushSync(() => { + btn?.click(); + }); + assert.equal(p?.innerHTML, '2'); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/read-version-previous-reaction/main.svelte b/packages/svelte/tests/runtime-runes/samples/read-version-previous-reaction/main.svelte new file mode 100644 index 0000000000..773aabeea3 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/read-version-previous-reaction/main.svelte @@ -0,0 +1,18 @@ +<script> + import Component from "./Component.svelte"; + + let props = $state({ + label: 0, + size: 0, + }); + + let filteredProps = $state(); + + $effect.pre(() => { + filteredProps = $state.snapshot(props); + }); +</script> + +<button onclick={()=>props.label++}></button> + +<Component {...filteredProps} /> \ No newline at end of file From dc8ae825b8c3fb8c286d54116af8d11244343974 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 9 Jan 2025 11:36:14 -0500 Subject: [PATCH 55/63] Version Packages (#14965) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> --- .changeset/fifty-chefs-invent.md | 5 ----- packages/svelte/CHANGELOG.md | 6 ++++++ packages/svelte/package.json | 2 +- packages/svelte/src/version.js | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) delete mode 100644 .changeset/fifty-chefs-invent.md diff --git a/.changeset/fifty-chefs-invent.md b/.changeset/fifty-chefs-invent.md deleted file mode 100644 index eb151f67e2..0000000000 --- a/.changeset/fifty-chefs-invent.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: reset dependency read versions after reaction execution diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index 6226fa851d..6023c6d4e1 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,11 @@ # svelte +## 5.17.3 + +### Patch Changes + +- fix: reset dependency read versions after reaction execution ([#14964](https://github.com/sveltejs/svelte/pull/14964)) + ## 5.17.2 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 3d5e350af0..459786330b 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -2,7 +2,7 @@ "name": "svelte", "description": "Cybernetically enhanced web apps", "license": "MIT", - "version": "5.17.2", + "version": "5.17.3", "type": "module", "types": "./types/index.d.ts", "engines": { diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js index 99bf940854..0fd7d2f039 100644 --- a/packages/svelte/src/version.js +++ b/packages/svelte/src/version.js @@ -4,5 +4,5 @@ * The current version, as set in package.json. * @type {string} */ -export const VERSION = '5.17.2'; +export const VERSION = '5.17.3'; export const PUBLIC_VERSION = '5'; From dbe5818560241d5a1b221b6e160298da48aebbb9 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway <trueadm@users.noreply.github.com> Date: Fri, 10 Jan 2025 01:14:52 +0000 Subject: [PATCH 56/63] fix: wrap each block expression in derived to encapsulte effects (#14967) * fix: wrap each block expression in derived to encapsulte effects * add test * Update .changeset/tender-apples-scream.md --------- Co-authored-by: Rich Harris <rich.harris@vercel.com> --- .changeset/tender-apples-scream.md | 5 ++ .../src/internal/client/dom/blocks/each.js | 19 ++++---- .../samples/each-updates-9/_config.js | 16 +++++++ .../samples/each-updates-9/main.svelte | 46 +++++++++++++++++++ 4 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 .changeset/tender-apples-scream.md create mode 100644 packages/svelte/tests/runtime-runes/samples/each-updates-9/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/each-updates-9/main.svelte diff --git a/.changeset/tender-apples-scream.md b/.changeset/tender-apples-scream.md new file mode 100644 index 0000000000..836bdaffdf --- /dev/null +++ b/.changeset/tender-apples-scream.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: wrap each block expression in derived to encapsulate effects diff --git a/packages/svelte/src/internal/client/dom/blocks/each.js b/packages/svelte/src/internal/client/dom/blocks/each.js index 9e64055940..b17090948a 100644 --- a/packages/svelte/src/internal/client/dom/blocks/each.js +++ b/packages/svelte/src/internal/client/dom/blocks/each.js @@ -35,8 +35,9 @@ import { source, mutable_source, internal_set } from '../../reactivity/sources.j import { array_from, is_array } from '../../../shared/utils.js'; import { INERT } from '../../constants.js'; import { queue_micro_task } from '../task.js'; -import { active_effect, active_reaction } from '../../runtime.js'; +import { active_effect, active_reaction, get } from '../../runtime.js'; import { DEV } from 'esm-env'; +import { derived_safe_equal } from '../../reactivity/deriveds.js'; /** * The row of a keyed each block that is currently updating. We track this @@ -135,15 +136,17 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f var was_empty = false; - block(() => { + // TODO: ideally we could use derived for runes mode but because of the ability + // to use a store which can be mutated, we can't do that here as mutating a store + // will still result in the collection array being the same from the store + var each_array = derived_safe_equal(() => { var collection = get_collection(); - var array = is_array(collection) - ? collection - : collection == null - ? [] - : array_from(collection); + return is_array(collection) ? collection : collection == null ? [] : array_from(collection); + }); + block(() => { + var array = get(each_array); var length = array.length; if (was_empty && length === 0) { @@ -254,7 +257,7 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f // that a mutation occurred and it's made the collection MAYBE_DIRTY, so reading the // collection again can provide consistency to the reactive graph again as the deriveds // will now be `CLEAN`. - get_collection(); + get(each_array); }); if (hydrating) { diff --git a/packages/svelte/tests/runtime-runes/samples/each-updates-9/_config.js b/packages/svelte/tests/runtime-runes/samples/each-updates-9/_config.js new file mode 100644 index 0000000000..ee35058c59 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/each-updates-9/_config.js @@ -0,0 +1,16 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target, logs }) { + const [btn1] = target.querySelectorAll('button'); + + btn1.click(); + flushSync(); + + await Promise.resolve(); + await Promise.resolve(); + + assert.deepEqual(logs, ['cleanup']); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/each-updates-9/main.svelte b/packages/svelte/tests/runtime-runes/samples/each-updates-9/main.svelte new file mode 100644 index 0000000000..f5b2c8eb12 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/each-updates-9/main.svelte @@ -0,0 +1,46 @@ +<script> + import { createSubscriber } from 'svelte/reactivity'; + + class MyStore { + #subscribe; + #data = $state([ + ['a', [1, 2]], + ['b', [3, 4]] + ]); + #id; + + constructor(options) { + options?.someBoolean; + this.#id = options?.id; + this.#subscribe = createSubscriber(() => { + debugger + return () => { + console.log('cleanup'); + }; + }); + } + + get data() { + this.#subscribe(); + return this.#data; + } + set data(v) { + this.#data = v; + } + } + + let storeOptions = $state({ + someBoolean: false, + id: 0 + }); + + let myStore = $derived(new MyStore(storeOptions)); +</script> + +<button + onclick={() => { + storeOptions.someBoolean = !storeOptions.someBoolean; + }}>+</button +> + +{#each myStore.data as _}{/each} From 41fb51349e5846bdb406baba555d02cbf4f55b8e Mon Sep 17 00:00:00 2001 From: Paolo Ricciuti <ricciutipaolo@gmail.com> Date: Fri, 10 Jan 2025 11:28:18 +0100 Subject: [PATCH 57/63] fix: store access on component destroy (#14968) Co-authored-by: Oscar Dominguez <dominguez.celada@gmail.com> --- .changeset/hot-kings-shout.md | 5 +++ .../3-transform/client/transform-client.js | 31 +++++++++++++--- .../src/internal/client/reactivity/store.js | 37 ++++++++++++++----- .../store-update-on-destroy/Test.svelte | 12 ++++++ .../store-update-on-destroy/_config.js | 12 ++++++ .../store-update-on-destroy/main.svelte | 15 ++++++++ 6 files changed, 96 insertions(+), 16 deletions(-) create mode 100644 .changeset/hot-kings-shout.md create mode 100644 packages/svelte/tests/runtime-runes/samples/store-update-on-destroy/Test.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/store-update-on-destroy/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/store-update-on-destroy/main.svelte diff --git a/.changeset/hot-kings-shout.md b/.changeset/hot-kings-shout.md new file mode 100644 index 0000000000..afba164abf --- /dev/null +++ b/.changeset/hot-kings-shout.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: store access on component destroy diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js index a969117ed3..582c32b534 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js @@ -214,6 +214,8 @@ export function client_component(analysis, options) { /** @type {ESTree.VariableDeclaration[]} */ const legacy_reactive_declarations = []; + let needs_store_cleanup = false; + for (const [name, binding] of analysis.instance.scope.declarations) { if (binding.kind === 'legacy_reactive') { legacy_reactive_declarations.push( @@ -222,7 +224,10 @@ export function client_component(analysis, options) { } if (binding.kind === 'store_sub') { if (store_setup.length === 0) { - store_setup.push(b.const('$$stores', b.call('$.setup_stores'))); + needs_store_cleanup = true; + store_setup.push( + b.const(b.array_pattern([b.id('$$stores'), b.id('$$cleanup')]), b.call('$.setup_stores')) + ); } // We're creating an arrow function that gets the store value which minifies better for two or more references @@ -391,14 +396,28 @@ export function client_component(analysis, options) { analysis.reactive_statements.size > 0 || component_returned_object.length > 0; + // we want the cleanup function for the stores to run as the very last thing + // so that it can effectively clean up the store subscription even after the user effects runs if (should_inject_context) { component_block.body.unshift(b.stmt(b.call('$.push', ...push_args))); - component_block.body.push( - component_returned_object.length > 0 - ? b.return(b.call('$.pop', b.object(component_returned_object))) - : b.stmt(b.call('$.pop')) - ); + let to_push; + + if (component_returned_object.length > 0) { + let pop_call = b.call('$.pop', b.object(component_returned_object)); + to_push = needs_store_cleanup ? b.var('$$pop', pop_call) : b.return(pop_call); + } else { + to_push = b.stmt(b.call('$.pop')); + } + + component_block.body.push(to_push); + } + + if (needs_store_cleanup) { + component_block.body.push(b.stmt(b.call('$$cleanup'))); + if (component_returned_object.length > 0) { + component_block.body.push(b.return(b.id('$$pop'))); + } } if (analysis.uses_rest_props) { diff --git a/packages/svelte/src/internal/client/reactivity/store.js b/packages/svelte/src/internal/client/reactivity/store.js index 11eee23e0a..e7a92ee052 100644 --- a/packages/svelte/src/internal/client/reactivity/store.js +++ b/packages/svelte/src/internal/client/reactivity/store.js @@ -1,7 +1,8 @@ /** @import { StoreReferencesContainer } from '#client' */ /** @import { Store } from '#shared' */ import { subscribe_to_store } from '../../../store/utils.js'; -import { noop } from '../../shared/utils.js'; +import { get as get_store } from '../../../store/shared/index.js'; +import { define_property, noop } from '../../shared/utils.js'; import { get } from '../runtime.js'; import { teardown } from './effects.js'; import { mutable_source, set } from './sources.js'; @@ -13,6 +14,8 @@ import { mutable_source, set } from './sources.js'; */ let is_store_binding = false; +let IS_UNMOUNTED = Symbol(); + /** * Gets the current value of a store. If the store isn't subscribed to yet, it will create a proxy * signal that will be updated when the store is. The store references container is needed to @@ -30,7 +33,8 @@ export function store_get(store, store_name, stores) { unsubscribe: noop }); - if (entry.store !== store) { + // if the component that setup this is already unmounted we don't want to register a subscription + if (entry.store !== store && !(IS_UNMOUNTED in stores)) { entry.unsubscribe(); entry.store = store ?? null; @@ -54,6 +58,13 @@ export function store_get(store, store_name, stores) { } } + // if the component that setup this stores is already unmounted the source will be out of sync + // so we just use the `get` for the stores, less performant but it avoids to create a memory leak + // and it will keep the value consistent + if (store && IS_UNMOUNTED in stores) { + return get_store(store); + } + return get(entry.source); } @@ -103,20 +114,26 @@ export function invalidate_store(stores, store_name) { /** * Unsubscribes from all auto-subscribed stores on destroy - * @returns {StoreReferencesContainer} + * @returns {[StoreReferencesContainer, ()=>void]} */ export function setup_stores() { /** @type {StoreReferencesContainer} */ const stores = {}; - teardown(() => { - for (var store_name in stores) { - const ref = stores[store_name]; - ref.unsubscribe(); - } - }); + function cleanup() { + teardown(() => { + for (var store_name in stores) { + const ref = stores[store_name]; + ref.unsubscribe(); + } + define_property(stores, IS_UNMOUNTED, { + enumerable: false, + value: true + }); + }); + } - return stores; + return [stores, cleanup]; } /** diff --git a/packages/svelte/tests/runtime-runes/samples/store-update-on-destroy/Test.svelte b/packages/svelte/tests/runtime-runes/samples/store-update-on-destroy/Test.svelte new file mode 100644 index 0000000000..364a4a7aca --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/store-update-on-destroy/Test.svelte @@ -0,0 +1,12 @@ +<script lang="ts"> + const { store } = $props(); + + $effect(() => { + $store; + return () => { + console.log($store); + $store++; + console.log($store); + }; + }); +</script> diff --git a/packages/svelte/tests/runtime-runes/samples/store-update-on-destroy/_config.js b/packages/svelte/tests/runtime-runes/samples/store-update-on-destroy/_config.js new file mode 100644 index 0000000000..bb99988756 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/store-update-on-destroy/_config.js @@ -0,0 +1,12 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target, logs }) { + const input = target.querySelector('input'); + flushSync(() => { + input?.click(); + }); + assert.deepEqual(logs, [0, 1]); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/store-update-on-destroy/main.svelte b/packages/svelte/tests/runtime-runes/samples/store-update-on-destroy/main.svelte new file mode 100644 index 0000000000..7ba59b5afc --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/store-update-on-destroy/main.svelte @@ -0,0 +1,15 @@ +<script lang="ts"> + import { writable } from 'svelte/store'; + + import Test from './Test.svelte'; + + let store = writable(0); + + let checked = $state(true); +</script> + +<input type="checkbox" bind:checked /> + +{#if checked} + <Test {store} /> +{/if} From 9b6e65fbeb61297978a16e8f711ebe2dc97f2b10 Mon Sep 17 00:00:00 2001 From: Paolo Ricciuti <ricciutipaolo@gmail.com> Date: Fri, 10 Jan 2025 14:36:26 +0100 Subject: [PATCH 58/63] fix: correctly transform `pre` with no content (#14973) Closes #14971 --- .changeset/spicy-insects-check.md | 5 +++++ packages/svelte/src/compiler/phases/3-transform/utils.js | 2 +- .../tests/runtime-runes/samples/pre-no-content/_config.js | 5 +++++ .../tests/runtime-runes/samples/pre-no-content/main.svelte | 1 + 4 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 .changeset/spicy-insects-check.md create mode 100644 packages/svelte/tests/runtime-runes/samples/pre-no-content/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/pre-no-content/main.svelte diff --git a/.changeset/spicy-insects-check.md b/.changeset/spicy-insects-check.md new file mode 100644 index 0000000000..b998d36400 --- /dev/null +++ b/.changeset/spicy-insects-check.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: correctly transform `pre` with no content diff --git a/packages/svelte/src/compiler/phases/3-transform/utils.js b/packages/svelte/src/compiler/phases/3-transform/utils.js index 62a635de35..46872fbfcf 100644 --- a/packages/svelte/src/compiler/phases/3-transform/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/utils.js @@ -272,7 +272,7 @@ export function clean_nodes( var first = trimmed[0]; // initial newline inside a `<pre>` is disregarded, if not followed by another newline - if (parent.type === 'RegularElement' && parent.name === 'pre' && first.type === 'Text') { + if (parent.type === 'RegularElement' && parent.name === 'pre' && first?.type === 'Text') { const text = first.data.replace(regex_starts_with_newline, ''); if (text !== first.data) { const tmp = text.replace(regex_starts_with_newline, ''); diff --git a/packages/svelte/tests/runtime-runes/samples/pre-no-content/_config.js b/packages/svelte/tests/runtime-runes/samples/pre-no-content/_config.js new file mode 100644 index 0000000000..cb9d31a69f --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/pre-no-content/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: `<pre></pre>` +}); diff --git a/packages/svelte/tests/runtime-runes/samples/pre-no-content/main.svelte b/packages/svelte/tests/runtime-runes/samples/pre-no-content/main.svelte new file mode 100644 index 0000000000..a4357066a5 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/pre-no-content/main.svelte @@ -0,0 +1 @@ +<pre></pre> \ No newline at end of file From 76ce303b0aa08e76cefc5d13f1fe21345caa0ce9 Mon Sep 17 00:00:00 2001 From: Rich Harris <rich.harris@vercel.com> Date: Fri, 10 Jan 2025 12:05:23 -0500 Subject: [PATCH 59/63] chore: bump esrap (#14969) * chore: bump esrap * fix * bump again --- packages/svelte/package.json | 2 +- packages/svelte/src/compiler/errors.js | 330 +++++++++--------- packages/svelte/src/compiler/warnings.js | 312 ++++++++--------- .../svelte/src/internal/client/warnings.js | 6 +- .../svelte/src/internal/shared/warnings.js | 2 +- .../_expected/client/index.svelte.js | 10 +- .../_expected/server/index.svelte.js | 2 +- .../_expected/client/index.svelte.js | 8 +- .../_expected/server/index.svelte.js | 2 +- .../_expected/client/index.svelte.js | 6 +- .../_expected/server/index.svelte.js | 2 +- .../_expected/client/index.svelte.js | 4 +- .../_expected/server/index.svelte.js | 2 +- .../_expected/client/index.svelte.js | 2 +- .../_expected/server/index.svelte.js | 2 +- .../_expected/client/main.svelte.js | 16 +- .../_expected/server/main.svelte.js | 4 +- .../_expected/client/index.svelte.js | 8 +- .../_expected/server/index.svelte.js | 2 +- .../_expected/client/index.svelte.js | 2 +- .../_expected/server/index.svelte.js | 2 +- .../_expected/client/index.svelte.js | 6 +- .../_expected/server/index.svelte.js | 2 +- .../_expected/client/index.svelte.js | 6 +- .../_expected/server/index.svelte.js | 2 +- .../hmr/_expected/client/index.svelte.js | 6 +- .../hmr/_expected/server/index.svelte.js | 2 +- .../_expected/client/index.svelte.js | 6 +- .../_expected/client/module.svelte.js | 2 +- .../_expected/server/index.svelte.js | 2 +- .../_expected/server/module.svelte.js | 2 +- .../_expected/client/index.svelte.js | 6 +- .../_expected/server/index.svelte.js | 2 +- .../purity/_expected/client/index.svelte.js | 6 +- .../purity/_expected/server/index.svelte.js | 2 +- .../_expected/client/index.svelte.js | 8 +- .../_expected/server/index.svelte.js | 2 +- .../_expected/client/index.svelte.js | 6 +- .../_expected/server/index.svelte.js | 4 +- .../_expected/client/index.svelte.js | 6 +- .../_expected/server/index.svelte.js | 2 +- .../_expected/client/index.svelte.js | 8 +- .../_expected/server/index.svelte.js | 2 +- .../samples/css-injected-map/_config.js | 2 +- pnpm-lock.yaml | 10 +- 45 files changed, 414 insertions(+), 414 deletions(-) diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 459786330b..47aec9ee93 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -155,7 +155,7 @@ "axobject-query": "^4.1.0", "clsx": "^2.1.1", "esm-env": "^1.2.1", - "esrap": "^1.3.2", + "esrap": "^1.4.2", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", diff --git a/packages/svelte/src/compiler/errors.js b/packages/svelte/src/compiler/errors.js index a997eeef8d..da038af430 100644 --- a/packages/svelte/src/compiler/errors.js +++ b/packages/svelte/src/compiler/errors.js @@ -52,7 +52,7 @@ function e(node, code, message) { * @returns {never} */ export function options_invalid_value(node, details) { - e(node, "options_invalid_value", `Invalid compiler option: ${details}\nhttps://svelte.dev/e/options_invalid_value`); + e(node, 'options_invalid_value', `Invalid compiler option: ${details}\nhttps://svelte.dev/e/options_invalid_value`); } /** @@ -62,7 +62,7 @@ export function options_invalid_value(node, details) { * @returns {never} */ export function options_removed(node, details) { - e(node, "options_removed", `Invalid compiler option: ${details}\nhttps://svelte.dev/e/options_removed`); + e(node, 'options_removed', `Invalid compiler option: ${details}\nhttps://svelte.dev/e/options_removed`); } /** @@ -72,7 +72,7 @@ export function options_removed(node, details) { * @returns {never} */ export function options_unrecognised(node, keypath) { - e(node, "options_unrecognised", `Unrecognised compiler option ${keypath}\nhttps://svelte.dev/e/options_unrecognised`); + e(node, 'options_unrecognised', `Unrecognised compiler option ${keypath}\nhttps://svelte.dev/e/options_unrecognised`); } /** @@ -81,7 +81,7 @@ export function options_unrecognised(node, keypath) { * @returns {never} */ export function bindable_invalid_location(node) { - e(node, "bindable_invalid_location", `\`$bindable()\` can only be used inside a \`$props()\` declaration\nhttps://svelte.dev/e/bindable_invalid_location`); + e(node, 'bindable_invalid_location', `\`$bindable()\` can only be used inside a \`$props()\` declaration\nhttps://svelte.dev/e/bindable_invalid_location`); } /** @@ -91,7 +91,7 @@ export function bindable_invalid_location(node) { * @returns {never} */ export function constant_assignment(node, thing) { - e(node, "constant_assignment", `Cannot assign to ${thing}\nhttps://svelte.dev/e/constant_assignment`); + e(node, 'constant_assignment', `Cannot assign to ${thing}\nhttps://svelte.dev/e/constant_assignment`); } /** @@ -101,7 +101,7 @@ export function constant_assignment(node, thing) { * @returns {never} */ export function constant_binding(node, thing) { - e(node, "constant_binding", `Cannot bind to ${thing}\nhttps://svelte.dev/e/constant_binding`); + e(node, 'constant_binding', `Cannot bind to ${thing}\nhttps://svelte.dev/e/constant_binding`); } /** @@ -111,7 +111,7 @@ export function constant_binding(node, thing) { * @returns {never} */ export function declaration_duplicate(node, name) { - e(node, "declaration_duplicate", `\`${name}\` has already been declared\nhttps://svelte.dev/e/declaration_duplicate`); + e(node, 'declaration_duplicate', `\`${name}\` has already been declared\nhttps://svelte.dev/e/declaration_duplicate`); } /** @@ -120,7 +120,7 @@ export function declaration_duplicate(node, name) { * @returns {never} */ export function declaration_duplicate_module_import(node) { - e(node, "declaration_duplicate_module_import", `Cannot declare a variable with the same name as an import inside \`<script module>\`\nhttps://svelte.dev/e/declaration_duplicate_module_import`); + e(node, 'declaration_duplicate_module_import', `Cannot declare a variable with the same name as an import inside \`<script module>\`\nhttps://svelte.dev/e/declaration_duplicate_module_import`); } /** @@ -129,7 +129,7 @@ export function declaration_duplicate_module_import(node) { * @returns {never} */ export function derived_invalid_export(node) { - e(node, "derived_invalid_export", `Cannot export derived state from a module. To expose the current derived value, export a function returning its value\nhttps://svelte.dev/e/derived_invalid_export`); + e(node, 'derived_invalid_export', `Cannot export derived state from a module. To expose the current derived value, export a function returning its value\nhttps://svelte.dev/e/derived_invalid_export`); } /** @@ -138,7 +138,7 @@ export function derived_invalid_export(node) { * @returns {never} */ export function dollar_binding_invalid(node) { - e(node, "dollar_binding_invalid", `The $ name is reserved, and cannot be used for variables and imports\nhttps://svelte.dev/e/dollar_binding_invalid`); + e(node, 'dollar_binding_invalid', `The $ name is reserved, and cannot be used for variables and imports\nhttps://svelte.dev/e/dollar_binding_invalid`); } /** @@ -147,7 +147,7 @@ export function dollar_binding_invalid(node) { * @returns {never} */ export function dollar_prefix_invalid(node) { - e(node, "dollar_prefix_invalid", `The $ prefix is reserved, and cannot be used for variables and imports\nhttps://svelte.dev/e/dollar_prefix_invalid`); + e(node, 'dollar_prefix_invalid', `The $ prefix is reserved, and cannot be used for variables and imports\nhttps://svelte.dev/e/dollar_prefix_invalid`); } /** @@ -156,7 +156,7 @@ export function dollar_prefix_invalid(node) { * @returns {never} */ export function each_item_invalid_assignment(node) { - e(node, "each_item_invalid_assignment", `Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. \`array[i] = value\` instead of \`entry = value\`, or \`bind:value={array[i]}\` instead of \`bind:value={entry}\`)\nhttps://svelte.dev/e/each_item_invalid_assignment`); + e(node, 'each_item_invalid_assignment', `Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. \`array[i] = value\` instead of \`entry = value\`, or \`bind:value={array[i]}\` instead of \`bind:value={entry}\`)\nhttps://svelte.dev/e/each_item_invalid_assignment`); } /** @@ -165,7 +165,7 @@ export function each_item_invalid_assignment(node) { * @returns {never} */ export function effect_invalid_placement(node) { - e(node, "effect_invalid_placement", `\`$effect()\` can only be used as an expression statement\nhttps://svelte.dev/e/effect_invalid_placement`); + e(node, 'effect_invalid_placement', `\`$effect()\` can only be used as an expression statement\nhttps://svelte.dev/e/effect_invalid_placement`); } /** @@ -175,7 +175,7 @@ export function effect_invalid_placement(node) { * @returns {never} */ export function export_undefined(node, name) { - e(node, "export_undefined", `\`${name}\` is not defined\nhttps://svelte.dev/e/export_undefined`); + e(node, 'export_undefined', `\`${name}\` is not defined\nhttps://svelte.dev/e/export_undefined`); } /** @@ -185,7 +185,7 @@ export function export_undefined(node, name) { * @returns {never} */ export function global_reference_invalid(node, name) { - e(node, "global_reference_invalid", `\`${name}\` is an illegal variable name. To reference a global variable called \`${name}\`, use \`globalThis.${name}\`\nhttps://svelte.dev/e/global_reference_invalid`); + e(node, 'global_reference_invalid', `\`${name}\` is an illegal variable name. To reference a global variable called \`${name}\`, use \`globalThis.${name}\`\nhttps://svelte.dev/e/global_reference_invalid`); } /** @@ -194,7 +194,7 @@ export function global_reference_invalid(node, name) { * @returns {never} */ export function host_invalid_placement(node) { - e(node, "host_invalid_placement", `\`$host()\` can only be used inside custom element component instances\nhttps://svelte.dev/e/host_invalid_placement`); + e(node, 'host_invalid_placement', `\`$host()\` can only be used inside custom element component instances\nhttps://svelte.dev/e/host_invalid_placement`); } /** @@ -203,7 +203,7 @@ export function host_invalid_placement(node) { * @returns {never} */ export function import_svelte_internal_forbidden(node) { - e(node, "import_svelte_internal_forbidden", `Imports of \`svelte/internal/*\` are forbidden. It contains private runtime code which is subject to change without notice. If you're importing from \`svelte/internal/*\` to work around a limitation of Svelte, please open an issue at https://github.com/sveltejs/svelte and explain your use case\nhttps://svelte.dev/e/import_svelte_internal_forbidden`); + e(node, 'import_svelte_internal_forbidden', `Imports of \`svelte/internal/*\` are forbidden. It contains private runtime code which is subject to change without notice. If you're importing from \`svelte/internal/*\` to work around a limitation of Svelte, please open an issue at https://github.com/sveltejs/svelte and explain your use case\nhttps://svelte.dev/e/import_svelte_internal_forbidden`); } /** @@ -212,7 +212,7 @@ export function import_svelte_internal_forbidden(node) { * @returns {never} */ export function inspect_trace_generator(node) { - e(node, "inspect_trace_generator", `\`$inspect.trace(...)\` cannot be used inside a generator function\nhttps://svelte.dev/e/inspect_trace_generator`); + e(node, 'inspect_trace_generator', `\`$inspect.trace(...)\` cannot be used inside a generator function\nhttps://svelte.dev/e/inspect_trace_generator`); } /** @@ -221,7 +221,7 @@ export function inspect_trace_generator(node) { * @returns {never} */ export function inspect_trace_invalid_placement(node) { - e(node, "inspect_trace_invalid_placement", `\`$inspect.trace(...)\` must be the first statement of a function body\nhttps://svelte.dev/e/inspect_trace_invalid_placement`); + e(node, 'inspect_trace_invalid_placement', `\`$inspect.trace(...)\` must be the first statement of a function body\nhttps://svelte.dev/e/inspect_trace_invalid_placement`); } /** @@ -230,7 +230,7 @@ export function inspect_trace_invalid_placement(node) { * @returns {never} */ export function invalid_arguments_usage(node) { - e(node, "invalid_arguments_usage", `The arguments keyword cannot be used within the template or at the top level of a component\nhttps://svelte.dev/e/invalid_arguments_usage`); + e(node, 'invalid_arguments_usage', `The arguments keyword cannot be used within the template or at the top level of a component\nhttps://svelte.dev/e/invalid_arguments_usage`); } /** @@ -239,7 +239,7 @@ export function invalid_arguments_usage(node) { * @returns {never} */ export function legacy_export_invalid(node) { - e(node, "legacy_export_invalid", `Cannot use \`export let\` in runes mode — use \`$props()\` instead\nhttps://svelte.dev/e/legacy_export_invalid`); + e(node, 'legacy_export_invalid', `Cannot use \`export let\` in runes mode — use \`$props()\` instead\nhttps://svelte.dev/e/legacy_export_invalid`); } /** @@ -248,7 +248,7 @@ export function legacy_export_invalid(node) { * @returns {never} */ export function legacy_props_invalid(node) { - e(node, "legacy_props_invalid", `Cannot use \`$$props\` in runes mode\nhttps://svelte.dev/e/legacy_props_invalid`); + e(node, 'legacy_props_invalid', `Cannot use \`$$props\` in runes mode\nhttps://svelte.dev/e/legacy_props_invalid`); } /** @@ -257,7 +257,7 @@ export function legacy_props_invalid(node) { * @returns {never} */ export function legacy_reactive_statement_invalid(node) { - e(node, "legacy_reactive_statement_invalid", `\`$:\` is not allowed in runes mode, use \`$derived\` or \`$effect\` instead\nhttps://svelte.dev/e/legacy_reactive_statement_invalid`); + e(node, 'legacy_reactive_statement_invalid', `\`$:\` is not allowed in runes mode, use \`$derived\` or \`$effect\` instead\nhttps://svelte.dev/e/legacy_reactive_statement_invalid`); } /** @@ -266,7 +266,7 @@ export function legacy_reactive_statement_invalid(node) { * @returns {never} */ export function legacy_rest_props_invalid(node) { - e(node, "legacy_rest_props_invalid", `Cannot use \`$$restProps\` in runes mode\nhttps://svelte.dev/e/legacy_rest_props_invalid`); + e(node, 'legacy_rest_props_invalid', `Cannot use \`$$restProps\` in runes mode\nhttps://svelte.dev/e/legacy_rest_props_invalid`); } /** @@ -275,7 +275,7 @@ export function legacy_rest_props_invalid(node) { * @returns {never} */ export function module_illegal_default_export(node) { - e(node, "module_illegal_default_export", `A component cannot have a default export\nhttps://svelte.dev/e/module_illegal_default_export`); + e(node, 'module_illegal_default_export', `A component cannot have a default export\nhttps://svelte.dev/e/module_illegal_default_export`); } /** @@ -284,7 +284,7 @@ export function module_illegal_default_export(node) { * @returns {never} */ export function props_duplicate(node) { - e(node, "props_duplicate", `Cannot use \`$props()\` more than once\nhttps://svelte.dev/e/props_duplicate`); + e(node, 'props_duplicate', `Cannot use \`$props()\` more than once\nhttps://svelte.dev/e/props_duplicate`); } /** @@ -293,7 +293,7 @@ export function props_duplicate(node) { * @returns {never} */ export function props_illegal_name(node) { - e(node, "props_illegal_name", `Declaring or accessing a prop starting with \`$$\` is illegal (they are reserved for Svelte internals)\nhttps://svelte.dev/e/props_illegal_name`); + e(node, 'props_illegal_name', `Declaring or accessing a prop starting with \`$$\` is illegal (they are reserved for Svelte internals)\nhttps://svelte.dev/e/props_illegal_name`); } /** @@ -302,7 +302,7 @@ export function props_illegal_name(node) { * @returns {never} */ export function props_invalid_identifier(node) { - e(node, "props_invalid_identifier", `\`$props()\` can only be used with an object destructuring pattern\nhttps://svelte.dev/e/props_invalid_identifier`); + e(node, 'props_invalid_identifier', `\`$props()\` can only be used with an object destructuring pattern\nhttps://svelte.dev/e/props_invalid_identifier`); } /** @@ -311,7 +311,7 @@ export function props_invalid_identifier(node) { * @returns {never} */ export function props_invalid_pattern(node) { - e(node, "props_invalid_pattern", `\`$props()\` assignment must not contain nested properties or computed keys\nhttps://svelte.dev/e/props_invalid_pattern`); + e(node, 'props_invalid_pattern', `\`$props()\` assignment must not contain nested properties or computed keys\nhttps://svelte.dev/e/props_invalid_pattern`); } /** @@ -320,7 +320,7 @@ export function props_invalid_pattern(node) { * @returns {never} */ export function props_invalid_placement(node) { - e(node, "props_invalid_placement", `\`$props()\` can only be used at the top level of components as a variable declaration initializer\nhttps://svelte.dev/e/props_invalid_placement`); + e(node, 'props_invalid_placement', `\`$props()\` can only be used at the top level of components as a variable declaration initializer\nhttps://svelte.dev/e/props_invalid_placement`); } /** @@ -330,7 +330,7 @@ export function props_invalid_placement(node) { * @returns {never} */ export function reactive_declaration_cycle(node, cycle) { - e(node, "reactive_declaration_cycle", `Cyclical dependency detected: ${cycle}\nhttps://svelte.dev/e/reactive_declaration_cycle`); + e(node, 'reactive_declaration_cycle', `Cyclical dependency detected: ${cycle}\nhttps://svelte.dev/e/reactive_declaration_cycle`); } /** @@ -340,7 +340,7 @@ export function reactive_declaration_cycle(node, cycle) { * @returns {never} */ export function rune_invalid_arguments(node, rune) { - e(node, "rune_invalid_arguments", `\`${rune}\` cannot be called with arguments\nhttps://svelte.dev/e/rune_invalid_arguments`); + e(node, 'rune_invalid_arguments', `\`${rune}\` cannot be called with arguments\nhttps://svelte.dev/e/rune_invalid_arguments`); } /** @@ -351,7 +351,7 @@ export function rune_invalid_arguments(node, rune) { * @returns {never} */ export function rune_invalid_arguments_length(node, rune, args) { - e(node, "rune_invalid_arguments_length", `\`${rune}\` must be called with ${args}\nhttps://svelte.dev/e/rune_invalid_arguments_length`); + e(node, 'rune_invalid_arguments_length', `\`${rune}\` must be called with ${args}\nhttps://svelte.dev/e/rune_invalid_arguments_length`); } /** @@ -360,7 +360,7 @@ export function rune_invalid_arguments_length(node, rune, args) { * @returns {never} */ export function rune_invalid_computed_property(node) { - e(node, "rune_invalid_computed_property", `Cannot access a computed property of a rune\nhttps://svelte.dev/e/rune_invalid_computed_property`); + e(node, 'rune_invalid_computed_property', `Cannot access a computed property of a rune\nhttps://svelte.dev/e/rune_invalid_computed_property`); } /** @@ -370,7 +370,7 @@ export function rune_invalid_computed_property(node) { * @returns {never} */ export function rune_invalid_name(node, name) { - e(node, "rune_invalid_name", `\`${name}\` is not a valid rune\nhttps://svelte.dev/e/rune_invalid_name`); + e(node, 'rune_invalid_name', `\`${name}\` is not a valid rune\nhttps://svelte.dev/e/rune_invalid_name`); } /** @@ -380,7 +380,7 @@ export function rune_invalid_name(node, name) { * @returns {never} */ export function rune_invalid_usage(node, rune) { - e(node, "rune_invalid_usage", `Cannot use \`${rune}\` rune in non-runes mode\nhttps://svelte.dev/e/rune_invalid_usage`); + e(node, 'rune_invalid_usage', `Cannot use \`${rune}\` rune in non-runes mode\nhttps://svelte.dev/e/rune_invalid_usage`); } /** @@ -389,7 +389,7 @@ export function rune_invalid_usage(node, rune) { * @returns {never} */ export function rune_missing_parentheses(node) { - e(node, "rune_missing_parentheses", `Cannot use rune without parentheses\nhttps://svelte.dev/e/rune_missing_parentheses`); + e(node, 'rune_missing_parentheses', `Cannot use rune without parentheses\nhttps://svelte.dev/e/rune_missing_parentheses`); } /** @@ -399,7 +399,7 @@ export function rune_missing_parentheses(node) { * @returns {never} */ export function rune_removed(node, name) { - e(node, "rune_removed", `The \`${name}\` rune has been removed\nhttps://svelte.dev/e/rune_removed`); + e(node, 'rune_removed', `The \`${name}\` rune has been removed\nhttps://svelte.dev/e/rune_removed`); } /** @@ -410,7 +410,7 @@ export function rune_removed(node, name) { * @returns {never} */ export function rune_renamed(node, name, replacement) { - e(node, "rune_renamed", `\`${name}\` is now \`${replacement}\`\nhttps://svelte.dev/e/rune_renamed`); + e(node, 'rune_renamed', `\`${name}\` is now \`${replacement}\`\nhttps://svelte.dev/e/rune_renamed`); } /** @@ -420,7 +420,7 @@ export function rune_renamed(node, name, replacement) { * @returns {never} */ export function runes_mode_invalid_import(node, name) { - e(node, "runes_mode_invalid_import", `${name} cannot be used in runes mode\nhttps://svelte.dev/e/runes_mode_invalid_import`); + e(node, 'runes_mode_invalid_import', `${name} cannot be used in runes mode\nhttps://svelte.dev/e/runes_mode_invalid_import`); } /** @@ -429,7 +429,7 @@ export function runes_mode_invalid_import(node, name) { * @returns {never} */ export function snippet_invalid_export(node) { - e(node, "snippet_invalid_export", `An exported snippet can only reference things declared in a \`<script module>\`, or other exportable snippets\nhttps://svelte.dev/e/snippet_invalid_export`); + e(node, 'snippet_invalid_export', `An exported snippet can only reference things declared in a \`<script module>\`, or other exportable snippets\nhttps://svelte.dev/e/snippet_invalid_export`); } /** @@ -438,7 +438,7 @@ export function snippet_invalid_export(node) { * @returns {never} */ export function snippet_parameter_assignment(node) { - e(node, "snippet_parameter_assignment", `Cannot reassign or bind to snippet parameter\nhttps://svelte.dev/e/snippet_parameter_assignment`); + e(node, 'snippet_parameter_assignment', `Cannot reassign or bind to snippet parameter\nhttps://svelte.dev/e/snippet_parameter_assignment`); } /** @@ -447,7 +447,7 @@ export function snippet_parameter_assignment(node) { * @returns {never} */ export function state_invalid_export(node) { - e(node, "state_invalid_export", `Cannot export state from a module if it is reassigned. Either export a function returning the state value or only mutate the state value's properties\nhttps://svelte.dev/e/state_invalid_export`); + e(node, 'state_invalid_export', `Cannot export state from a module if it is reassigned. Either export a function returning the state value or only mutate the state value's properties\nhttps://svelte.dev/e/state_invalid_export`); } /** @@ -457,7 +457,7 @@ export function state_invalid_export(node) { * @returns {never} */ export function state_invalid_placement(node, rune) { - e(node, "state_invalid_placement", `\`${rune}(...)\` can only be used as a variable declaration initializer or a class field\nhttps://svelte.dev/e/state_invalid_placement`); + e(node, 'state_invalid_placement', `\`${rune}(...)\` can only be used as a variable declaration initializer or a class field\nhttps://svelte.dev/e/state_invalid_placement`); } /** @@ -466,7 +466,7 @@ export function state_invalid_placement(node, rune) { * @returns {never} */ export function store_invalid_scoped_subscription(node) { - e(node, "store_invalid_scoped_subscription", `Cannot subscribe to stores that are not declared at the top level of the component\nhttps://svelte.dev/e/store_invalid_scoped_subscription`); + e(node, 'store_invalid_scoped_subscription', `Cannot subscribe to stores that are not declared at the top level of the component\nhttps://svelte.dev/e/store_invalid_scoped_subscription`); } /** @@ -475,7 +475,7 @@ export function store_invalid_scoped_subscription(node) { * @returns {never} */ export function store_invalid_subscription(node) { - e(node, "store_invalid_subscription", `Cannot reference store value inside \`<script module>\`\nhttps://svelte.dev/e/store_invalid_subscription`); + e(node, 'store_invalid_subscription', `Cannot reference store value inside \`<script module>\`\nhttps://svelte.dev/e/store_invalid_subscription`); } /** @@ -484,7 +484,7 @@ export function store_invalid_subscription(node) { * @returns {never} */ export function store_invalid_subscription_module(node) { - e(node, "store_invalid_subscription_module", `Cannot reference store value outside a \`.svelte\` file\nhttps://svelte.dev/e/store_invalid_subscription_module`); + e(node, 'store_invalid_subscription_module', `Cannot reference store value outside a \`.svelte\` file\nhttps://svelte.dev/e/store_invalid_subscription_module`); } /** @@ -494,7 +494,7 @@ export function store_invalid_subscription_module(node) { * @returns {never} */ export function typescript_invalid_feature(node, feature) { - e(node, "typescript_invalid_feature", `TypeScript language features like ${feature} are not natively supported, and their use is generally discouraged. Outside of \`<script>\` tags, these features are not supported. For use within \`<script>\` tags, you will need to use a preprocessor to convert it to JavaScript before it gets passed to the Svelte compiler. If you are using \`vitePreprocess\`, make sure to specifically enable preprocessing script tags (\`vitePreprocess({ script: true })\`)\nhttps://svelte.dev/e/typescript_invalid_feature`); + e(node, 'typescript_invalid_feature', `TypeScript language features like ${feature} are not natively supported, and their use is generally discouraged. Outside of \`<script>\` tags, these features are not supported. For use within \`<script>\` tags, you will need to use a preprocessor to convert it to JavaScript before it gets passed to the Svelte compiler. If you are using \`vitePreprocess\`, make sure to specifically enable preprocessing script tags (\`vitePreprocess({ script: true })\`)\nhttps://svelte.dev/e/typescript_invalid_feature`); } /** @@ -503,7 +503,7 @@ export function typescript_invalid_feature(node, feature) { * @returns {never} */ export function css_empty_declaration(node) { - e(node, "css_empty_declaration", `Declaration cannot be empty\nhttps://svelte.dev/e/css_empty_declaration`); + e(node, 'css_empty_declaration', `Declaration cannot be empty\nhttps://svelte.dev/e/css_empty_declaration`); } /** @@ -512,7 +512,7 @@ export function css_empty_declaration(node) { * @returns {never} */ export function css_expected_identifier(node) { - e(node, "css_expected_identifier", `Expected a valid CSS identifier\nhttps://svelte.dev/e/css_expected_identifier`); + e(node, 'css_expected_identifier', `Expected a valid CSS identifier\nhttps://svelte.dev/e/css_expected_identifier`); } /** @@ -522,7 +522,7 @@ export function css_expected_identifier(node) { * @returns {never} */ export function css_global_block_invalid_combinator(node, name) { - e(node, "css_global_block_invalid_combinator", `A \`:global\` selector cannot follow a \`${name}\` combinator\nhttps://svelte.dev/e/css_global_block_invalid_combinator`); + e(node, 'css_global_block_invalid_combinator', `A \`:global\` selector cannot follow a \`${name}\` combinator\nhttps://svelte.dev/e/css_global_block_invalid_combinator`); } /** @@ -531,7 +531,7 @@ export function css_global_block_invalid_combinator(node, name) { * @returns {never} */ export function css_global_block_invalid_declaration(node) { - e(node, "css_global_block_invalid_declaration", `A top-level \`:global {...}\` block can only contain rules, not declarations\nhttps://svelte.dev/e/css_global_block_invalid_declaration`); + e(node, 'css_global_block_invalid_declaration', `A top-level \`:global {...}\` block can only contain rules, not declarations\nhttps://svelte.dev/e/css_global_block_invalid_declaration`); } /** @@ -540,7 +540,7 @@ export function css_global_block_invalid_declaration(node) { * @returns {never} */ export function css_global_block_invalid_list(node) { - e(node, "css_global_block_invalid_list", `A \`:global\` selector cannot be part of a selector list with more than one item\nhttps://svelte.dev/e/css_global_block_invalid_list`); + e(node, 'css_global_block_invalid_list', `A \`:global\` selector cannot be part of a selector list with more than one item\nhttps://svelte.dev/e/css_global_block_invalid_list`); } /** @@ -549,7 +549,7 @@ export function css_global_block_invalid_list(node) { * @returns {never} */ export function css_global_block_invalid_modifier(node) { - e(node, "css_global_block_invalid_modifier", `A \`:global\` selector cannot modify an existing selector\nhttps://svelte.dev/e/css_global_block_invalid_modifier`); + e(node, 'css_global_block_invalid_modifier', `A \`:global\` selector cannot modify an existing selector\nhttps://svelte.dev/e/css_global_block_invalid_modifier`); } /** @@ -558,7 +558,7 @@ export function css_global_block_invalid_modifier(node) { * @returns {never} */ export function css_global_block_invalid_modifier_start(node) { - e(node, "css_global_block_invalid_modifier_start", `A \`:global\` selector can only be modified if it is a descendant of other selectors\nhttps://svelte.dev/e/css_global_block_invalid_modifier_start`); + e(node, 'css_global_block_invalid_modifier_start', `A \`:global\` selector can only be modified if it is a descendant of other selectors\nhttps://svelte.dev/e/css_global_block_invalid_modifier_start`); } /** @@ -567,7 +567,7 @@ export function css_global_block_invalid_modifier_start(node) { * @returns {never} */ export function css_global_invalid_placement(node) { - e(node, "css_global_invalid_placement", `\`:global(...)\` can be at the start or end of a selector sequence, but not in the middle\nhttps://svelte.dev/e/css_global_invalid_placement`); + e(node, 'css_global_invalid_placement', `\`:global(...)\` can be at the start or end of a selector sequence, but not in the middle\nhttps://svelte.dev/e/css_global_invalid_placement`); } /** @@ -576,7 +576,7 @@ export function css_global_invalid_placement(node) { * @returns {never} */ export function css_global_invalid_selector(node) { - e(node, "css_global_invalid_selector", `\`:global(...)\` must contain exactly one selector\nhttps://svelte.dev/e/css_global_invalid_selector`); + e(node, 'css_global_invalid_selector', `\`:global(...)\` must contain exactly one selector\nhttps://svelte.dev/e/css_global_invalid_selector`); } /** @@ -585,7 +585,7 @@ export function css_global_invalid_selector(node) { * @returns {never} */ export function css_global_invalid_selector_list(node) { - e(node, "css_global_invalid_selector_list", `\`:global(...)\` must not contain type or universal selectors when used in a compound selector\nhttps://svelte.dev/e/css_global_invalid_selector_list`); + e(node, 'css_global_invalid_selector_list', `\`:global(...)\` must not contain type or universal selectors when used in a compound selector\nhttps://svelte.dev/e/css_global_invalid_selector_list`); } /** @@ -594,7 +594,7 @@ export function css_global_invalid_selector_list(node) { * @returns {never} */ export function css_nesting_selector_invalid_placement(node) { - e(node, "css_nesting_selector_invalid_placement", `Nesting selectors can only be used inside a rule or as the first selector inside a lone \`:global(...)\`\nhttps://svelte.dev/e/css_nesting_selector_invalid_placement`); + e(node, 'css_nesting_selector_invalid_placement', `Nesting selectors can only be used inside a rule or as the first selector inside a lone \`:global(...)\`\nhttps://svelte.dev/e/css_nesting_selector_invalid_placement`); } /** @@ -603,7 +603,7 @@ export function css_nesting_selector_invalid_placement(node) { * @returns {never} */ export function css_selector_invalid(node) { - e(node, "css_selector_invalid", `Invalid selector\nhttps://svelte.dev/e/css_selector_invalid`); + e(node, 'css_selector_invalid', `Invalid selector\nhttps://svelte.dev/e/css_selector_invalid`); } /** @@ -612,7 +612,7 @@ export function css_selector_invalid(node) { * @returns {never} */ export function css_type_selector_invalid_placement(node) { - e(node, "css_type_selector_invalid_placement", `\`:global(...)\` must not be followed by a type selector\nhttps://svelte.dev/e/css_type_selector_invalid_placement`); + e(node, 'css_type_selector_invalid_placement', `\`:global(...)\` must not be followed by a type selector\nhttps://svelte.dev/e/css_type_selector_invalid_placement`); } /** @@ -621,7 +621,7 @@ export function css_type_selector_invalid_placement(node) { * @returns {never} */ export function animation_duplicate(node) { - e(node, "animation_duplicate", `An element can only have one 'animate' directive\nhttps://svelte.dev/e/animation_duplicate`); + e(node, 'animation_duplicate', `An element can only have one 'animate' directive\nhttps://svelte.dev/e/animation_duplicate`); } /** @@ -630,7 +630,7 @@ export function animation_duplicate(node) { * @returns {never} */ export function animation_invalid_placement(node) { - e(node, "animation_invalid_placement", `An element that uses the \`animate:\` directive must be the only child of a keyed \`{#each ...}\` block\nhttps://svelte.dev/e/animation_invalid_placement`); + e(node, 'animation_invalid_placement', `An element that uses the \`animate:\` directive must be the only child of a keyed \`{#each ...}\` block\nhttps://svelte.dev/e/animation_invalid_placement`); } /** @@ -639,7 +639,7 @@ export function animation_invalid_placement(node) { * @returns {never} */ export function animation_missing_key(node) { - e(node, "animation_missing_key", `An element that uses the \`animate:\` directive must be the only child of a keyed \`{#each ...}\` block. Did you forget to add a key to your each block?\nhttps://svelte.dev/e/animation_missing_key`); + e(node, 'animation_missing_key', `An element that uses the \`animate:\` directive must be the only child of a keyed \`{#each ...}\` block. Did you forget to add a key to your each block?\nhttps://svelte.dev/e/animation_missing_key`); } /** @@ -648,7 +648,7 @@ export function animation_missing_key(node) { * @returns {never} */ export function attribute_contenteditable_dynamic(node) { - e(node, "attribute_contenteditable_dynamic", `'contenteditable' attribute cannot be dynamic if element uses two-way binding\nhttps://svelte.dev/e/attribute_contenteditable_dynamic`); + e(node, 'attribute_contenteditable_dynamic', `'contenteditable' attribute cannot be dynamic if element uses two-way binding\nhttps://svelte.dev/e/attribute_contenteditable_dynamic`); } /** @@ -657,7 +657,7 @@ export function attribute_contenteditable_dynamic(node) { * @returns {never} */ export function attribute_contenteditable_missing(node) { - e(node, "attribute_contenteditable_missing", `'contenteditable' attribute is required for textContent, innerHTML and innerText two-way bindings\nhttps://svelte.dev/e/attribute_contenteditable_missing`); + e(node, 'attribute_contenteditable_missing', `'contenteditable' attribute is required for textContent, innerHTML and innerText two-way bindings\nhttps://svelte.dev/e/attribute_contenteditable_missing`); } /** @@ -666,7 +666,7 @@ export function attribute_contenteditable_missing(node) { * @returns {never} */ export function attribute_duplicate(node) { - e(node, "attribute_duplicate", `Attributes need to be unique\nhttps://svelte.dev/e/attribute_duplicate`); + e(node, 'attribute_duplicate', `Attributes need to be unique\nhttps://svelte.dev/e/attribute_duplicate`); } /** @@ -675,7 +675,7 @@ export function attribute_duplicate(node) { * @returns {never} */ export function attribute_empty_shorthand(node) { - e(node, "attribute_empty_shorthand", `Attribute shorthand cannot be empty\nhttps://svelte.dev/e/attribute_empty_shorthand`); + e(node, 'attribute_empty_shorthand', `Attribute shorthand cannot be empty\nhttps://svelte.dev/e/attribute_empty_shorthand`); } /** @@ -684,7 +684,7 @@ export function attribute_empty_shorthand(node) { * @returns {never} */ export function attribute_invalid_event_handler(node) { - e(node, "attribute_invalid_event_handler", `Event attribute must be a JavaScript expression, not a string\nhttps://svelte.dev/e/attribute_invalid_event_handler`); + e(node, 'attribute_invalid_event_handler', `Event attribute must be a JavaScript expression, not a string\nhttps://svelte.dev/e/attribute_invalid_event_handler`); } /** @@ -693,7 +693,7 @@ export function attribute_invalid_event_handler(node) { * @returns {never} */ export function attribute_invalid_multiple(node) { - e(node, "attribute_invalid_multiple", `'multiple' attribute must be static if select uses two-way binding\nhttps://svelte.dev/e/attribute_invalid_multiple`); + e(node, 'attribute_invalid_multiple', `'multiple' attribute must be static if select uses two-way binding\nhttps://svelte.dev/e/attribute_invalid_multiple`); } /** @@ -703,7 +703,7 @@ export function attribute_invalid_multiple(node) { * @returns {never} */ export function attribute_invalid_name(node, name) { - e(node, "attribute_invalid_name", `'${name}' is not a valid attribute name\nhttps://svelte.dev/e/attribute_invalid_name`); + e(node, 'attribute_invalid_name', `'${name}' is not a valid attribute name\nhttps://svelte.dev/e/attribute_invalid_name`); } /** @@ -712,7 +712,7 @@ export function attribute_invalid_name(node, name) { * @returns {never} */ export function attribute_invalid_sequence_expression(node) { - e(node, "attribute_invalid_sequence_expression", `Sequence expressions are not allowed as attribute/directive values in runes mode, unless wrapped in parentheses\nhttps://svelte.dev/e/attribute_invalid_sequence_expression`); + e(node, 'attribute_invalid_sequence_expression', `Sequence expressions are not allowed as attribute/directive values in runes mode, unless wrapped in parentheses\nhttps://svelte.dev/e/attribute_invalid_sequence_expression`); } /** @@ -721,7 +721,7 @@ export function attribute_invalid_sequence_expression(node) { * @returns {never} */ export function attribute_invalid_type(node) { - e(node, "attribute_invalid_type", `'type' attribute must be a static text value if input uses two-way binding\nhttps://svelte.dev/e/attribute_invalid_type`); + e(node, 'attribute_invalid_type', `'type' attribute must be a static text value if input uses two-way binding\nhttps://svelte.dev/e/attribute_invalid_type`); } /** @@ -730,7 +730,7 @@ export function attribute_invalid_type(node) { * @returns {never} */ export function attribute_unquoted_sequence(node) { - e(node, "attribute_unquoted_sequence", `Attribute values containing \`{...}\` must be enclosed in quote marks, unless the value only contains the expression\nhttps://svelte.dev/e/attribute_unquoted_sequence`); + e(node, 'attribute_unquoted_sequence', `Attribute values containing \`{...}\` must be enclosed in quote marks, unless the value only contains the expression\nhttps://svelte.dev/e/attribute_unquoted_sequence`); } /** @@ -739,7 +739,7 @@ export function attribute_unquoted_sequence(node) { * @returns {never} */ export function bind_group_invalid_expression(node) { - e(node, "bind_group_invalid_expression", `\`bind:group\` can only bind to an Identifier or MemberExpression\nhttps://svelte.dev/e/bind_group_invalid_expression`); + e(node, 'bind_group_invalid_expression', `\`bind:group\` can only bind to an Identifier or MemberExpression\nhttps://svelte.dev/e/bind_group_invalid_expression`); } /** @@ -748,7 +748,7 @@ export function bind_group_invalid_expression(node) { * @returns {never} */ export function bind_invalid_expression(node) { - e(node, "bind_invalid_expression", `Can only bind to an Identifier or MemberExpression or a \`{get, set}\` pair\nhttps://svelte.dev/e/bind_invalid_expression`); + e(node, 'bind_invalid_expression', `Can only bind to an Identifier or MemberExpression or a \`{get, set}\` pair\nhttps://svelte.dev/e/bind_invalid_expression`); } /** @@ -759,7 +759,7 @@ export function bind_invalid_expression(node) { * @returns {never} */ export function bind_invalid_name(node, name, explanation) { - e(node, "bind_invalid_name", `${explanation ? `\`bind:${name}\` is not a valid binding. ${explanation}` : `\`bind:${name}\` is not a valid binding`}\nhttps://svelte.dev/e/bind_invalid_name`); + e(node, 'bind_invalid_name', `${explanation ? `\`bind:${name}\` is not a valid binding. ${explanation}` : `\`bind:${name}\` is not a valid binding`}\nhttps://svelte.dev/e/bind_invalid_name`); } /** @@ -769,7 +769,7 @@ export function bind_invalid_name(node, name, explanation) { * @returns {never} */ export function bind_invalid_parens(node, name) { - e(node, "bind_invalid_parens", `\`bind:${name}={get, set}\` must not have surrounding parentheses\nhttps://svelte.dev/e/bind_invalid_parens`); + e(node, 'bind_invalid_parens', `\`bind:${name}={get, set}\` must not have surrounding parentheses\nhttps://svelte.dev/e/bind_invalid_parens`); } /** @@ -780,7 +780,7 @@ export function bind_invalid_parens(node, name) { * @returns {never} */ export function bind_invalid_target(node, name, elements) { - e(node, "bind_invalid_target", `\`bind:${name}\` can only be used with ${elements}\nhttps://svelte.dev/e/bind_invalid_target`); + e(node, 'bind_invalid_target', `\`bind:${name}\` can only be used with ${elements}\nhttps://svelte.dev/e/bind_invalid_target`); } /** @@ -789,7 +789,7 @@ export function bind_invalid_target(node, name, elements) { * @returns {never} */ export function bind_invalid_value(node) { - e(node, "bind_invalid_value", `Can only bind to state or props\nhttps://svelte.dev/e/bind_invalid_value`); + e(node, 'bind_invalid_value', `Can only bind to state or props\nhttps://svelte.dev/e/bind_invalid_value`); } /** @@ -799,7 +799,7 @@ export function bind_invalid_value(node) { * @returns {never} */ export function block_duplicate_clause(node, name) { - e(node, "block_duplicate_clause", `${name} cannot appear more than once within a block\nhttps://svelte.dev/e/block_duplicate_clause`); + e(node, 'block_duplicate_clause', `${name} cannot appear more than once within a block\nhttps://svelte.dev/e/block_duplicate_clause`); } /** @@ -808,7 +808,7 @@ export function block_duplicate_clause(node, name) { * @returns {never} */ export function block_invalid_continuation_placement(node) { - e(node, "block_invalid_continuation_placement", `{:...} block is invalid at this position (did you forget to close the preceding element or block?)\nhttps://svelte.dev/e/block_invalid_continuation_placement`); + e(node, 'block_invalid_continuation_placement', `{:...} block is invalid at this position (did you forget to close the preceding element or block?)\nhttps://svelte.dev/e/block_invalid_continuation_placement`); } /** @@ -817,7 +817,7 @@ export function block_invalid_continuation_placement(node) { * @returns {never} */ export function block_invalid_elseif(node) { - e(node, "block_invalid_elseif", `'elseif' should be 'else if'\nhttps://svelte.dev/e/block_invalid_elseif`); + e(node, 'block_invalid_elseif', `'elseif' should be 'else if'\nhttps://svelte.dev/e/block_invalid_elseif`); } /** @@ -828,7 +828,7 @@ export function block_invalid_elseif(node) { * @returns {never} */ export function block_invalid_placement(node, name, location) { - e(node, "block_invalid_placement", `{#${name} ...} block cannot be ${location}\nhttps://svelte.dev/e/block_invalid_placement`); + e(node, 'block_invalid_placement', `{#${name} ...} block cannot be ${location}\nhttps://svelte.dev/e/block_invalid_placement`); } /** @@ -837,7 +837,7 @@ export function block_invalid_placement(node, name, location) { * @returns {never} */ export function block_unclosed(node) { - e(node, "block_unclosed", `Block was left open\nhttps://svelte.dev/e/block_unclosed`); + e(node, 'block_unclosed', `Block was left open\nhttps://svelte.dev/e/block_unclosed`); } /** @@ -847,7 +847,7 @@ export function block_unclosed(node) { * @returns {never} */ export function block_unexpected_character(node, character) { - e(node, "block_unexpected_character", `Expected a \`${character}\` character immediately following the opening bracket\nhttps://svelte.dev/e/block_unexpected_character`); + e(node, 'block_unexpected_character', `Expected a \`${character}\` character immediately following the opening bracket\nhttps://svelte.dev/e/block_unexpected_character`); } /** @@ -856,7 +856,7 @@ export function block_unexpected_character(node, character) { * @returns {never} */ export function block_unexpected_close(node) { - e(node, "block_unexpected_close", `Unexpected block closing tag\nhttps://svelte.dev/e/block_unexpected_close`); + e(node, 'block_unexpected_close', `Unexpected block closing tag\nhttps://svelte.dev/e/block_unexpected_close`); } /** @@ -865,7 +865,7 @@ export function block_unexpected_close(node) { * @returns {never} */ export function component_invalid_directive(node) { - e(node, "component_invalid_directive", `This type of directive is not valid on components\nhttps://svelte.dev/e/component_invalid_directive`); + e(node, 'component_invalid_directive', `This type of directive is not valid on components\nhttps://svelte.dev/e/component_invalid_directive`); } /** @@ -875,7 +875,7 @@ export function component_invalid_directive(node) { * @returns {never} */ export function const_tag_cycle(node, cycle) { - e(node, "const_tag_cycle", `Cyclical dependency detected: ${cycle}\nhttps://svelte.dev/e/const_tag_cycle`); + e(node, 'const_tag_cycle', `Cyclical dependency detected: ${cycle}\nhttps://svelte.dev/e/const_tag_cycle`); } /** @@ -884,7 +884,7 @@ export function const_tag_cycle(node, cycle) { * @returns {never} */ export function const_tag_invalid_expression(node) { - e(node, "const_tag_invalid_expression", `{@const ...} must consist of a single variable declaration\nhttps://svelte.dev/e/const_tag_invalid_expression`); + e(node, 'const_tag_invalid_expression', `{@const ...} must consist of a single variable declaration\nhttps://svelte.dev/e/const_tag_invalid_expression`); } /** @@ -893,7 +893,7 @@ export function const_tag_invalid_expression(node) { * @returns {never} */ export function const_tag_invalid_placement(node) { - e(node, "const_tag_invalid_placement", `\`{@const}\` must be the immediate child of \`{#snippet}\`, \`{#if}\`, \`{:else if}\`, \`{:else}\`, \`{#each}\`, \`{:then}\`, \`{:catch}\`, \`<svelte:fragment>\` or \`<Component>\`\nhttps://svelte.dev/e/const_tag_invalid_placement`); + e(node, 'const_tag_invalid_placement', `\`{@const}\` must be the immediate child of \`{#snippet}\`, \`{#if}\`, \`{:else if}\`, \`{:else}\`, \`{#each}\`, \`{:then}\`, \`{:catch}\`, \`<svelte:fragment>\` or \`<Component>\`\nhttps://svelte.dev/e/const_tag_invalid_placement`); } /** @@ -902,7 +902,7 @@ export function const_tag_invalid_placement(node) { * @returns {never} */ export function debug_tag_invalid_arguments(node) { - e(node, "debug_tag_invalid_arguments", `{@debug ...} arguments must be identifiers, not arbitrary expressions\nhttps://svelte.dev/e/debug_tag_invalid_arguments`); + e(node, 'debug_tag_invalid_arguments', `{@debug ...} arguments must be identifiers, not arbitrary expressions\nhttps://svelte.dev/e/debug_tag_invalid_arguments`); } /** @@ -911,7 +911,7 @@ export function debug_tag_invalid_arguments(node) { * @returns {never} */ export function directive_invalid_value(node) { - e(node, "directive_invalid_value", `Directive value must be a JavaScript expression enclosed in curly braces\nhttps://svelte.dev/e/directive_invalid_value`); + e(node, 'directive_invalid_value', `Directive value must be a JavaScript expression enclosed in curly braces\nhttps://svelte.dev/e/directive_invalid_value`); } /** @@ -921,7 +921,7 @@ export function directive_invalid_value(node) { * @returns {never} */ export function directive_missing_name(node, type) { - e(node, "directive_missing_name", `\`${type}\` name cannot be empty\nhttps://svelte.dev/e/directive_missing_name`); + e(node, 'directive_missing_name', `\`${type}\` name cannot be empty\nhttps://svelte.dev/e/directive_missing_name`); } /** @@ -931,7 +931,7 @@ export function directive_missing_name(node, type) { * @returns {never} */ export function element_invalid_closing_tag(node, name) { - e(node, "element_invalid_closing_tag", `\`</${name}>\` attempted to close an element that was not open\nhttps://svelte.dev/e/element_invalid_closing_tag`); + e(node, 'element_invalid_closing_tag', `\`</${name}>\` attempted to close an element that was not open\nhttps://svelte.dev/e/element_invalid_closing_tag`); } /** @@ -942,7 +942,7 @@ export function element_invalid_closing_tag(node, name) { * @returns {never} */ export function element_invalid_closing_tag_autoclosed(node, name, reason) { - e(node, "element_invalid_closing_tag_autoclosed", `\`</${name}>\` attempted to close element that was already automatically closed by \`<${reason}>\` (cannot nest \`<${reason}>\` inside \`<${name}>\`)\nhttps://svelte.dev/e/element_invalid_closing_tag_autoclosed`); + e(node, 'element_invalid_closing_tag_autoclosed', `\`</${name}>\` attempted to close element that was already automatically closed by \`<${reason}>\` (cannot nest \`<${reason}>\` inside \`<${name}>\`)\nhttps://svelte.dev/e/element_invalid_closing_tag_autoclosed`); } /** @@ -952,7 +952,7 @@ export function element_invalid_closing_tag_autoclosed(node, name, reason) { * @returns {never} */ export function element_unclosed(node, name) { - e(node, "element_unclosed", `\`<${name}>\` was left open\nhttps://svelte.dev/e/element_unclosed`); + e(node, 'element_unclosed', `\`<${name}>\` was left open\nhttps://svelte.dev/e/element_unclosed`); } /** @@ -961,7 +961,7 @@ export function element_unclosed(node, name) { * @returns {never} */ export function event_handler_invalid_component_modifier(node) { - e(node, "event_handler_invalid_component_modifier", `Event modifiers other than 'once' can only be used on DOM elements\nhttps://svelte.dev/e/event_handler_invalid_component_modifier`); + e(node, 'event_handler_invalid_component_modifier', `Event modifiers other than 'once' can only be used on DOM elements\nhttps://svelte.dev/e/event_handler_invalid_component_modifier`); } /** @@ -971,7 +971,7 @@ export function event_handler_invalid_component_modifier(node) { * @returns {never} */ export function event_handler_invalid_modifier(node, list) { - e(node, "event_handler_invalid_modifier", `Valid event modifiers are ${list}\nhttps://svelte.dev/e/event_handler_invalid_modifier`); + e(node, 'event_handler_invalid_modifier', `Valid event modifiers are ${list}\nhttps://svelte.dev/e/event_handler_invalid_modifier`); } /** @@ -982,7 +982,7 @@ export function event_handler_invalid_modifier(node, list) { * @returns {never} */ export function event_handler_invalid_modifier_combination(node, modifier1, modifier2) { - e(node, "event_handler_invalid_modifier_combination", `The '${modifier1}' and '${modifier2}' modifiers cannot be used together\nhttps://svelte.dev/e/event_handler_invalid_modifier_combination`); + e(node, 'event_handler_invalid_modifier_combination', `The '${modifier1}' and '${modifier2}' modifiers cannot be used together\nhttps://svelte.dev/e/event_handler_invalid_modifier_combination`); } /** @@ -991,7 +991,7 @@ export function event_handler_invalid_modifier_combination(node, modifier1, modi * @returns {never} */ export function expected_attribute_value(node) { - e(node, "expected_attribute_value", `Expected attribute value\nhttps://svelte.dev/e/expected_attribute_value`); + e(node, 'expected_attribute_value', `Expected attribute value\nhttps://svelte.dev/e/expected_attribute_value`); } /** @@ -1000,7 +1000,7 @@ export function expected_attribute_value(node) { * @returns {never} */ export function expected_block_type(node) { - e(node, "expected_block_type", `Expected 'if', 'each', 'await', 'key' or 'snippet'\nhttps://svelte.dev/e/expected_block_type`); + e(node, 'expected_block_type', `Expected 'if', 'each', 'await', 'key' or 'snippet'\nhttps://svelte.dev/e/expected_block_type`); } /** @@ -1009,7 +1009,7 @@ export function expected_block_type(node) { * @returns {never} */ export function expected_identifier(node) { - e(node, "expected_identifier", `Expected an identifier\nhttps://svelte.dev/e/expected_identifier`); + e(node, 'expected_identifier', `Expected an identifier\nhttps://svelte.dev/e/expected_identifier`); } /** @@ -1018,7 +1018,7 @@ export function expected_identifier(node) { * @returns {never} */ export function expected_pattern(node) { - e(node, "expected_pattern", `Expected identifier or destructure pattern\nhttps://svelte.dev/e/expected_pattern`); + e(node, 'expected_pattern', `Expected identifier or destructure pattern\nhttps://svelte.dev/e/expected_pattern`); } /** @@ -1028,7 +1028,7 @@ export function expected_pattern(node) { * @returns {never} */ export function expected_token(node, token) { - e(node, "expected_token", `Expected token ${token}\nhttps://svelte.dev/e/expected_token`); + e(node, 'expected_token', `Expected token ${token}\nhttps://svelte.dev/e/expected_token`); } /** @@ -1037,7 +1037,7 @@ export function expected_token(node, token) { * @returns {never} */ export function expected_whitespace(node) { - e(node, "expected_whitespace", `Expected whitespace\nhttps://svelte.dev/e/expected_whitespace`); + e(node, 'expected_whitespace', `Expected whitespace\nhttps://svelte.dev/e/expected_whitespace`); } /** @@ -1047,7 +1047,7 @@ export function expected_whitespace(node) { * @returns {never} */ export function illegal_element_attribute(node, name) { - e(node, "illegal_element_attribute", `\`<${name}>\` does not support non-event attributes or spread attributes\nhttps://svelte.dev/e/illegal_element_attribute`); + e(node, 'illegal_element_attribute', `\`<${name}>\` does not support non-event attributes or spread attributes\nhttps://svelte.dev/e/illegal_element_attribute`); } /** @@ -1057,7 +1057,7 @@ export function illegal_element_attribute(node, name) { * @returns {never} */ export function js_parse_error(node, message) { - e(node, "js_parse_error", `${message}\nhttps://svelte.dev/e/js_parse_error`); + e(node, 'js_parse_error', `${message}\nhttps://svelte.dev/e/js_parse_error`); } /** @@ -1066,7 +1066,7 @@ export function js_parse_error(node, message) { * @returns {never} */ export function let_directive_invalid_placement(node) { - e(node, "let_directive_invalid_placement", `\`let:\` directive at invalid position\nhttps://svelte.dev/e/let_directive_invalid_placement`); + e(node, 'let_directive_invalid_placement', `\`let:\` directive at invalid position\nhttps://svelte.dev/e/let_directive_invalid_placement`); } /** @@ -1076,7 +1076,7 @@ export function let_directive_invalid_placement(node) { * @returns {never} */ export function mixed_event_handler_syntaxes(node, name) { - e(node, "mixed_event_handler_syntaxes", `Mixing old (on:${name}) and new syntaxes for event handling is not allowed. Use only the on${name} syntax\nhttps://svelte.dev/e/mixed_event_handler_syntaxes`); + e(node, 'mixed_event_handler_syntaxes', `Mixing old (on:${name}) and new syntaxes for event handling is not allowed. Use only the on${name} syntax\nhttps://svelte.dev/e/mixed_event_handler_syntaxes`); } /** @@ -1086,7 +1086,7 @@ export function mixed_event_handler_syntaxes(node, name) { * @returns {never} */ export function node_invalid_placement(node, message) { - e(node, "node_invalid_placement", `${message}. The browser will 'repair' the HTML (by moving, removing, or inserting elements) which breaks Svelte's assumptions about the structure of your components.\nhttps://svelte.dev/e/node_invalid_placement`); + e(node, 'node_invalid_placement', `${message}. The browser will 'repair' the HTML (by moving, removing, or inserting elements) which breaks Svelte's assumptions about the structure of your components.\nhttps://svelte.dev/e/node_invalid_placement`); } /** @@ -1095,7 +1095,7 @@ export function node_invalid_placement(node, message) { * @returns {never} */ export function render_tag_invalid_call_expression(node) { - e(node, "render_tag_invalid_call_expression", `Calling a snippet function using apply, bind or call is not allowed\nhttps://svelte.dev/e/render_tag_invalid_call_expression`); + e(node, 'render_tag_invalid_call_expression', `Calling a snippet function using apply, bind or call is not allowed\nhttps://svelte.dev/e/render_tag_invalid_call_expression`); } /** @@ -1104,7 +1104,7 @@ export function render_tag_invalid_call_expression(node) { * @returns {never} */ export function render_tag_invalid_expression(node) { - e(node, "render_tag_invalid_expression", `\`{@render ...}\` tags can only contain call expressions\nhttps://svelte.dev/e/render_tag_invalid_expression`); + e(node, 'render_tag_invalid_expression', `\`{@render ...}\` tags can only contain call expressions\nhttps://svelte.dev/e/render_tag_invalid_expression`); } /** @@ -1113,7 +1113,7 @@ export function render_tag_invalid_expression(node) { * @returns {never} */ export function render_tag_invalid_spread_argument(node) { - e(node, "render_tag_invalid_spread_argument", `cannot use spread arguments in \`{@render ...}\` tags\nhttps://svelte.dev/e/render_tag_invalid_spread_argument`); + e(node, 'render_tag_invalid_spread_argument', `cannot use spread arguments in \`{@render ...}\` tags\nhttps://svelte.dev/e/render_tag_invalid_spread_argument`); } /** @@ -1122,7 +1122,7 @@ export function render_tag_invalid_spread_argument(node) { * @returns {never} */ export function script_duplicate(node) { - e(node, "script_duplicate", `A component can have a single top-level \`<script>\` element and/or a single top-level \`<script module>\` element\nhttps://svelte.dev/e/script_duplicate`); + e(node, 'script_duplicate', `A component can have a single top-level \`<script>\` element and/or a single top-level \`<script module>\` element\nhttps://svelte.dev/e/script_duplicate`); } /** @@ -1132,7 +1132,7 @@ export function script_duplicate(node) { * @returns {never} */ export function script_invalid_attribute_value(node, name) { - e(node, "script_invalid_attribute_value", `If the \`${name}\` attribute is supplied, it must be a boolean attribute\nhttps://svelte.dev/e/script_invalid_attribute_value`); + e(node, 'script_invalid_attribute_value', `If the \`${name}\` attribute is supplied, it must be a boolean attribute\nhttps://svelte.dev/e/script_invalid_attribute_value`); } /** @@ -1141,7 +1141,7 @@ export function script_invalid_attribute_value(node, name) { * @returns {never} */ export function script_invalid_context(node) { - e(node, "script_invalid_context", `If the context attribute is supplied, its value must be "module"\nhttps://svelte.dev/e/script_invalid_context`); + e(node, 'script_invalid_context', `If the context attribute is supplied, its value must be "module"\nhttps://svelte.dev/e/script_invalid_context`); } /** @@ -1151,7 +1151,7 @@ export function script_invalid_context(node) { * @returns {never} */ export function script_reserved_attribute(node, name) { - e(node, "script_reserved_attribute", `The \`${name}\` attribute is reserved and cannot be used\nhttps://svelte.dev/e/script_reserved_attribute`); + e(node, 'script_reserved_attribute', `The \`${name}\` attribute is reserved and cannot be used\nhttps://svelte.dev/e/script_reserved_attribute`); } /** @@ -1162,7 +1162,7 @@ export function script_reserved_attribute(node, name) { * @returns {never} */ export function slot_attribute_duplicate(node, name, component) { - e(node, "slot_attribute_duplicate", `Duplicate slot name '${name}' in <${component}>\nhttps://svelte.dev/e/slot_attribute_duplicate`); + e(node, 'slot_attribute_duplicate', `Duplicate slot name '${name}' in <${component}>\nhttps://svelte.dev/e/slot_attribute_duplicate`); } /** @@ -1171,7 +1171,7 @@ export function slot_attribute_duplicate(node, name, component) { * @returns {never} */ export function slot_attribute_invalid(node) { - e(node, "slot_attribute_invalid", `slot attribute must be a static value\nhttps://svelte.dev/e/slot_attribute_invalid`); + e(node, 'slot_attribute_invalid', `slot attribute must be a static value\nhttps://svelte.dev/e/slot_attribute_invalid`); } /** @@ -1180,7 +1180,7 @@ export function slot_attribute_invalid(node) { * @returns {never} */ export function slot_attribute_invalid_placement(node) { - e(node, "slot_attribute_invalid_placement", `Element with a slot='...' attribute must be a child of a component or a descendant of a custom element\nhttps://svelte.dev/e/slot_attribute_invalid_placement`); + e(node, 'slot_attribute_invalid_placement', `Element with a slot='...' attribute must be a child of a component or a descendant of a custom element\nhttps://svelte.dev/e/slot_attribute_invalid_placement`); } /** @@ -1189,7 +1189,7 @@ export function slot_attribute_invalid_placement(node) { * @returns {never} */ export function slot_default_duplicate(node) { - e(node, "slot_default_duplicate", `Found default slot content alongside an explicit slot="default"\nhttps://svelte.dev/e/slot_default_duplicate`); + e(node, 'slot_default_duplicate', `Found default slot content alongside an explicit slot="default"\nhttps://svelte.dev/e/slot_default_duplicate`); } /** @@ -1198,7 +1198,7 @@ export function slot_default_duplicate(node) { * @returns {never} */ export function slot_element_invalid_attribute(node) { - e(node, "slot_element_invalid_attribute", `\`<slot>\` can only receive attributes and (optionally) let directives\nhttps://svelte.dev/e/slot_element_invalid_attribute`); + e(node, 'slot_element_invalid_attribute', `\`<slot>\` can only receive attributes and (optionally) let directives\nhttps://svelte.dev/e/slot_element_invalid_attribute`); } /** @@ -1207,7 +1207,7 @@ export function slot_element_invalid_attribute(node) { * @returns {never} */ export function slot_element_invalid_name(node) { - e(node, "slot_element_invalid_name", `slot attribute must be a static value\nhttps://svelte.dev/e/slot_element_invalid_name`); + e(node, 'slot_element_invalid_name', `slot attribute must be a static value\nhttps://svelte.dev/e/slot_element_invalid_name`); } /** @@ -1216,7 +1216,7 @@ export function slot_element_invalid_name(node) { * @returns {never} */ export function slot_element_invalid_name_default(node) { - e(node, "slot_element_invalid_name_default", `\`default\` is a reserved word — it cannot be used as a slot name\nhttps://svelte.dev/e/slot_element_invalid_name_default`); + e(node, 'slot_element_invalid_name_default', `\`default\` is a reserved word — it cannot be used as a slot name\nhttps://svelte.dev/e/slot_element_invalid_name_default`); } /** @@ -1225,7 +1225,7 @@ export function slot_element_invalid_name_default(node) { * @returns {never} */ export function slot_snippet_conflict(node) { - e(node, "slot_snippet_conflict", `Cannot use \`<slot>\` syntax and \`{@render ...}\` tags in the same component. Migrate towards \`{@render ...}\` tags completely\nhttps://svelte.dev/e/slot_snippet_conflict`); + e(node, 'slot_snippet_conflict', `Cannot use \`<slot>\` syntax and \`{@render ...}\` tags in the same component. Migrate towards \`{@render ...}\` tags completely\nhttps://svelte.dev/e/slot_snippet_conflict`); } /** @@ -1234,7 +1234,7 @@ export function slot_snippet_conflict(node) { * @returns {never} */ export function snippet_conflict(node) { - e(node, "snippet_conflict", `Cannot use explicit children snippet at the same time as implicit children content. Remove either the non-whitespace content or the children snippet block\nhttps://svelte.dev/e/snippet_conflict`); + e(node, 'snippet_conflict', `Cannot use explicit children snippet at the same time as implicit children content. Remove either the non-whitespace content or the children snippet block\nhttps://svelte.dev/e/snippet_conflict`); } /** @@ -1243,7 +1243,7 @@ export function snippet_conflict(node) { * @returns {never} */ export function snippet_invalid_rest_parameter(node) { - e(node, "snippet_invalid_rest_parameter", `Snippets do not support rest parameters; use an array instead\nhttps://svelte.dev/e/snippet_invalid_rest_parameter`); + e(node, 'snippet_invalid_rest_parameter', `Snippets do not support rest parameters; use an array instead\nhttps://svelte.dev/e/snippet_invalid_rest_parameter`); } /** @@ -1253,7 +1253,7 @@ export function snippet_invalid_rest_parameter(node) { * @returns {never} */ export function snippet_shadowing_prop(node, prop) { - e(node, "snippet_shadowing_prop", `This snippet is shadowing the prop \`${prop}\` with the same name\nhttps://svelte.dev/e/snippet_shadowing_prop`); + e(node, 'snippet_shadowing_prop', `This snippet is shadowing the prop \`${prop}\` with the same name\nhttps://svelte.dev/e/snippet_shadowing_prop`); } /** @@ -1262,7 +1262,7 @@ export function snippet_shadowing_prop(node, prop) { * @returns {never} */ export function style_directive_invalid_modifier(node) { - e(node, "style_directive_invalid_modifier", `\`style:\` directive can only use the \`important\` modifier\nhttps://svelte.dev/e/style_directive_invalid_modifier`); + e(node, 'style_directive_invalid_modifier', `\`style:\` directive can only use the \`important\` modifier\nhttps://svelte.dev/e/style_directive_invalid_modifier`); } /** @@ -1271,7 +1271,7 @@ export function style_directive_invalid_modifier(node) { * @returns {never} */ export function style_duplicate(node) { - e(node, "style_duplicate", `A component can have a single top-level \`<style>\` element\nhttps://svelte.dev/e/style_duplicate`); + e(node, 'style_duplicate', `A component can have a single top-level \`<style>\` element\nhttps://svelte.dev/e/style_duplicate`); } /** @@ -1280,7 +1280,7 @@ export function style_duplicate(node) { * @returns {never} */ export function svelte_body_illegal_attribute(node) { - e(node, "svelte_body_illegal_attribute", `\`<svelte:body>\` does not support non-event attributes or spread attributes\nhttps://svelte.dev/e/svelte_body_illegal_attribute`); + e(node, 'svelte_body_illegal_attribute', `\`<svelte:body>\` does not support non-event attributes or spread attributes\nhttps://svelte.dev/e/svelte_body_illegal_attribute`); } /** @@ -1289,7 +1289,7 @@ export function svelte_body_illegal_attribute(node) { * @returns {never} */ export function svelte_boundary_invalid_attribute(node) { - e(node, "svelte_boundary_invalid_attribute", `Valid attributes on \`<svelte:boundary>\` are \`onerror\` and \`failed\`\nhttps://svelte.dev/e/svelte_boundary_invalid_attribute`); + e(node, 'svelte_boundary_invalid_attribute', `Valid attributes on \`<svelte:boundary>\` are \`onerror\` and \`failed\`\nhttps://svelte.dev/e/svelte_boundary_invalid_attribute`); } /** @@ -1298,7 +1298,7 @@ export function svelte_boundary_invalid_attribute(node) { * @returns {never} */ export function svelte_boundary_invalid_attribute_value(node) { - e(node, "svelte_boundary_invalid_attribute_value", `Attribute value must be a non-string expression\nhttps://svelte.dev/e/svelte_boundary_invalid_attribute_value`); + e(node, 'svelte_boundary_invalid_attribute_value', `Attribute value must be a non-string expression\nhttps://svelte.dev/e/svelte_boundary_invalid_attribute_value`); } /** @@ -1307,7 +1307,7 @@ export function svelte_boundary_invalid_attribute_value(node) { * @returns {never} */ export function svelte_component_invalid_this(node) { - e(node, "svelte_component_invalid_this", `Invalid component definition — must be an \`{expression}\`\nhttps://svelte.dev/e/svelte_component_invalid_this`); + e(node, 'svelte_component_invalid_this', `Invalid component definition — must be an \`{expression}\`\nhttps://svelte.dev/e/svelte_component_invalid_this`); } /** @@ -1316,7 +1316,7 @@ export function svelte_component_invalid_this(node) { * @returns {never} */ export function svelte_component_missing_this(node) { - e(node, "svelte_component_missing_this", `\`<svelte:component>\` must have a 'this' attribute\nhttps://svelte.dev/e/svelte_component_missing_this`); + e(node, 'svelte_component_missing_this', `\`<svelte:component>\` must have a 'this' attribute\nhttps://svelte.dev/e/svelte_component_missing_this`); } /** @@ -1325,7 +1325,7 @@ export function svelte_component_missing_this(node) { * @returns {never} */ export function svelte_element_missing_this(node) { - e(node, "svelte_element_missing_this", `\`<svelte:element>\` must have a 'this' attribute with a value\nhttps://svelte.dev/e/svelte_element_missing_this`); + e(node, 'svelte_element_missing_this', `\`<svelte:element>\` must have a 'this' attribute with a value\nhttps://svelte.dev/e/svelte_element_missing_this`); } /** @@ -1334,7 +1334,7 @@ export function svelte_element_missing_this(node) { * @returns {never} */ export function svelte_fragment_invalid_attribute(node) { - e(node, "svelte_fragment_invalid_attribute", `\`<svelte:fragment>\` can only have a slot attribute and (optionally) a let: directive\nhttps://svelte.dev/e/svelte_fragment_invalid_attribute`); + e(node, 'svelte_fragment_invalid_attribute', `\`<svelte:fragment>\` can only have a slot attribute and (optionally) a let: directive\nhttps://svelte.dev/e/svelte_fragment_invalid_attribute`); } /** @@ -1343,7 +1343,7 @@ export function svelte_fragment_invalid_attribute(node) { * @returns {never} */ export function svelte_fragment_invalid_placement(node) { - e(node, "svelte_fragment_invalid_placement", `\`<svelte:fragment>\` must be the direct child of a component\nhttps://svelte.dev/e/svelte_fragment_invalid_placement`); + e(node, 'svelte_fragment_invalid_placement', `\`<svelte:fragment>\` must be the direct child of a component\nhttps://svelte.dev/e/svelte_fragment_invalid_placement`); } /** @@ -1352,7 +1352,7 @@ export function svelte_fragment_invalid_placement(node) { * @returns {never} */ export function svelte_head_illegal_attribute(node) { - e(node, "svelte_head_illegal_attribute", `\`<svelte:head>\` cannot have attributes nor directives\nhttps://svelte.dev/e/svelte_head_illegal_attribute`); + e(node, 'svelte_head_illegal_attribute', `\`<svelte:head>\` cannot have attributes nor directives\nhttps://svelte.dev/e/svelte_head_illegal_attribute`); } /** @@ -1362,7 +1362,7 @@ export function svelte_head_illegal_attribute(node) { * @returns {never} */ export function svelte_meta_duplicate(node, name) { - e(node, "svelte_meta_duplicate", `A component can only have one \`<${name}>\` element\nhttps://svelte.dev/e/svelte_meta_duplicate`); + e(node, 'svelte_meta_duplicate', `A component can only have one \`<${name}>\` element\nhttps://svelte.dev/e/svelte_meta_duplicate`); } /** @@ -1372,7 +1372,7 @@ export function svelte_meta_duplicate(node, name) { * @returns {never} */ export function svelte_meta_invalid_content(node, name) { - e(node, "svelte_meta_invalid_content", `<${name}> cannot have children\nhttps://svelte.dev/e/svelte_meta_invalid_content`); + e(node, 'svelte_meta_invalid_content', `<${name}> cannot have children\nhttps://svelte.dev/e/svelte_meta_invalid_content`); } /** @@ -1382,7 +1382,7 @@ export function svelte_meta_invalid_content(node, name) { * @returns {never} */ export function svelte_meta_invalid_placement(node, name) { - e(node, "svelte_meta_invalid_placement", `\`<${name}>\` tags cannot be inside elements or blocks\nhttps://svelte.dev/e/svelte_meta_invalid_placement`); + e(node, 'svelte_meta_invalid_placement', `\`<${name}>\` tags cannot be inside elements or blocks\nhttps://svelte.dev/e/svelte_meta_invalid_placement`); } /** @@ -1392,7 +1392,7 @@ export function svelte_meta_invalid_placement(node, name) { * @returns {never} */ export function svelte_meta_invalid_tag(node, list) { - e(node, "svelte_meta_invalid_tag", `Valid \`<svelte:...>\` tag names are ${list}\nhttps://svelte.dev/e/svelte_meta_invalid_tag`); + e(node, 'svelte_meta_invalid_tag', `Valid \`<svelte:...>\` tag names are ${list}\nhttps://svelte.dev/e/svelte_meta_invalid_tag`); } /** @@ -1401,7 +1401,7 @@ export function svelte_meta_invalid_tag(node, list) { * @returns {never} */ export function svelte_options_deprecated_tag(node) { - e(node, "svelte_options_deprecated_tag", `"tag" option is deprecated — use "customElement" instead\nhttps://svelte.dev/e/svelte_options_deprecated_tag`); + e(node, 'svelte_options_deprecated_tag', `"tag" option is deprecated — use "customElement" instead\nhttps://svelte.dev/e/svelte_options_deprecated_tag`); } /** @@ -1410,7 +1410,7 @@ export function svelte_options_deprecated_tag(node) { * @returns {never} */ export function svelte_options_invalid_attribute(node) { - e(node, "svelte_options_invalid_attribute", `\`<svelte:options>\` can only receive static attributes\nhttps://svelte.dev/e/svelte_options_invalid_attribute`); + e(node, 'svelte_options_invalid_attribute', `\`<svelte:options>\` can only receive static attributes\nhttps://svelte.dev/e/svelte_options_invalid_attribute`); } /** @@ -1420,7 +1420,7 @@ export function svelte_options_invalid_attribute(node) { * @returns {never} */ export function svelte_options_invalid_attribute_value(node, list) { - e(node, "svelte_options_invalid_attribute_value", `Value must be ${list}, if specified\nhttps://svelte.dev/e/svelte_options_invalid_attribute_value`); + e(node, 'svelte_options_invalid_attribute_value', `Value must be ${list}, if specified\nhttps://svelte.dev/e/svelte_options_invalid_attribute_value`); } /** @@ -1429,7 +1429,7 @@ export function svelte_options_invalid_attribute_value(node, list) { * @returns {never} */ export function svelte_options_invalid_customelement(node) { - e(node, "svelte_options_invalid_customelement", `"customElement" must be a string literal defining a valid custom element name or an object of the form { tag?: string; shadow?: "open" | "none"; props?: { [key: string]: { attribute?: string; reflect?: boolean; type: .. } } }\nhttps://svelte.dev/e/svelte_options_invalid_customelement`); + e(node, 'svelte_options_invalid_customelement', `"customElement" must be a string literal defining a valid custom element name or an object of the form { tag?: string; shadow?: "open" | "none"; props?: { [key: string]: { attribute?: string; reflect?: boolean; type: .. } } }\nhttps://svelte.dev/e/svelte_options_invalid_customelement`); } /** @@ -1438,7 +1438,7 @@ export function svelte_options_invalid_customelement(node) { * @returns {never} */ export function svelte_options_invalid_customelement_props(node) { - e(node, "svelte_options_invalid_customelement_props", `"props" must be a statically analyzable object literal of the form "{ [key: string]: { attribute?: string; reflect?: boolean; type?: "String" | "Boolean" | "Number" | "Array" | "Object" }"\nhttps://svelte.dev/e/svelte_options_invalid_customelement_props`); + e(node, 'svelte_options_invalid_customelement_props', `"props" must be a statically analyzable object literal of the form "{ [key: string]: { attribute?: string; reflect?: boolean; type?: "String" | "Boolean" | "Number" | "Array" | "Object" }"\nhttps://svelte.dev/e/svelte_options_invalid_customelement_props`); } /** @@ -1447,7 +1447,7 @@ export function svelte_options_invalid_customelement_props(node) { * @returns {never} */ export function svelte_options_invalid_customelement_shadow(node) { - e(node, "svelte_options_invalid_customelement_shadow", `"shadow" must be either "open" or "none"\nhttps://svelte.dev/e/svelte_options_invalid_customelement_shadow`); + e(node, 'svelte_options_invalid_customelement_shadow', `"shadow" must be either "open" or "none"\nhttps://svelte.dev/e/svelte_options_invalid_customelement_shadow`); } /** @@ -1456,7 +1456,7 @@ export function svelte_options_invalid_customelement_shadow(node) { * @returns {never} */ export function svelte_options_invalid_tagname(node) { - e(node, "svelte_options_invalid_tagname", `Tag name must be lowercase and hyphenated\nhttps://svelte.dev/e/svelte_options_invalid_tagname`); + e(node, 'svelte_options_invalid_tagname', `Tag name must be lowercase and hyphenated\nhttps://svelte.dev/e/svelte_options_invalid_tagname`); } /** @@ -1465,7 +1465,7 @@ export function svelte_options_invalid_tagname(node) { * @returns {never} */ export function svelte_options_reserved_tagname(node) { - e(node, "svelte_options_reserved_tagname", `Tag name is reserved\nhttps://svelte.dev/e/svelte_options_reserved_tagname`); + e(node, 'svelte_options_reserved_tagname', `Tag name is reserved\nhttps://svelte.dev/e/svelte_options_reserved_tagname`); } /** @@ -1475,7 +1475,7 @@ export function svelte_options_reserved_tagname(node) { * @returns {never} */ export function svelte_options_unknown_attribute(node, name) { - e(node, "svelte_options_unknown_attribute", `\`<svelte:options>\` unknown attribute '${name}'\nhttps://svelte.dev/e/svelte_options_unknown_attribute`); + e(node, 'svelte_options_unknown_attribute', `\`<svelte:options>\` unknown attribute '${name}'\nhttps://svelte.dev/e/svelte_options_unknown_attribute`); } /** @@ -1484,7 +1484,7 @@ export function svelte_options_unknown_attribute(node, name) { * @returns {never} */ export function svelte_self_invalid_placement(node) { - e(node, "svelte_self_invalid_placement", `\`<svelte:self>\` components can only exist inside \`{#if}\` blocks, \`{#each}\` blocks, \`{#snippet}\` blocks or slots passed to components\nhttps://svelte.dev/e/svelte_self_invalid_placement`); + e(node, 'svelte_self_invalid_placement', `\`<svelte:self>\` components can only exist inside \`{#if}\` blocks, \`{#each}\` blocks, \`{#snippet}\` blocks or slots passed to components\nhttps://svelte.dev/e/svelte_self_invalid_placement`); } /** @@ -1493,7 +1493,7 @@ export function svelte_self_invalid_placement(node) { * @returns {never} */ export function tag_invalid_name(node) { - e(node, "tag_invalid_name", `Expected a valid element or component name. Components must have a valid variable name or dot notation expression\nhttps://svelte.dev/e/tag_invalid_name`); + e(node, 'tag_invalid_name', `Expected a valid element or component name. Components must have a valid variable name or dot notation expression\nhttps://svelte.dev/e/tag_invalid_name`); } /** @@ -1504,7 +1504,7 @@ export function tag_invalid_name(node) { * @returns {never} */ export function tag_invalid_placement(node, name, location) { - e(node, "tag_invalid_placement", `{@${name} ...} tag cannot be ${location}\nhttps://svelte.dev/e/tag_invalid_placement`); + e(node, 'tag_invalid_placement', `{@${name} ...} tag cannot be ${location}\nhttps://svelte.dev/e/tag_invalid_placement`); } /** @@ -1513,7 +1513,7 @@ export function tag_invalid_placement(node, name, location) { * @returns {never} */ export function textarea_invalid_content(node) { - e(node, "textarea_invalid_content", `A \`<textarea>\` can have either a value attribute or (equivalently) child content, but not both\nhttps://svelte.dev/e/textarea_invalid_content`); + e(node, 'textarea_invalid_content', `A \`<textarea>\` can have either a value attribute or (equivalently) child content, but not both\nhttps://svelte.dev/e/textarea_invalid_content`); } /** @@ -1522,7 +1522,7 @@ export function textarea_invalid_content(node) { * @returns {never} */ export function title_illegal_attribute(node) { - e(node, "title_illegal_attribute", `\`<title>\` cannot have attributes nor directives\nhttps://svelte.dev/e/title_illegal_attribute`); + e(node, 'title_illegal_attribute', `\`<title>\` cannot have attributes nor directives\nhttps://svelte.dev/e/title_illegal_attribute`); } /** @@ -1531,7 +1531,7 @@ export function title_illegal_attribute(node) { * @returns {never} */ export function title_invalid_content(node) { - e(node, "title_invalid_content", `\`<title>\` can only contain text and {tags}\nhttps://svelte.dev/e/title_invalid_content`); + e(node, 'title_invalid_content', `\`<title>\` can only contain text and {tags}\nhttps://svelte.dev/e/title_invalid_content`); } /** @@ -1542,7 +1542,7 @@ export function title_invalid_content(node) { * @returns {never} */ export function transition_conflict(node, type, existing) { - e(node, "transition_conflict", `Cannot use \`${type}:\` alongside existing \`${existing}:\` directive\nhttps://svelte.dev/e/transition_conflict`); + e(node, 'transition_conflict', `Cannot use \`${type}:\` alongside existing \`${existing}:\` directive\nhttps://svelte.dev/e/transition_conflict`); } /** @@ -1552,7 +1552,7 @@ export function transition_conflict(node, type, existing) { * @returns {never} */ export function transition_duplicate(node, type) { - e(node, "transition_duplicate", `Cannot use multiple \`${type}:\` directives on a single element\nhttps://svelte.dev/e/transition_duplicate`); + e(node, 'transition_duplicate', `Cannot use multiple \`${type}:\` directives on a single element\nhttps://svelte.dev/e/transition_duplicate`); } /** @@ -1561,7 +1561,7 @@ export function transition_duplicate(node, type) { * @returns {never} */ export function unexpected_eof(node) { - e(node, "unexpected_eof", `Unexpected end of input\nhttps://svelte.dev/e/unexpected_eof`); + e(node, 'unexpected_eof', `Unexpected end of input\nhttps://svelte.dev/e/unexpected_eof`); } /** @@ -1571,7 +1571,7 @@ export function unexpected_eof(node) { * @returns {never} */ export function unexpected_reserved_word(node, word) { - e(node, "unexpected_reserved_word", `'${word}' is a reserved word in JavaScript and cannot be used here\nhttps://svelte.dev/e/unexpected_reserved_word`); + e(node, 'unexpected_reserved_word', `'${word}' is a reserved word in JavaScript and cannot be used here\nhttps://svelte.dev/e/unexpected_reserved_word`); } /** @@ -1580,7 +1580,7 @@ export function unexpected_reserved_word(node, word) { * @returns {never} */ export function unterminated_string_constant(node) { - e(node, "unterminated_string_constant", `Unterminated string constant\nhttps://svelte.dev/e/unterminated_string_constant`); + e(node, 'unterminated_string_constant', `Unterminated string constant\nhttps://svelte.dev/e/unterminated_string_constant`); } /** @@ -1589,5 +1589,5 @@ export function unterminated_string_constant(node) { * @returns {never} */ export function void_element_invalid_content(node) { - e(node, "void_element_invalid_content", `Void elements cannot have children or closing tags\nhttps://svelte.dev/e/void_element_invalid_content`); + e(node, 'void_element_invalid_content', `Void elements cannot have children or closing tags\nhttps://svelte.dev/e/void_element_invalid_content`); } \ No newline at end of file diff --git a/packages/svelte/src/compiler/warnings.js b/packages/svelte/src/compiler/warnings.js index 81d4e3240e..a9ea617d3f 100644 --- a/packages/svelte/src/compiler/warnings.js +++ b/packages/svelte/src/compiler/warnings.js @@ -44,84 +44,84 @@ function w(node, code, message) { } export const codes = [ - "a11y_accesskey", - "a11y_aria_activedescendant_has_tabindex", - "a11y_aria_attributes", - "a11y_autocomplete_valid", - "a11y_autofocus", - "a11y_click_events_have_key_events", - "a11y_consider_explicit_label", - "a11y_distracting_elements", - "a11y_figcaption_index", - "a11y_figcaption_parent", - "a11y_hidden", - "a11y_img_redundant_alt", - "a11y_incorrect_aria_attribute_type", - "a11y_incorrect_aria_attribute_type_boolean", - "a11y_incorrect_aria_attribute_type_id", - "a11y_incorrect_aria_attribute_type_idlist", - "a11y_incorrect_aria_attribute_type_integer", - "a11y_incorrect_aria_attribute_type_token", - "a11y_incorrect_aria_attribute_type_tokenlist", - "a11y_incorrect_aria_attribute_type_tristate", - "a11y_interactive_supports_focus", - "a11y_invalid_attribute", - "a11y_label_has_associated_control", - "a11y_media_has_caption", - "a11y_misplaced_role", - "a11y_misplaced_scope", - "a11y_missing_attribute", - "a11y_missing_content", - "a11y_mouse_events_have_key_events", - "a11y_no_abstract_role", - "a11y_no_interactive_element_to_noninteractive_role", - "a11y_no_noninteractive_element_interactions", - "a11y_no_noninteractive_element_to_interactive_role", - "a11y_no_noninteractive_tabindex", - "a11y_no_redundant_roles", - "a11y_no_static_element_interactions", - "a11y_positive_tabindex", - "a11y_role_has_required_aria_props", - "a11y_role_supports_aria_props", - "a11y_role_supports_aria_props_implicit", - "a11y_unknown_aria_attribute", - "a11y_unknown_role", - "legacy_code", - "unknown_code", - "options_deprecated_accessors", - "options_deprecated_immutable", - "options_missing_custom_element", - "options_removed_enable_sourcemap", - "options_removed_hydratable", - "options_removed_loop_guard_timeout", - "options_renamed_ssr_dom", - "export_let_unused", - "legacy_component_creation", - "non_reactive_update", - "perf_avoid_inline_class", - "perf_avoid_nested_class", - "reactive_declaration_invalid_placement", - "reactive_declaration_module_script_dependency", - "state_referenced_locally", - "store_rune_conflict", - "css_unused_selector", - "attribute_avoid_is", - "attribute_global_event_reference", - "attribute_illegal_colon", - "attribute_invalid_property_name", - "attribute_quoted", - "bind_invalid_each_rest", - "block_empty", - "component_name_lowercase", - "element_invalid_self_closing_tag", - "event_directive_deprecated", - "node_invalid_placement_ssr", - "script_context_deprecated", - "script_unknown_attribute", - "slot_element_deprecated", - "svelte_component_deprecated", - "svelte_element_invalid_this", - "svelte_self_deprecated" + 'a11y_accesskey', + 'a11y_aria_activedescendant_has_tabindex', + 'a11y_aria_attributes', + 'a11y_autocomplete_valid', + 'a11y_autofocus', + 'a11y_click_events_have_key_events', + 'a11y_consider_explicit_label', + 'a11y_distracting_elements', + 'a11y_figcaption_index', + 'a11y_figcaption_parent', + 'a11y_hidden', + 'a11y_img_redundant_alt', + 'a11y_incorrect_aria_attribute_type', + 'a11y_incorrect_aria_attribute_type_boolean', + 'a11y_incorrect_aria_attribute_type_id', + 'a11y_incorrect_aria_attribute_type_idlist', + 'a11y_incorrect_aria_attribute_type_integer', + 'a11y_incorrect_aria_attribute_type_token', + 'a11y_incorrect_aria_attribute_type_tokenlist', + 'a11y_incorrect_aria_attribute_type_tristate', + 'a11y_interactive_supports_focus', + 'a11y_invalid_attribute', + 'a11y_label_has_associated_control', + 'a11y_media_has_caption', + 'a11y_misplaced_role', + 'a11y_misplaced_scope', + 'a11y_missing_attribute', + 'a11y_missing_content', + 'a11y_mouse_events_have_key_events', + 'a11y_no_abstract_role', + 'a11y_no_interactive_element_to_noninteractive_role', + 'a11y_no_noninteractive_element_interactions', + 'a11y_no_noninteractive_element_to_interactive_role', + 'a11y_no_noninteractive_tabindex', + 'a11y_no_redundant_roles', + 'a11y_no_static_element_interactions', + 'a11y_positive_tabindex', + 'a11y_role_has_required_aria_props', + 'a11y_role_supports_aria_props', + 'a11y_role_supports_aria_props_implicit', + 'a11y_unknown_aria_attribute', + 'a11y_unknown_role', + 'legacy_code', + 'unknown_code', + 'options_deprecated_accessors', + 'options_deprecated_immutable', + 'options_missing_custom_element', + 'options_removed_enable_sourcemap', + 'options_removed_hydratable', + 'options_removed_loop_guard_timeout', + 'options_renamed_ssr_dom', + 'export_let_unused', + 'legacy_component_creation', + 'non_reactive_update', + 'perf_avoid_inline_class', + 'perf_avoid_nested_class', + 'reactive_declaration_invalid_placement', + 'reactive_declaration_module_script_dependency', + 'state_referenced_locally', + 'store_rune_conflict', + 'css_unused_selector', + 'attribute_avoid_is', + 'attribute_global_event_reference', + 'attribute_illegal_colon', + 'attribute_invalid_property_name', + 'attribute_quoted', + 'bind_invalid_each_rest', + 'block_empty', + 'component_name_lowercase', + 'element_invalid_self_closing_tag', + 'event_directive_deprecated', + 'node_invalid_placement_ssr', + 'script_context_deprecated', + 'script_unknown_attribute', + 'slot_element_deprecated', + 'svelte_component_deprecated', + 'svelte_element_invalid_this', + 'svelte_self_deprecated' ]; /** @@ -129,7 +129,7 @@ export const codes = [ * @param {null | NodeLike} node */ export function a11y_accesskey(node) { - w(node, "a11y_accesskey", `Avoid using accesskey\nhttps://svelte.dev/e/a11y_accesskey`); + w(node, 'a11y_accesskey', `Avoid using accesskey\nhttps://svelte.dev/e/a11y_accesskey`); } /** @@ -137,7 +137,7 @@ export function a11y_accesskey(node) { * @param {null | NodeLike} node */ export function a11y_aria_activedescendant_has_tabindex(node) { - w(node, "a11y_aria_activedescendant_has_tabindex", `An element with an aria-activedescendant attribute should have a tabindex value\nhttps://svelte.dev/e/a11y_aria_activedescendant_has_tabindex`); + w(node, 'a11y_aria_activedescendant_has_tabindex', `An element with an aria-activedescendant attribute should have a tabindex value\nhttps://svelte.dev/e/a11y_aria_activedescendant_has_tabindex`); } /** @@ -146,7 +146,7 @@ export function a11y_aria_activedescendant_has_tabindex(node) { * @param {string} name */ export function a11y_aria_attributes(node, name) { - w(node, "a11y_aria_attributes", `\`<${name}>\` should not have aria-* attributes\nhttps://svelte.dev/e/a11y_aria_attributes`); + w(node, 'a11y_aria_attributes', `\`<${name}>\` should not have aria-* attributes\nhttps://svelte.dev/e/a11y_aria_attributes`); } /** @@ -156,7 +156,7 @@ export function a11y_aria_attributes(node, name) { * @param {string} type */ export function a11y_autocomplete_valid(node, value, type) { - w(node, "a11y_autocomplete_valid", `'${value}' is an invalid value for 'autocomplete' on \`<input type="${type}">\`\nhttps://svelte.dev/e/a11y_autocomplete_valid`); + w(node, 'a11y_autocomplete_valid', `'${value}' is an invalid value for 'autocomplete' on \`<input type="${type}">\`\nhttps://svelte.dev/e/a11y_autocomplete_valid`); } /** @@ -164,7 +164,7 @@ export function a11y_autocomplete_valid(node, value, type) { * @param {null | NodeLike} node */ export function a11y_autofocus(node) { - w(node, "a11y_autofocus", `Avoid using autofocus\nhttps://svelte.dev/e/a11y_autofocus`); + w(node, 'a11y_autofocus', `Avoid using autofocus\nhttps://svelte.dev/e/a11y_autofocus`); } /** @@ -172,7 +172,7 @@ export function a11y_autofocus(node) { * @param {null | NodeLike} node */ export function a11y_click_events_have_key_events(node) { - w(node, "a11y_click_events_have_key_events", `Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as \`<button type="button">\` or \`<a>\` might be more appropriate\nhttps://svelte.dev/e/a11y_click_events_have_key_events`); + w(node, 'a11y_click_events_have_key_events', `Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as \`<button type="button">\` or \`<a>\` might be more appropriate\nhttps://svelte.dev/e/a11y_click_events_have_key_events`); } /** @@ -180,7 +180,7 @@ export function a11y_click_events_have_key_events(node) { * @param {null | NodeLike} node */ export function a11y_consider_explicit_label(node) { - w(node, "a11y_consider_explicit_label", `Buttons and links should either contain text or have an \`aria-label\` or \`aria-labelledby\` attribute\nhttps://svelte.dev/e/a11y_consider_explicit_label`); + w(node, 'a11y_consider_explicit_label', `Buttons and links should either contain text or have an \`aria-label\` or \`aria-labelledby\` attribute\nhttps://svelte.dev/e/a11y_consider_explicit_label`); } /** @@ -189,7 +189,7 @@ export function a11y_consider_explicit_label(node) { * @param {string} name */ export function a11y_distracting_elements(node, name) { - w(node, "a11y_distracting_elements", `Avoid \`<${name}>\` elements\nhttps://svelte.dev/e/a11y_distracting_elements`); + w(node, 'a11y_distracting_elements', `Avoid \`<${name}>\` elements\nhttps://svelte.dev/e/a11y_distracting_elements`); } /** @@ -197,7 +197,7 @@ export function a11y_distracting_elements(node, name) { * @param {null | NodeLike} node */ export function a11y_figcaption_index(node) { - w(node, "a11y_figcaption_index", `\`<figcaption>\` must be first or last child of \`<figure>\`\nhttps://svelte.dev/e/a11y_figcaption_index`); + w(node, 'a11y_figcaption_index', `\`<figcaption>\` must be first or last child of \`<figure>\`\nhttps://svelte.dev/e/a11y_figcaption_index`); } /** @@ -205,7 +205,7 @@ export function a11y_figcaption_index(node) { * @param {null | NodeLike} node */ export function a11y_figcaption_parent(node) { - w(node, "a11y_figcaption_parent", `\`<figcaption>\` must be an immediate child of \`<figure>\`\nhttps://svelte.dev/e/a11y_figcaption_parent`); + w(node, 'a11y_figcaption_parent', `\`<figcaption>\` must be an immediate child of \`<figure>\`\nhttps://svelte.dev/e/a11y_figcaption_parent`); } /** @@ -214,7 +214,7 @@ export function a11y_figcaption_parent(node) { * @param {string} name */ export function a11y_hidden(node, name) { - w(node, "a11y_hidden", `\`<${name}>\` element should not be hidden\nhttps://svelte.dev/e/a11y_hidden`); + w(node, 'a11y_hidden', `\`<${name}>\` element should not be hidden\nhttps://svelte.dev/e/a11y_hidden`); } /** @@ -222,7 +222,7 @@ export function a11y_hidden(node, name) { * @param {null | NodeLike} node */ export function a11y_img_redundant_alt(node) { - w(node, "a11y_img_redundant_alt", `Screenreaders already announce \`<img>\` elements as an image\nhttps://svelte.dev/e/a11y_img_redundant_alt`); + w(node, 'a11y_img_redundant_alt', `Screenreaders already announce \`<img>\` elements as an image\nhttps://svelte.dev/e/a11y_img_redundant_alt`); } /** @@ -232,7 +232,7 @@ export function a11y_img_redundant_alt(node) { * @param {string} type */ export function a11y_incorrect_aria_attribute_type(node, attribute, type) { - w(node, "a11y_incorrect_aria_attribute_type", `The value of '${attribute}' must be a ${type}\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type`); + w(node, 'a11y_incorrect_aria_attribute_type', `The value of '${attribute}' must be a ${type}\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type`); } /** @@ -241,7 +241,7 @@ export function a11y_incorrect_aria_attribute_type(node, attribute, type) { * @param {string} attribute */ export function a11y_incorrect_aria_attribute_type_boolean(node, attribute) { - w(node, "a11y_incorrect_aria_attribute_type_boolean", `The value of '${attribute}' must be either 'true' or 'false'. It cannot be empty\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type_boolean`); + w(node, 'a11y_incorrect_aria_attribute_type_boolean', `The value of '${attribute}' must be either 'true' or 'false'. It cannot be empty\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type_boolean`); } /** @@ -250,7 +250,7 @@ export function a11y_incorrect_aria_attribute_type_boolean(node, attribute) { * @param {string} attribute */ export function a11y_incorrect_aria_attribute_type_id(node, attribute) { - w(node, "a11y_incorrect_aria_attribute_type_id", `The value of '${attribute}' must be a string that represents a DOM element ID\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type_id`); + w(node, 'a11y_incorrect_aria_attribute_type_id', `The value of '${attribute}' must be a string that represents a DOM element ID\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type_id`); } /** @@ -259,7 +259,7 @@ export function a11y_incorrect_aria_attribute_type_id(node, attribute) { * @param {string} attribute */ export function a11y_incorrect_aria_attribute_type_idlist(node, attribute) { - w(node, "a11y_incorrect_aria_attribute_type_idlist", `The value of '${attribute}' must be a space-separated list of strings that represent DOM element IDs\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type_idlist`); + w(node, 'a11y_incorrect_aria_attribute_type_idlist', `The value of '${attribute}' must be a space-separated list of strings that represent DOM element IDs\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type_idlist`); } /** @@ -268,7 +268,7 @@ export function a11y_incorrect_aria_attribute_type_idlist(node, attribute) { * @param {string} attribute */ export function a11y_incorrect_aria_attribute_type_integer(node, attribute) { - w(node, "a11y_incorrect_aria_attribute_type_integer", `The value of '${attribute}' must be an integer\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type_integer`); + w(node, 'a11y_incorrect_aria_attribute_type_integer', `The value of '${attribute}' must be an integer\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type_integer`); } /** @@ -278,7 +278,7 @@ export function a11y_incorrect_aria_attribute_type_integer(node, attribute) { * @param {string} values */ export function a11y_incorrect_aria_attribute_type_token(node, attribute, values) { - w(node, "a11y_incorrect_aria_attribute_type_token", `The value of '${attribute}' must be exactly one of ${values}\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type_token`); + w(node, 'a11y_incorrect_aria_attribute_type_token', `The value of '${attribute}' must be exactly one of ${values}\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type_token`); } /** @@ -288,7 +288,7 @@ export function a11y_incorrect_aria_attribute_type_token(node, attribute, values * @param {string} values */ export function a11y_incorrect_aria_attribute_type_tokenlist(node, attribute, values) { - w(node, "a11y_incorrect_aria_attribute_type_tokenlist", `The value of '${attribute}' must be a space-separated list of one or more of ${values}\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type_tokenlist`); + w(node, 'a11y_incorrect_aria_attribute_type_tokenlist', `The value of '${attribute}' must be a space-separated list of one or more of ${values}\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type_tokenlist`); } /** @@ -297,7 +297,7 @@ export function a11y_incorrect_aria_attribute_type_tokenlist(node, attribute, va * @param {string} attribute */ export function a11y_incorrect_aria_attribute_type_tristate(node, attribute) { - w(node, "a11y_incorrect_aria_attribute_type_tristate", `The value of '${attribute}' must be exactly one of true, false, or mixed\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type_tristate`); + w(node, 'a11y_incorrect_aria_attribute_type_tristate', `The value of '${attribute}' must be exactly one of true, false, or mixed\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type_tristate`); } /** @@ -306,7 +306,7 @@ export function a11y_incorrect_aria_attribute_type_tristate(node, attribute) { * @param {string} role */ export function a11y_interactive_supports_focus(node, role) { - w(node, "a11y_interactive_supports_focus", `Elements with the '${role}' interactive role must have a tabindex value\nhttps://svelte.dev/e/a11y_interactive_supports_focus`); + w(node, 'a11y_interactive_supports_focus', `Elements with the '${role}' interactive role must have a tabindex value\nhttps://svelte.dev/e/a11y_interactive_supports_focus`); } /** @@ -316,7 +316,7 @@ export function a11y_interactive_supports_focus(node, role) { * @param {string} href_attribute */ export function a11y_invalid_attribute(node, href_value, href_attribute) { - w(node, "a11y_invalid_attribute", `'${href_value}' is not a valid ${href_attribute} attribute\nhttps://svelte.dev/e/a11y_invalid_attribute`); + w(node, 'a11y_invalid_attribute', `'${href_value}' is not a valid ${href_attribute} attribute\nhttps://svelte.dev/e/a11y_invalid_attribute`); } /** @@ -324,7 +324,7 @@ export function a11y_invalid_attribute(node, href_value, href_attribute) { * @param {null | NodeLike} node */ export function a11y_label_has_associated_control(node) { - w(node, "a11y_label_has_associated_control", `A form label must be associated with a control\nhttps://svelte.dev/e/a11y_label_has_associated_control`); + w(node, 'a11y_label_has_associated_control', `A form label must be associated with a control\nhttps://svelte.dev/e/a11y_label_has_associated_control`); } /** @@ -332,7 +332,7 @@ export function a11y_label_has_associated_control(node) { * @param {null | NodeLike} node */ export function a11y_media_has_caption(node) { - w(node, "a11y_media_has_caption", `\`<video>\` elements must have a \`<track kind="captions">\`\nhttps://svelte.dev/e/a11y_media_has_caption`); + w(node, 'a11y_media_has_caption', `\`<video>\` elements must have a \`<track kind="captions">\`\nhttps://svelte.dev/e/a11y_media_has_caption`); } /** @@ -341,7 +341,7 @@ export function a11y_media_has_caption(node) { * @param {string} name */ export function a11y_misplaced_role(node, name) { - w(node, "a11y_misplaced_role", `\`<${name}>\` should not have role attribute\nhttps://svelte.dev/e/a11y_misplaced_role`); + w(node, 'a11y_misplaced_role', `\`<${name}>\` should not have role attribute\nhttps://svelte.dev/e/a11y_misplaced_role`); } /** @@ -349,7 +349,7 @@ export function a11y_misplaced_role(node, name) { * @param {null | NodeLike} node */ export function a11y_misplaced_scope(node) { - w(node, "a11y_misplaced_scope", `The scope attribute should only be used with \`<th>\` elements\nhttps://svelte.dev/e/a11y_misplaced_scope`); + w(node, 'a11y_misplaced_scope', `The scope attribute should only be used with \`<th>\` elements\nhttps://svelte.dev/e/a11y_misplaced_scope`); } /** @@ -360,7 +360,7 @@ export function a11y_misplaced_scope(node) { * @param {string} sequence */ export function a11y_missing_attribute(node, name, article, sequence) { - w(node, "a11y_missing_attribute", `\`<${name}>\` element should have ${article} ${sequence} attribute\nhttps://svelte.dev/e/a11y_missing_attribute`); + w(node, 'a11y_missing_attribute', `\`<${name}>\` element should have ${article} ${sequence} attribute\nhttps://svelte.dev/e/a11y_missing_attribute`); } /** @@ -369,7 +369,7 @@ export function a11y_missing_attribute(node, name, article, sequence) { * @param {string} name */ export function a11y_missing_content(node, name) { - w(node, "a11y_missing_content", `\`<${name}>\` element should contain text\nhttps://svelte.dev/e/a11y_missing_content`); + w(node, 'a11y_missing_content', `\`<${name}>\` element should contain text\nhttps://svelte.dev/e/a11y_missing_content`); } /** @@ -379,7 +379,7 @@ export function a11y_missing_content(node, name) { * @param {string} accompanied_by */ export function a11y_mouse_events_have_key_events(node, event, accompanied_by) { - w(node, "a11y_mouse_events_have_key_events", `'${event}' event must be accompanied by '${accompanied_by}' event\nhttps://svelte.dev/e/a11y_mouse_events_have_key_events`); + w(node, 'a11y_mouse_events_have_key_events', `'${event}' event must be accompanied by '${accompanied_by}' event\nhttps://svelte.dev/e/a11y_mouse_events_have_key_events`); } /** @@ -388,7 +388,7 @@ export function a11y_mouse_events_have_key_events(node, event, accompanied_by) { * @param {string} role */ export function a11y_no_abstract_role(node, role) { - w(node, "a11y_no_abstract_role", `Abstract role '${role}' is forbidden\nhttps://svelte.dev/e/a11y_no_abstract_role`); + w(node, 'a11y_no_abstract_role', `Abstract role '${role}' is forbidden\nhttps://svelte.dev/e/a11y_no_abstract_role`); } /** @@ -398,7 +398,7 @@ export function a11y_no_abstract_role(node, role) { * @param {string} role */ export function a11y_no_interactive_element_to_noninteractive_role(node, element, role) { - w(node, "a11y_no_interactive_element_to_noninteractive_role", `\`<${element}>\` cannot have role '${role}'\nhttps://svelte.dev/e/a11y_no_interactive_element_to_noninteractive_role`); + w(node, 'a11y_no_interactive_element_to_noninteractive_role', `\`<${element}>\` cannot have role '${role}'\nhttps://svelte.dev/e/a11y_no_interactive_element_to_noninteractive_role`); } /** @@ -407,7 +407,7 @@ export function a11y_no_interactive_element_to_noninteractive_role(node, element * @param {string} element */ export function a11y_no_noninteractive_element_interactions(node, element) { - w(node, "a11y_no_noninteractive_element_interactions", `Non-interactive element \`<${element}>\` should not be assigned mouse or keyboard event listeners\nhttps://svelte.dev/e/a11y_no_noninteractive_element_interactions`); + w(node, 'a11y_no_noninteractive_element_interactions', `Non-interactive element \`<${element}>\` should not be assigned mouse or keyboard event listeners\nhttps://svelte.dev/e/a11y_no_noninteractive_element_interactions`); } /** @@ -417,7 +417,7 @@ export function a11y_no_noninteractive_element_interactions(node, element) { * @param {string} role */ export function a11y_no_noninteractive_element_to_interactive_role(node, element, role) { - w(node, "a11y_no_noninteractive_element_to_interactive_role", `Non-interactive element \`<${element}>\` cannot have interactive role '${role}'\nhttps://svelte.dev/e/a11y_no_noninteractive_element_to_interactive_role`); + w(node, 'a11y_no_noninteractive_element_to_interactive_role', `Non-interactive element \`<${element}>\` cannot have interactive role '${role}'\nhttps://svelte.dev/e/a11y_no_noninteractive_element_to_interactive_role`); } /** @@ -425,7 +425,7 @@ export function a11y_no_noninteractive_element_to_interactive_role(node, element * @param {null | NodeLike} node */ export function a11y_no_noninteractive_tabindex(node) { - w(node, "a11y_no_noninteractive_tabindex", `noninteractive element cannot have nonnegative tabIndex value\nhttps://svelte.dev/e/a11y_no_noninteractive_tabindex`); + w(node, 'a11y_no_noninteractive_tabindex', `noninteractive element cannot have nonnegative tabIndex value\nhttps://svelte.dev/e/a11y_no_noninteractive_tabindex`); } /** @@ -434,7 +434,7 @@ export function a11y_no_noninteractive_tabindex(node) { * @param {string} role */ export function a11y_no_redundant_roles(node, role) { - w(node, "a11y_no_redundant_roles", `Redundant role '${role}'\nhttps://svelte.dev/e/a11y_no_redundant_roles`); + w(node, 'a11y_no_redundant_roles', `Redundant role '${role}'\nhttps://svelte.dev/e/a11y_no_redundant_roles`); } /** @@ -444,7 +444,7 @@ export function a11y_no_redundant_roles(node, role) { * @param {string} handler */ export function a11y_no_static_element_interactions(node, element, handler) { - w(node, "a11y_no_static_element_interactions", `\`<${element}>\` with a ${handler} handler must have an ARIA role\nhttps://svelte.dev/e/a11y_no_static_element_interactions`); + w(node, 'a11y_no_static_element_interactions', `\`<${element}>\` with a ${handler} handler must have an ARIA role\nhttps://svelte.dev/e/a11y_no_static_element_interactions`); } /** @@ -452,7 +452,7 @@ export function a11y_no_static_element_interactions(node, element, handler) { * @param {null | NodeLike} node */ export function a11y_positive_tabindex(node) { - w(node, "a11y_positive_tabindex", `Avoid tabindex values above zero\nhttps://svelte.dev/e/a11y_positive_tabindex`); + w(node, 'a11y_positive_tabindex', `Avoid tabindex values above zero\nhttps://svelte.dev/e/a11y_positive_tabindex`); } /** @@ -462,7 +462,7 @@ export function a11y_positive_tabindex(node) { * @param {string} props */ export function a11y_role_has_required_aria_props(node, role, props) { - w(node, "a11y_role_has_required_aria_props", `Elements with the ARIA role "${role}" must have the following attributes defined: ${props}\nhttps://svelte.dev/e/a11y_role_has_required_aria_props`); + w(node, 'a11y_role_has_required_aria_props', `Elements with the ARIA role "${role}" must have the following attributes defined: ${props}\nhttps://svelte.dev/e/a11y_role_has_required_aria_props`); } /** @@ -472,7 +472,7 @@ export function a11y_role_has_required_aria_props(node, role, props) { * @param {string} role */ export function a11y_role_supports_aria_props(node, attribute, role) { - w(node, "a11y_role_supports_aria_props", `The attribute '${attribute}' is not supported by the role '${role}'\nhttps://svelte.dev/e/a11y_role_supports_aria_props`); + w(node, 'a11y_role_supports_aria_props', `The attribute '${attribute}' is not supported by the role '${role}'\nhttps://svelte.dev/e/a11y_role_supports_aria_props`); } /** @@ -483,7 +483,7 @@ export function a11y_role_supports_aria_props(node, attribute, role) { * @param {string} name */ export function a11y_role_supports_aria_props_implicit(node, attribute, role, name) { - w(node, "a11y_role_supports_aria_props_implicit", `The attribute '${attribute}' is not supported by the role '${role}'. This role is implicit on the element \`<${name}>\`\nhttps://svelte.dev/e/a11y_role_supports_aria_props_implicit`); + w(node, 'a11y_role_supports_aria_props_implicit', `The attribute '${attribute}' is not supported by the role '${role}'. This role is implicit on the element \`<${name}>\`\nhttps://svelte.dev/e/a11y_role_supports_aria_props_implicit`); } /** @@ -493,7 +493,7 @@ export function a11y_role_supports_aria_props_implicit(node, attribute, role, na * @param {string | undefined | null} [suggestion] */ export function a11y_unknown_aria_attribute(node, attribute, suggestion) { - w(node, "a11y_unknown_aria_attribute", `${suggestion ? `Unknown aria attribute 'aria-${attribute}'. Did you mean '${suggestion}'?` : `Unknown aria attribute 'aria-${attribute}'`}\nhttps://svelte.dev/e/a11y_unknown_aria_attribute`); + w(node, 'a11y_unknown_aria_attribute', `${suggestion ? `Unknown aria attribute 'aria-${attribute}'. Did you mean '${suggestion}'?` : `Unknown aria attribute 'aria-${attribute}'`}\nhttps://svelte.dev/e/a11y_unknown_aria_attribute`); } /** @@ -503,7 +503,7 @@ export function a11y_unknown_aria_attribute(node, attribute, suggestion) { * @param {string | undefined | null} [suggestion] */ export function a11y_unknown_role(node, role, suggestion) { - w(node, "a11y_unknown_role", `${suggestion ? `Unknown role '${role}'. Did you mean '${suggestion}'?` : `Unknown role '${role}'`}\nhttps://svelte.dev/e/a11y_unknown_role`); + w(node, 'a11y_unknown_role', `${suggestion ? `Unknown role '${role}'. Did you mean '${suggestion}'?` : `Unknown role '${role}'`}\nhttps://svelte.dev/e/a11y_unknown_role`); } /** @@ -513,7 +513,7 @@ export function a11y_unknown_role(node, role, suggestion) { * @param {string} suggestion */ export function legacy_code(node, code, suggestion) { - w(node, "legacy_code", `\`${code}\` is no longer valid — please use \`${suggestion}\` instead\nhttps://svelte.dev/e/legacy_code`); + w(node, 'legacy_code', `\`${code}\` is no longer valid — please use \`${suggestion}\` instead\nhttps://svelte.dev/e/legacy_code`); } /** @@ -523,7 +523,7 @@ export function legacy_code(node, code, suggestion) { * @param {string | undefined | null} [suggestion] */ export function unknown_code(node, code, suggestion) { - w(node, "unknown_code", `${suggestion ? `\`${code}\` is not a recognised code (did you mean \`${suggestion}\`?)` : `\`${code}\` is not a recognised code`}\nhttps://svelte.dev/e/unknown_code`); + w(node, 'unknown_code', `${suggestion ? `\`${code}\` is not a recognised code (did you mean \`${suggestion}\`?)` : `\`${code}\` is not a recognised code`}\nhttps://svelte.dev/e/unknown_code`); } /** @@ -531,7 +531,7 @@ export function unknown_code(node, code, suggestion) { * @param {null | NodeLike} node */ export function options_deprecated_accessors(node) { - w(node, "options_deprecated_accessors", `The \`accessors\` option has been deprecated. It will have no effect in runes mode\nhttps://svelte.dev/e/options_deprecated_accessors`); + w(node, 'options_deprecated_accessors', `The \`accessors\` option has been deprecated. It will have no effect in runes mode\nhttps://svelte.dev/e/options_deprecated_accessors`); } /** @@ -539,7 +539,7 @@ export function options_deprecated_accessors(node) { * @param {null | NodeLike} node */ export function options_deprecated_immutable(node) { - w(node, "options_deprecated_immutable", `The \`immutable\` option has been deprecated. It will have no effect in runes mode\nhttps://svelte.dev/e/options_deprecated_immutable`); + w(node, 'options_deprecated_immutable', `The \`immutable\` option has been deprecated. It will have no effect in runes mode\nhttps://svelte.dev/e/options_deprecated_immutable`); } /** @@ -547,7 +547,7 @@ export function options_deprecated_immutable(node) { * @param {null | NodeLike} node */ export function options_missing_custom_element(node) { - w(node, "options_missing_custom_element", `The \`customElement\` option is used when generating a custom element. Did you forget the \`customElement: true\` compile option?\nhttps://svelte.dev/e/options_missing_custom_element`); + w(node, 'options_missing_custom_element', `The \`customElement\` option is used when generating a custom element. Did you forget the \`customElement: true\` compile option?\nhttps://svelte.dev/e/options_missing_custom_element`); } /** @@ -555,7 +555,7 @@ export function options_missing_custom_element(node) { * @param {null | NodeLike} node */ export function options_removed_enable_sourcemap(node) { - w(node, "options_removed_enable_sourcemap", `The \`enableSourcemap\` option has been removed. Source maps are always generated now, and tooling can choose to ignore them\nhttps://svelte.dev/e/options_removed_enable_sourcemap`); + w(node, 'options_removed_enable_sourcemap', `The \`enableSourcemap\` option has been removed. Source maps are always generated now, and tooling can choose to ignore them\nhttps://svelte.dev/e/options_removed_enable_sourcemap`); } /** @@ -563,7 +563,7 @@ export function options_removed_enable_sourcemap(node) { * @param {null | NodeLike} node */ export function options_removed_hydratable(node) { - w(node, "options_removed_hydratable", `The \`hydratable\` option has been removed. Svelte components are always hydratable now\nhttps://svelte.dev/e/options_removed_hydratable`); + w(node, 'options_removed_hydratable', `The \`hydratable\` option has been removed. Svelte components are always hydratable now\nhttps://svelte.dev/e/options_removed_hydratable`); } /** @@ -571,7 +571,7 @@ export function options_removed_hydratable(node) { * @param {null | NodeLike} node */ export function options_removed_loop_guard_timeout(node) { - w(node, "options_removed_loop_guard_timeout", `The \`loopGuardTimeout\` option has been removed\nhttps://svelte.dev/e/options_removed_loop_guard_timeout`); + w(node, 'options_removed_loop_guard_timeout', `The \`loopGuardTimeout\` option has been removed\nhttps://svelte.dev/e/options_removed_loop_guard_timeout`); } /** @@ -579,7 +579,7 @@ export function options_removed_loop_guard_timeout(node) { * @param {null | NodeLike} node */ export function options_renamed_ssr_dom(node) { - w(node, "options_renamed_ssr_dom", `\`generate: "dom"\` and \`generate: "ssr"\` options have been renamed to "client" and "server" respectively\nhttps://svelte.dev/e/options_renamed_ssr_dom`); + w(node, 'options_renamed_ssr_dom', `\`generate: "dom"\` and \`generate: "ssr"\` options have been renamed to "client" and "server" respectively\nhttps://svelte.dev/e/options_renamed_ssr_dom`); } /** @@ -588,7 +588,7 @@ export function options_renamed_ssr_dom(node) { * @param {string} name */ export function export_let_unused(node, name) { - w(node, "export_let_unused", `Component has unused export property '${name}'. If it is for external reference only, please consider using \`export const ${name}\`\nhttps://svelte.dev/e/export_let_unused`); + w(node, 'export_let_unused', `Component has unused export property '${name}'. If it is for external reference only, please consider using \`export const ${name}\`\nhttps://svelte.dev/e/export_let_unused`); } /** @@ -596,7 +596,7 @@ export function export_let_unused(node, name) { * @param {null | NodeLike} node */ export function legacy_component_creation(node) { - w(node, "legacy_component_creation", `Svelte 5 components are no longer classes. Instantiate them using \`mount\` or \`hydrate\` (imported from 'svelte') instead.\nhttps://svelte.dev/e/legacy_component_creation`); + w(node, 'legacy_component_creation', `Svelte 5 components are no longer classes. Instantiate them using \`mount\` or \`hydrate\` (imported from 'svelte') instead.\nhttps://svelte.dev/e/legacy_component_creation`); } /** @@ -605,7 +605,7 @@ export function legacy_component_creation(node) { * @param {string} name */ export function non_reactive_update(node, name) { - w(node, "non_reactive_update", `\`${name}\` is updated, but is not declared with \`$state(...)\`. Changing its value will not correctly trigger updates\nhttps://svelte.dev/e/non_reactive_update`); + w(node, 'non_reactive_update', `\`${name}\` is updated, but is not declared with \`$state(...)\`. Changing its value will not correctly trigger updates\nhttps://svelte.dev/e/non_reactive_update`); } /** @@ -613,7 +613,7 @@ export function non_reactive_update(node, name) { * @param {null | NodeLike} node */ export function perf_avoid_inline_class(node) { - w(node, "perf_avoid_inline_class", `Avoid 'new class' — instead, declare the class at the top level scope\nhttps://svelte.dev/e/perf_avoid_inline_class`); + w(node, 'perf_avoid_inline_class', `Avoid 'new class' — instead, declare the class at the top level scope\nhttps://svelte.dev/e/perf_avoid_inline_class`); } /** @@ -621,7 +621,7 @@ export function perf_avoid_inline_class(node) { * @param {null | NodeLike} node */ export function perf_avoid_nested_class(node) { - w(node, "perf_avoid_nested_class", `Avoid declaring classes below the top level scope\nhttps://svelte.dev/e/perf_avoid_nested_class`); + w(node, 'perf_avoid_nested_class', `Avoid declaring classes below the top level scope\nhttps://svelte.dev/e/perf_avoid_nested_class`); } /** @@ -629,7 +629,7 @@ export function perf_avoid_nested_class(node) { * @param {null | NodeLike} node */ export function reactive_declaration_invalid_placement(node) { - w(node, "reactive_declaration_invalid_placement", `Reactive declarations only exist at the top level of the instance script\nhttps://svelte.dev/e/reactive_declaration_invalid_placement`); + w(node, 'reactive_declaration_invalid_placement', `Reactive declarations only exist at the top level of the instance script\nhttps://svelte.dev/e/reactive_declaration_invalid_placement`); } /** @@ -637,7 +637,7 @@ export function reactive_declaration_invalid_placement(node) { * @param {null | NodeLike} node */ export function reactive_declaration_module_script_dependency(node) { - w(node, "reactive_declaration_module_script_dependency", `Reassignments of module-level declarations will not cause reactive statements to update\nhttps://svelte.dev/e/reactive_declaration_module_script_dependency`); + w(node, 'reactive_declaration_module_script_dependency', `Reassignments of module-level declarations will not cause reactive statements to update\nhttps://svelte.dev/e/reactive_declaration_module_script_dependency`); } /** @@ -645,7 +645,7 @@ export function reactive_declaration_module_script_dependency(node) { * @param {null | NodeLike} node */ export function state_referenced_locally(node) { - w(node, "state_referenced_locally", `State referenced in its own scope will never update. Did you mean to reference it inside a closure?\nhttps://svelte.dev/e/state_referenced_locally`); + w(node, 'state_referenced_locally', `State referenced in its own scope will never update. Did you mean to reference it inside a closure?\nhttps://svelte.dev/e/state_referenced_locally`); } /** @@ -654,7 +654,7 @@ export function state_referenced_locally(node) { * @param {string} name */ export function store_rune_conflict(node, name) { - w(node, "store_rune_conflict", `It looks like you're using the \`$${name}\` rune, but there is a local binding called \`${name}\`. Referencing a local variable with a \`$\` prefix will create a store subscription. Please rename \`${name}\` to avoid the ambiguity\nhttps://svelte.dev/e/store_rune_conflict`); + w(node, 'store_rune_conflict', `It looks like you're using the \`$${name}\` rune, but there is a local binding called \`${name}\`. Referencing a local variable with a \`$\` prefix will create a store subscription. Please rename \`${name}\` to avoid the ambiguity\nhttps://svelte.dev/e/store_rune_conflict`); } /** @@ -663,7 +663,7 @@ export function store_rune_conflict(node, name) { * @param {string} name */ export function css_unused_selector(node, name) { - w(node, "css_unused_selector", `Unused CSS selector "${name}"\nhttps://svelte.dev/e/css_unused_selector`); + w(node, 'css_unused_selector', `Unused CSS selector "${name}"\nhttps://svelte.dev/e/css_unused_selector`); } /** @@ -671,7 +671,7 @@ export function css_unused_selector(node, name) { * @param {null | NodeLike} node */ export function attribute_avoid_is(node) { - w(node, "attribute_avoid_is", `The "is" attribute is not supported cross-browser and should be avoided\nhttps://svelte.dev/e/attribute_avoid_is`); + w(node, 'attribute_avoid_is', `The "is" attribute is not supported cross-browser and should be avoided\nhttps://svelte.dev/e/attribute_avoid_is`); } /** @@ -680,7 +680,7 @@ export function attribute_avoid_is(node) { * @param {string} name */ export function attribute_global_event_reference(node, name) { - w(node, "attribute_global_event_reference", `You are referencing \`globalThis.${name}\`. Did you forget to declare a variable with that name?\nhttps://svelte.dev/e/attribute_global_event_reference`); + w(node, 'attribute_global_event_reference', `You are referencing \`globalThis.${name}\`. Did you forget to declare a variable with that name?\nhttps://svelte.dev/e/attribute_global_event_reference`); } /** @@ -688,7 +688,7 @@ export function attribute_global_event_reference(node, name) { * @param {null | NodeLike} node */ export function attribute_illegal_colon(node) { - w(node, "attribute_illegal_colon", `Attributes should not contain ':' characters to prevent ambiguity with Svelte directives\nhttps://svelte.dev/e/attribute_illegal_colon`); + w(node, 'attribute_illegal_colon', `Attributes should not contain ':' characters to prevent ambiguity with Svelte directives\nhttps://svelte.dev/e/attribute_illegal_colon`); } /** @@ -698,7 +698,7 @@ export function attribute_illegal_colon(node) { * @param {string} right */ export function attribute_invalid_property_name(node, wrong, right) { - w(node, "attribute_invalid_property_name", `'${wrong}' is not a valid HTML attribute. Did you mean '${right}'?\nhttps://svelte.dev/e/attribute_invalid_property_name`); + w(node, 'attribute_invalid_property_name', `'${wrong}' is not a valid HTML attribute. Did you mean '${right}'?\nhttps://svelte.dev/e/attribute_invalid_property_name`); } /** @@ -706,7 +706,7 @@ export function attribute_invalid_property_name(node, wrong, right) { * @param {null | NodeLike} node */ export function attribute_quoted(node) { - w(node, "attribute_quoted", `Quoted attributes on components and custom elements will be stringified in a future version of Svelte. If this isn't what you want, remove the quotes\nhttps://svelte.dev/e/attribute_quoted`); + w(node, 'attribute_quoted', `Quoted attributes on components and custom elements will be stringified in a future version of Svelte. If this isn't what you want, remove the quotes\nhttps://svelte.dev/e/attribute_quoted`); } /** @@ -715,7 +715,7 @@ export function attribute_quoted(node) { * @param {string} name */ export function bind_invalid_each_rest(node, name) { - w(node, "bind_invalid_each_rest", `The rest operator (...) will create a new object and binding '${name}' with the original object will not work\nhttps://svelte.dev/e/bind_invalid_each_rest`); + w(node, 'bind_invalid_each_rest', `The rest operator (...) will create a new object and binding '${name}' with the original object will not work\nhttps://svelte.dev/e/bind_invalid_each_rest`); } /** @@ -723,7 +723,7 @@ export function bind_invalid_each_rest(node, name) { * @param {null | NodeLike} node */ export function block_empty(node) { - w(node, "block_empty", `Empty block\nhttps://svelte.dev/e/block_empty`); + w(node, 'block_empty', `Empty block\nhttps://svelte.dev/e/block_empty`); } /** @@ -732,7 +732,7 @@ export function block_empty(node) { * @param {string} name */ export function component_name_lowercase(node, name) { - w(node, "component_name_lowercase", `\`<${name}>\` will be treated as an HTML element unless it begins with a capital letter\nhttps://svelte.dev/e/component_name_lowercase`); + w(node, 'component_name_lowercase', `\`<${name}>\` will be treated as an HTML element unless it begins with a capital letter\nhttps://svelte.dev/e/component_name_lowercase`); } /** @@ -741,7 +741,7 @@ export function component_name_lowercase(node, name) { * @param {string} name */ export function element_invalid_self_closing_tag(node, name) { - w(node, "element_invalid_self_closing_tag", `Self-closing HTML tags for non-void elements are ambiguous — use \`<${name} ...></${name}>\` rather than \`<${name} ... />\`\nhttps://svelte.dev/e/element_invalid_self_closing_tag`); + w(node, 'element_invalid_self_closing_tag', `Self-closing HTML tags for non-void elements are ambiguous — use \`<${name} ...></${name}>\` rather than \`<${name} ... />\`\nhttps://svelte.dev/e/element_invalid_self_closing_tag`); } /** @@ -750,7 +750,7 @@ export function element_invalid_self_closing_tag(node, name) { * @param {string} name */ export function event_directive_deprecated(node, name) { - w(node, "event_directive_deprecated", `Using \`on:${name}\` to listen to the ${name} event is deprecated. Use the event attribute \`on${name}\` instead\nhttps://svelte.dev/e/event_directive_deprecated`); + w(node, 'event_directive_deprecated', `Using \`on:${name}\` to listen to the ${name} event is deprecated. Use the event attribute \`on${name}\` instead\nhttps://svelte.dev/e/event_directive_deprecated`); } /** @@ -759,7 +759,7 @@ export function event_directive_deprecated(node, name) { * @param {string} message */ export function node_invalid_placement_ssr(node, message) { - w(node, "node_invalid_placement_ssr", `${message}. When rendering this component on the server, the resulting HTML will be modified by the browser (by moving, removing, or inserting elements), likely resulting in a \`hydration_mismatch\` warning\nhttps://svelte.dev/e/node_invalid_placement_ssr`); + w(node, 'node_invalid_placement_ssr', `${message}. When rendering this component on the server, the resulting HTML will be modified by the browser (by moving, removing, or inserting elements), likely resulting in a \`hydration_mismatch\` warning\nhttps://svelte.dev/e/node_invalid_placement_ssr`); } /** @@ -767,7 +767,7 @@ export function node_invalid_placement_ssr(node, message) { * @param {null | NodeLike} node */ export function script_context_deprecated(node) { - w(node, "script_context_deprecated", `\`context="module"\` is deprecated, use the \`module\` attribute instead\nhttps://svelte.dev/e/script_context_deprecated`); + w(node, 'script_context_deprecated', `\`context="module"\` is deprecated, use the \`module\` attribute instead\nhttps://svelte.dev/e/script_context_deprecated`); } /** @@ -775,7 +775,7 @@ export function script_context_deprecated(node) { * @param {null | NodeLike} node */ export function script_unknown_attribute(node) { - w(node, "script_unknown_attribute", `Unrecognized attribute — should be one of \`generics\`, \`lang\` or \`module\`. If this exists for a preprocessor, ensure that the preprocessor removes it\nhttps://svelte.dev/e/script_unknown_attribute`); + w(node, 'script_unknown_attribute', `Unrecognized attribute — should be one of \`generics\`, \`lang\` or \`module\`. If this exists for a preprocessor, ensure that the preprocessor removes it\nhttps://svelte.dev/e/script_unknown_attribute`); } /** @@ -783,7 +783,7 @@ export function script_unknown_attribute(node) { * @param {null | NodeLike} node */ export function slot_element_deprecated(node) { - w(node, "slot_element_deprecated", `Using \`<slot>\` to render parent content is deprecated. Use \`{@render ...}\` tags instead\nhttps://svelte.dev/e/slot_element_deprecated`); + w(node, 'slot_element_deprecated', `Using \`<slot>\` to render parent content is deprecated. Use \`{@render ...}\` tags instead\nhttps://svelte.dev/e/slot_element_deprecated`); } /** @@ -791,7 +791,7 @@ export function slot_element_deprecated(node) { * @param {null | NodeLike} node */ export function svelte_component_deprecated(node) { - w(node, "svelte_component_deprecated", `\`<svelte:component>\` is deprecated in runes mode — components are dynamic by default\nhttps://svelte.dev/e/svelte_component_deprecated`); + w(node, 'svelte_component_deprecated', `\`<svelte:component>\` is deprecated in runes mode — components are dynamic by default\nhttps://svelte.dev/e/svelte_component_deprecated`); } /** @@ -799,7 +799,7 @@ export function svelte_component_deprecated(node) { * @param {null | NodeLike} node */ export function svelte_element_invalid_this(node) { - w(node, "svelte_element_invalid_this", `\`this\` should be an \`{expression}\`. Using a string attribute value will cause an error in future versions of Svelte\nhttps://svelte.dev/e/svelte_element_invalid_this`); + w(node, 'svelte_element_invalid_this', `\`this\` should be an \`{expression}\`. Using a string attribute value will cause an error in future versions of Svelte\nhttps://svelte.dev/e/svelte_element_invalid_this`); } /** @@ -809,5 +809,5 @@ export function svelte_element_invalid_this(node) { * @param {string} basename */ export function svelte_self_deprecated(node, name, basename) { - w(node, "svelte_self_deprecated", `\`<svelte:self>\` is deprecated — use self-imports (e.g. \`import ${name} from './${basename}'\`) instead\nhttps://svelte.dev/e/svelte_self_deprecated`); + w(node, 'svelte_self_deprecated', `\`<svelte:self>\` is deprecated — use self-imports (e.g. \`import ${name} from './${basename}'\`) instead\nhttps://svelte.dev/e/svelte_self_deprecated`); } \ No newline at end of file diff --git a/packages/svelte/src/internal/client/warnings.js b/packages/svelte/src/internal/client/warnings.js index 78d457f48f..250c6eca2f 100644 --- a/packages/svelte/src/internal/client/warnings.js +++ b/packages/svelte/src/internal/client/warnings.js @@ -76,7 +76,7 @@ export function hydration_attribute_changed(attribute, html, value) { */ export function hydration_html_changed(location) { if (DEV) { - console.warn(`%c[svelte] hydration_html_changed\n%c${location ? `The value of an \`{@html ...}\` block ${location} changed between server and client renders. The client value will be ignored in favour of the server value` : "The value of an `{@html ...}` block changed between server and client renders. The client value will be ignored in favour of the server value"}\nhttps://svelte.dev/e/hydration_html_changed`, bold, normal); + console.warn(`%c[svelte] hydration_html_changed\n%c${location ? `The value of an \`{@html ...}\` block ${location} changed between server and client renders. The client value will be ignored in favour of the server value` : 'The value of an `{@html ...}` block changed between server and client renders. The client value will be ignored in favour of the server value'}\nhttps://svelte.dev/e/hydration_html_changed`, bold, normal); } else { console.warn(`https://svelte.dev/e/hydration_html_changed`); } @@ -88,7 +88,7 @@ export function hydration_html_changed(location) { */ export function hydration_mismatch(location) { if (DEV) { - console.warn(`%c[svelte] hydration_mismatch\n%c${location ? `Hydration failed because the initial UI does not match what was rendered on the server. The error occurred near ${location}` : "Hydration failed because the initial UI does not match what was rendered on the server"}\nhttps://svelte.dev/e/hydration_mismatch`, bold, normal); + console.warn(`%c[svelte] hydration_mismatch\n%c${location ? `Hydration failed because the initial UI does not match what was rendered on the server. The error occurred near ${location}` : 'Hydration failed because the initial UI does not match what was rendered on the server'}\nhttps://svelte.dev/e/hydration_mismatch`, bold, normal); } else { console.warn(`https://svelte.dev/e/hydration_mismatch`); } @@ -149,7 +149,7 @@ export function ownership_invalid_binding(parent, child, owner) { */ export function ownership_invalid_mutation(component, owner) { if (DEV) { - console.warn(`%c[svelte] ownership_invalid_mutation\n%c${component ? `${component} mutated a value owned by ${owner}. This is strongly discouraged. Consider passing values to child components with \`bind:\`, or use a callback instead` : "Mutating a value outside the component that created it is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead"}\nhttps://svelte.dev/e/ownership_invalid_mutation`, bold, normal); + console.warn(`%c[svelte] ownership_invalid_mutation\n%c${component ? `${component} mutated a value owned by ${owner}. This is strongly discouraged. Consider passing values to child components with \`bind:\`, or use a callback instead` : 'Mutating a value outside the component that created it is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead'}\nhttps://svelte.dev/e/ownership_invalid_mutation`, bold, normal); } else { console.warn(`https://svelte.dev/e/ownership_invalid_mutation`); } diff --git a/packages/svelte/src/internal/shared/warnings.js b/packages/svelte/src/internal/shared/warnings.js index 83c58c9b14..281be08382 100644 --- a/packages/svelte/src/internal/shared/warnings.js +++ b/packages/svelte/src/internal/shared/warnings.js @@ -29,7 +29,7 @@ export function state_snapshot_uncloneable(properties) { ? `The following properties cannot be cloned with \`$state.snapshot\` — the return value contains the originals: ${properties}` - : "Value cannot be cloned with `$state.snapshot` — the original value was returned"}\nhttps://svelte.dev/e/state_snapshot_uncloneable`, bold, normal); + : 'Value cannot be cloned with `$state.snapshot` — the original value was returned'}\nhttps://svelte.dev/e/state_snapshot_uncloneable`, bold, normal); } else { console.warn(`https://svelte.dev/e/state_snapshot_uncloneable`); } diff --git a/packages/svelte/tests/snapshot/samples/await-block-scope/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/await-block-scope/_expected/client/index.svelte.js index 87fce120fd..3e5a12ed9d 100644 --- a/packages/svelte/tests/snapshot/samples/await-block-scope/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/await-block-scope/_expected/client/index.svelte.js @@ -1,5 +1,5 @@ -import "svelte/internal/disclose-version"; -import * as $ from "svelte/internal/client"; +import 'svelte/internal/disclose-version'; +import * as $ from 'svelte/internal/client'; function increment(_, counter) { counter.count += 1; @@ -26,11 +26,11 @@ export default function Await_block_scope($$anchor) { var text_1 = $.sibling(node); $.template_effect(() => { - $.set_text(text, `clicks: ${counter.count ?? ""}`); - $.set_text(text_1, ` ${counter.count ?? ""}`); + $.set_text(text, `clicks: ${counter.count ?? ''}`); + $.set_text(text_1, ` ${counter.count ?? ''}`); }); $.append($$anchor, fragment); } -$.delegate(["click"]); \ No newline at end of file +$.delegate(['click']); \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/await-block-scope/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/await-block-scope/_expected/server/index.svelte.js index 44c68a7c96..012789a550 100644 --- a/packages/svelte/tests/snapshot/samples/await-block-scope/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/await-block-scope/_expected/server/index.svelte.js @@ -1,4 +1,4 @@ -import * as $ from "svelte/internal/server"; +import * as $ from 'svelte/internal/server'; export default function Await_block_scope($$payload) { let counter = { count: 0 }; diff --git a/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client/index.svelte.js index bcddb6f658..fa990b33ee 100644 --- a/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client/index.svelte.js @@ -1,11 +1,11 @@ -import "svelte/internal/disclose-version"; -import * as $ from "svelte/internal/client"; +import 'svelte/internal/disclose-version'; +import * as $ from 'svelte/internal/client'; import TextInput from './Child.svelte'; const snippet = ($$anchor) => { $.next(); - var text = $.text("Something"); + var text = $.text('Something'); $.append($$anchor, text); }; @@ -29,6 +29,6 @@ export default function Bind_component_snippet($$anchor) { var text_1 = $.sibling(node); - $.template_effect(() => $.set_text(text_1, ` value: ${$.get(value) ?? ""}`)); + $.template_effect(() => $.set_text(text_1, ` value: ${$.get(value) ?? ''}`)); $.append($$anchor, fragment); } \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/server/index.svelte.js index d223a31502..c091179c41 100644 --- a/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/server/index.svelte.js @@ -1,4 +1,4 @@ -import * as $ from "svelte/internal/server"; +import * as $ from 'svelte/internal/server'; import TextInput from './Child.svelte'; function snippet($$payload) { diff --git a/packages/svelte/tests/snapshot/samples/bind-this/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/bind-this/_expected/client/index.svelte.js index fedcc87696..dfd32a04e5 100644 --- a/packages/svelte/tests/snapshot/samples/bind-this/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/bind-this/_expected/client/index.svelte.js @@ -1,6 +1,6 @@ -import "svelte/internal/disclose-version"; -import "svelte/internal/flags/legacy"; -import * as $ from "svelte/internal/client"; +import 'svelte/internal/disclose-version'; +import 'svelte/internal/flags/legacy'; +import * as $ from 'svelte/internal/client'; export default function Bind_this($$anchor) { $.bind_this(Foo($$anchor, { $$legacy: true }), ($$value) => foo = $$value, () => foo); diff --git a/packages/svelte/tests/snapshot/samples/bind-this/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/bind-this/_expected/server/index.svelte.js index badca8d4a0..148573766f 100644 --- a/packages/svelte/tests/snapshot/samples/bind-this/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/bind-this/_expected/server/index.svelte.js @@ -1,4 +1,4 @@ -import * as $ from "svelte/internal/server"; +import * as $ from 'svelte/internal/server'; export default function Bind_this($$payload) { Foo($$payload, {}); diff --git a/packages/svelte/tests/snapshot/samples/class-state-field-constructor-assignment/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/class-state-field-constructor-assignment/_expected/client/index.svelte.js index 399fa19b62..2898f31a6f 100644 --- a/packages/svelte/tests/snapshot/samples/class-state-field-constructor-assignment/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/class-state-field-constructor-assignment/_expected/client/index.svelte.js @@ -1,5 +1,5 @@ -import "svelte/internal/disclose-version"; -import * as $ from "svelte/internal/client"; +import 'svelte/internal/disclose-version'; +import * as $ from 'svelte/internal/client'; export default function Class_state_field_constructor_assignment($$anchor, $$props) { $.push($$props, true); diff --git a/packages/svelte/tests/snapshot/samples/class-state-field-constructor-assignment/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/class-state-field-constructor-assignment/_expected/server/index.svelte.js index bcc7c2e1f2..2a115a4983 100644 --- a/packages/svelte/tests/snapshot/samples/class-state-field-constructor-assignment/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/class-state-field-constructor-assignment/_expected/server/index.svelte.js @@ -1,4 +1,4 @@ -import * as $ from "svelte/internal/server"; +import * as $ from 'svelte/internal/server'; export default function Class_state_field_constructor_assignment($$payload, $$props) { $.push(); diff --git a/packages/svelte/tests/snapshot/samples/destructured-assignments/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/destructured-assignments/_expected/client/index.svelte.js index dbda825c4d..9651713c52 100644 --- a/packages/svelte/tests/snapshot/samples/destructured-assignments/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/destructured-assignments/_expected/client/index.svelte.js @@ -1,5 +1,5 @@ /* index.svelte.js generated by Svelte VERSION */ -import * as $ from "svelte/internal/client"; +import * as $ from 'svelte/internal/client'; let a = $.state(1); let b = $.state(2); diff --git a/packages/svelte/tests/snapshot/samples/destructured-assignments/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/destructured-assignments/_expected/server/index.svelte.js index 2797d4312b..62b655b266 100644 --- a/packages/svelte/tests/snapshot/samples/destructured-assignments/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/destructured-assignments/_expected/server/index.svelte.js @@ -1,5 +1,5 @@ /* index.svelte.js generated by Svelte VERSION */ -import * as $ from "svelte/internal/server"; +import * as $ from 'svelte/internal/server'; let a = 1; let b = 2; diff --git a/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js b/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js index 846acc67a6..ce77a27e19 100644 --- a/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js +++ b/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js @@ -1,5 +1,5 @@ -import "svelte/internal/disclose-version"; -import * as $ from "svelte/internal/client"; +import 'svelte/internal/disclose-version'; +import * as $ from 'svelte/internal/client'; var root = $.template(`<div></div> <svg></svg> <custom-element></custom-element> <div></div> <svg></svg> <custom-element></custom-element>`, 3); @@ -13,20 +13,20 @@ export default function Main($$anchor) { var custom_element = $.sibling(svg, 2); var div_1 = $.sibling(custom_element, 2); - $.template_effect(() => $.set_attribute(div_1, "foobar", y())); + $.template_effect(() => $.set_attribute(div_1, 'foobar', y())); var svg_1 = $.sibling(div_1, 2); - $.template_effect(() => $.set_attribute(svg_1, "viewBox", y())); + $.template_effect(() => $.set_attribute(svg_1, 'viewBox', y())); var custom_element_1 = $.sibling(svg_1, 2); - $.template_effect(() => $.set_custom_element_data(custom_element_1, "fooBar", y())); + $.template_effect(() => $.set_custom_element_data(custom_element_1, 'fooBar', y())); $.template_effect(() => { - $.set_attribute(div, "foobar", x); - $.set_attribute(svg, "viewBox", x); - $.set_custom_element_data(custom_element, "fooBar", x); + $.set_attribute(div, 'foobar', x); + $.set_attribute(svg, 'viewBox', x); + $.set_custom_element_data(custom_element, 'fooBar', x); }); $.append($$anchor, fragment); diff --git a/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/server/main.svelte.js b/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/server/main.svelte.js index 5eaa55aa49..4ea5edb6a0 100644 --- a/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/server/main.svelte.js +++ b/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/server/main.svelte.js @@ -1,9 +1,9 @@ -import * as $ from "svelte/internal/server"; +import * as $ from 'svelte/internal/server'; export default function Main($$payload) { // needs to be a snapshot test because jsdom does auto-correct the attribute casing let x = 'test'; let y = () => 'test'; - $$payload.out += `<div${$.attr("foobar", x)}></div> <svg${$.attr("viewBox", x)}></svg> <custom-element${$.attr("foobar", x)}></custom-element> <div${$.attr("foobar", y())}></div> <svg${$.attr("viewBox", y())}></svg> <custom-element${$.attr("foobar", y())}></custom-element>`; + $$payload.out += `<div${$.attr('foobar', x)}></div> <svg${$.attr('viewBox', x)}></svg> <custom-element${$.attr('foobar', x)}></custom-element> <div${$.attr('foobar', y())}></div> <svg${$.attr('viewBox', y())}></svg> <custom-element${$.attr('foobar', y())}></custom-element>`; } \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js index 80f2da11a2..c0626bd416 100644 --- a/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js @@ -1,6 +1,6 @@ -import "svelte/internal/disclose-version"; -import "svelte/internal/flags/legacy"; -import * as $ from "svelte/internal/client"; +import 'svelte/internal/disclose-version'; +import 'svelte/internal/flags/legacy'; +import * as $ from 'svelte/internal/client'; export default function Each_string_template($$anchor) { var fragment = $.comment(); @@ -11,7 +11,7 @@ export default function Each_string_template($$anchor) { var text = $.text(); - $.template_effect(() => $.set_text(text, `${thing ?? ""}, `)); + $.template_effect(() => $.set_text(text, `${thing ?? ''}, `)); $.append($$anchor, text); }); diff --git a/packages/svelte/tests/snapshot/samples/each-string-template/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/each-string-template/_expected/server/index.svelte.js index d4debe1727..4386c22ebe 100644 --- a/packages/svelte/tests/snapshot/samples/each-string-template/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/each-string-template/_expected/server/index.svelte.js @@ -1,4 +1,4 @@ -import * as $ from "svelte/internal/server"; +import * as $ from 'svelte/internal/server'; export default function Each_string_template($$payload) { const each_array = $.ensure_array_like(['foo', 'bar', 'baz']); diff --git a/packages/svelte/tests/snapshot/samples/export-state/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/export-state/_expected/client/index.svelte.js index bab47c8c50..c2a6054bc6 100644 --- a/packages/svelte/tests/snapshot/samples/export-state/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/export-state/_expected/client/index.svelte.js @@ -1,4 +1,4 @@ /* index.svelte.js generated by Svelte VERSION */ -import * as $ from "svelte/internal/client"; +import * as $ from 'svelte/internal/client'; export const object = $.proxy({ ok: true }); \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/export-state/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/export-state/_expected/server/index.svelte.js index a3b619df6e..1f6c244212 100644 --- a/packages/svelte/tests/snapshot/samples/export-state/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/export-state/_expected/server/index.svelte.js @@ -1,4 +1,4 @@ /* index.svelte.js generated by Svelte VERSION */ -import * as $ from "svelte/internal/server"; +import * as $ from 'svelte/internal/server'; export const object = { ok: true }; \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/client/index.svelte.js index 95d1c72017..c545608bca 100644 --- a/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/client/index.svelte.js @@ -1,5 +1,5 @@ -import "svelte/internal/disclose-version"; -import * as $ from "svelte/internal/client"; +import 'svelte/internal/disclose-version'; +import * as $ from 'svelte/internal/client'; export default function Function_prop_no_getter($$anchor) { let count = $.state(0); @@ -19,7 +19,7 @@ export default function Function_prop_no_getter($$anchor) { var text = $.text(); - $.template_effect(() => $.set_text(text, `clicks: ${$.get(count) ?? ""}`)); + $.template_effect(() => $.set_text(text, `clicks: ${$.get(count) ?? ''}`)); $.append($$anchor, text); }, $$slots: { default: true } diff --git a/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/server/index.svelte.js index 05b343d821..88f6f55ee7 100644 --- a/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/server/index.svelte.js @@ -1,4 +1,4 @@ -import * as $ from "svelte/internal/server"; +import * as $ from 'svelte/internal/server'; export default function Function_prop_no_getter($$payload) { let count = 0; diff --git a/packages/svelte/tests/snapshot/samples/hello-world/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/hello-world/_expected/client/index.svelte.js index 9f6f291669..899c126001 100644 --- a/packages/svelte/tests/snapshot/samples/hello-world/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/hello-world/_expected/client/index.svelte.js @@ -1,6 +1,6 @@ -import "svelte/internal/disclose-version"; -import "svelte/internal/flags/legacy"; -import * as $ from "svelte/internal/client"; +import 'svelte/internal/disclose-version'; +import 'svelte/internal/flags/legacy'; +import * as $ from 'svelte/internal/client'; var root = $.template(`<h1>hello world</h1>`); diff --git a/packages/svelte/tests/snapshot/samples/hello-world/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/hello-world/_expected/server/index.svelte.js index a313799dfd..8766fb1300 100644 --- a/packages/svelte/tests/snapshot/samples/hello-world/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/hello-world/_expected/server/index.svelte.js @@ -1,4 +1,4 @@ -import * as $ from "svelte/internal/server"; +import * as $ from 'svelte/internal/server'; export default function Hello_world($$payload) { $$payload.out += `<h1>hello world</h1>`; diff --git a/packages/svelte/tests/snapshot/samples/hmr/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/hmr/_expected/client/index.svelte.js index 86c2880abc..3c8322500b 100644 --- a/packages/svelte/tests/snapshot/samples/hmr/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/hmr/_expected/client/index.svelte.js @@ -1,6 +1,6 @@ -import "svelte/internal/disclose-version"; -import "svelte/internal/flags/legacy"; -import * as $ from "svelte/internal/client"; +import 'svelte/internal/disclose-version'; +import 'svelte/internal/flags/legacy'; +import * as $ from 'svelte/internal/client'; var root = $.template(`<h1>hello world</h1>`); diff --git a/packages/svelte/tests/snapshot/samples/hmr/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/hmr/_expected/server/index.svelte.js index 33fe307c09..959e0a403e 100644 --- a/packages/svelte/tests/snapshot/samples/hmr/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/hmr/_expected/server/index.svelte.js @@ -1,4 +1,4 @@ -import * as $ from "svelte/internal/server"; +import * as $ from 'svelte/internal/server'; export default function Hmr($$payload) { $$payload.out += `<h1>hello world</h1>`; diff --git a/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/client/index.svelte.js index 9c7d2f3f23..ebbe191dcb 100644 --- a/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/client/index.svelte.js @@ -1,6 +1,6 @@ -import "svelte/internal/disclose-version"; -import "svelte/internal/flags/legacy"; -import * as $ from "svelte/internal/client"; +import 'svelte/internal/disclose-version'; +import 'svelte/internal/flags/legacy'; +import * as $ from 'svelte/internal/client'; import { random } from './module.svelte'; export default function Imports_in_modules($$anchor) { diff --git a/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/client/module.svelte.js b/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/client/module.svelte.js index 6edbc8af77..0d366e6258 100644 --- a/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/client/module.svelte.js +++ b/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/client/module.svelte.js @@ -1,5 +1,5 @@ /* module.svelte.js generated by Svelte VERSION */ -import * as $ from "svelte/internal/client"; +import * as $ from 'svelte/internal/client'; import { random } from './export'; export { random }; \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/server/index.svelte.js index 35b64b4186..4cd6bc59d7 100644 --- a/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/server/index.svelte.js @@ -1,4 +1,4 @@ -import * as $ from "svelte/internal/server"; +import * as $ from 'svelte/internal/server'; import { random } from './module.svelte'; export default function Imports_in_modules($$payload) { diff --git a/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/server/module.svelte.js b/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/server/module.svelte.js index e51aae5a25..2e0af8af84 100644 --- a/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/server/module.svelte.js +++ b/packages/svelte/tests/snapshot/samples/imports-in-modules/_expected/server/module.svelte.js @@ -1,5 +1,5 @@ /* module.svelte.js generated by Svelte VERSION */ -import * as $ from "svelte/internal/server"; +import * as $ from 'svelte/internal/server'; import { random } from './export'; export { random }; \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/props-identifier/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/props-identifier/_expected/client/index.svelte.js index 2a10dbc1b1..5a46b9bbef 100644 --- a/packages/svelte/tests/snapshot/samples/props-identifier/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/props-identifier/_expected/client/index.svelte.js @@ -1,10 +1,10 @@ -import "svelte/internal/disclose-version"; -import * as $ from "svelte/internal/client"; +import 'svelte/internal/disclose-version'; +import * as $ from 'svelte/internal/client'; export default function Props_identifier($$anchor, $$props) { $.push($$props, true); - let props = $.rest_props($$props, ["$$slots", "$$events", "$$legacy"]); + let props = $.rest_props($$props, ['$$slots', '$$events', '$$legacy']); $$props.a; props[a]; diff --git a/packages/svelte/tests/snapshot/samples/props-identifier/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/props-identifier/_expected/server/index.svelte.js index 6fef87d63b..33a3633939 100644 --- a/packages/svelte/tests/snapshot/samples/props-identifier/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/props-identifier/_expected/server/index.svelte.js @@ -1,4 +1,4 @@ -import * as $ from "svelte/internal/server"; +import * as $ from 'svelte/internal/server'; export default function Props_identifier($$payload, $$props) { $.push(); diff --git a/packages/svelte/tests/snapshot/samples/purity/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/purity/_expected/client/index.svelte.js index 0a627a55ae..940ed8f9e8 100644 --- a/packages/svelte/tests/snapshot/samples/purity/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/purity/_expected/client/index.svelte.js @@ -1,6 +1,6 @@ -import "svelte/internal/disclose-version"; -import "svelte/internal/flags/legacy"; -import * as $ from "svelte/internal/client"; +import 'svelte/internal/disclose-version'; +import 'svelte/internal/flags/legacy'; +import * as $ from 'svelte/internal/client'; var root = $.template(`<p></p> <p></p> <!>`, 1); diff --git a/packages/svelte/tests/snapshot/samples/purity/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/purity/_expected/server/index.svelte.js index 1eea71e4dd..588332407a 100644 --- a/packages/svelte/tests/snapshot/samples/purity/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/purity/_expected/server/index.svelte.js @@ -1,4 +1,4 @@ -import * as $ from "svelte/internal/server"; +import * as $ from 'svelte/internal/server'; export default function Purity($$payload) { $$payload.out += `<p>${$.escape(Math.max(0, Math.min(0, 100)))}</p> <p>${$.escape(location.href)}</p> `; diff --git a/packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/client/index.svelte.js index 8dd7df82cf..9b203b97e8 100644 --- a/packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/client/index.svelte.js @@ -1,5 +1,5 @@ -import "svelte/internal/disclose-version"; -import * as $ from "svelte/internal/client"; +import 'svelte/internal/disclose-version'; +import * as $ from 'svelte/internal/client'; var root = $.template(`<header><nav><a href="/">Home</a> <a href="/away">Away</a></nav></header> <main><h1> </h1> <div class="static"><p>we don't need to traverse these nodes</p></div> <p>or</p> <p>these</p> <p>ones</p> <!> <p>these</p> <p>trailing</p> <p>nodes</p> <p>can</p> <p>be</p> <p>completely</p> <p>ignored</p></main> <cant-skip><custom-elements></custom-elements></cant-skip> <div><input></div> <div><source></div> <select><option>a</option></select> <img src="..." alt="" loading="lazy"> <div><img src="..." alt="" loading="lazy"></div>`, 3); @@ -20,7 +20,7 @@ export default function Skip_static_subtree($$anchor, $$props) { var cant_skip = $.sibling(main, 2); var custom_elements = $.child(cant_skip); - $.set_custom_element_data(custom_elements, "with", "attributes"); + $.set_custom_element_data(custom_elements, 'with', 'attributes'); $.reset(cant_skip); var div = $.sibling(cant_skip, 2); @@ -38,7 +38,7 @@ export default function Skip_static_subtree($$anchor, $$props) { var select = $.sibling(div_1, 2); var option = $.child(select); - option.value = null == (option.__value = "a") ? "" : "a"; + option.value = null == (option.__value = 'a') ? '' : 'a'; $.reset(select); var img = $.sibling(select, 2); diff --git a/packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/server/index.svelte.js index 309f5a2b57..e694c12647 100644 --- a/packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/server/index.svelte.js @@ -1,4 +1,4 @@ -import * as $ from "svelte/internal/server"; +import * as $ from 'svelte/internal/server'; export default function Skip_static_subtree($$payload, $$props) { let { title, content } = $$props; diff --git a/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client/index.svelte.js index c24023c8a4..a67210e541 100644 --- a/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client/index.svelte.js @@ -1,5 +1,5 @@ -import "svelte/internal/disclose-version"; -import * as $ from "svelte/internal/client"; +import 'svelte/internal/disclose-version'; +import * as $ from 'svelte/internal/client'; function reset(_, str, tpl) { $.set(str, ''); @@ -30,4 +30,4 @@ export default function State_proxy_literal($$anchor) { $.append($$anchor, fragment); } -$.delegate(["click"]); \ No newline at end of file +$.delegate(['click']); \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/server/index.svelte.js index 3424f807ab..7b2a884d70 100644 --- a/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/server/index.svelte.js @@ -1,4 +1,4 @@ -import * as $ from "svelte/internal/server"; +import * as $ from 'svelte/internal/server'; export default function State_proxy_literal($$payload) { let str = ''; @@ -11,5 +11,5 @@ export default function State_proxy_literal($$payload) { tpl = ``; } - $$payload.out += `<input${$.attr("value", str)}> <input${$.attr("value", tpl)}> <button>reset</button>`; + $$payload.out += `<input${$.attr('value', str)}> <input${$.attr('value', tpl)}> <button>reset</button>`; } \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js index a4bbea582b..2270005ee0 100644 --- a/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js @@ -1,8 +1,8 @@ -import "svelte/internal/disclose-version"; -import * as $ from "svelte/internal/client"; +import 'svelte/internal/disclose-version'; +import * as $ from 'svelte/internal/client'; export default function Svelte_element($$anchor, $$props) { - let tag = $.prop($$props, "tag", 3, 'hr'); + let tag = $.prop($$props, 'tag', 3, 'hr'); var fragment = $.comment(); var node = $.first_child(fragment); diff --git a/packages/svelte/tests/snapshot/samples/svelte-element/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/svelte-element/_expected/server/index.svelte.js index 4a766f7de5..4426ad1164 100644 --- a/packages/svelte/tests/snapshot/samples/svelte-element/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/svelte-element/_expected/server/index.svelte.js @@ -1,4 +1,4 @@ -import * as $ from "svelte/internal/server"; +import * as $ from 'svelte/internal/server'; export default function Svelte_element($$payload, $$props) { let { tag = 'hr' } = $$props; diff --git a/packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/client/index.svelte.js index 8ba14526aa..8e343fcf36 100644 --- a/packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/client/index.svelte.js @@ -1,5 +1,5 @@ -import "svelte/internal/disclose-version"; -import * as $ from "svelte/internal/client"; +import 'svelte/internal/disclose-version'; +import * as $ from 'svelte/internal/client'; var root = $.template(`<p> </p>`); @@ -16,8 +16,8 @@ export default function Text_nodes_deriveds($$anchor) { } var p = root(); - const stringified_text = $.derived(() => text1() ?? ""); - const stringified_text_1 = $.derived(() => text2() ?? ""); + const stringified_text = $.derived(() => text1() ?? ''); + const stringified_text_1 = $.derived(() => text2() ?? ''); var text = $.child(p); $.template_effect(() => $.set_text(text, `${$.get(stringified_text)}${$.get(stringified_text_1)}`)); diff --git a/packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/server/index.svelte.js index f7dc4176e4..6f019647f5 100644 --- a/packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/server/index.svelte.js @@ -1,4 +1,4 @@ -import * as $ from "svelte/internal/server"; +import * as $ from 'svelte/internal/server'; export default function Text_nodes_deriveds($$payload) { let count1 = 0; diff --git a/packages/svelte/tests/sourcemaps/samples/css-injected-map/_config.js b/packages/svelte/tests/sourcemaps/samples/css-injected-map/_config.js index 74a2185076..c2b2fe766a 100644 --- a/packages/svelte/tests/sourcemaps/samples/css-injected-map/_config.js +++ b/packages/svelte/tests/sourcemaps/samples/css-injected-map/_config.js @@ -30,7 +30,7 @@ export default test({ async test({ assert, code_client }) { // Check that the css source map embedded in the js is accurate const match = code_client.match( - /code: "(.*?)(?:\\n\/\*# sourceMappingURL=data:(.*?);charset=(.*?);base64,(.*?) \*\/)?"/ + /code: '(.*?)(?:\\n\/\*# sourceMappingURL=data:(.*?);charset=(.*?);base64,(.*?) \*\/)?'/ ); assert.ok(match); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8bf7bb4224..731bb97edb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -87,8 +87,8 @@ importers: specifier: ^1.2.1 version: 1.2.1 esrap: - specifier: ^1.3.2 - version: 1.3.2 + specifier: ^1.4.2 + version: 1.4.2 is-reference: specifier: ^3.0.3 version: 3.0.3 @@ -1118,8 +1118,8 @@ packages: resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} engines: {node: '>=0.10'} - esrap@1.3.2: - resolution: {integrity: sha512-C4PXusxYhFT98GjLSmb20k9PREuUdporer50dhzGuJu9IJXktbMddVCMLAERl5dAHyAi73GWWCE4FVHGP1794g==} + esrap@1.4.2: + resolution: {integrity: sha512-FhVlJzvTw7ZLxYZ7RyHwQCFE64dkkpzGNNnphaGCLwjqGk1SQcqzbgdx9FowPCktx6NOSHkzvcZ3vsvdH54YXA==} esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} @@ -3324,7 +3324,7 @@ snapshots: dependencies: estraverse: 5.3.0 - esrap@1.3.2: + esrap@1.4.2: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 From ab3290fa870838a1f8c8baddc5d093dfa3265280 Mon Sep 17 00:00:00 2001 From: eyalkutz <45904301+eyalkutz@users.noreply.github.com> Date: Sun, 12 Jan 2025 20:52:27 +0200 Subject: [PATCH 60/63] Remove out-of-date note from CONTRIBUTING.md (#14986) --- CONTRIBUTING.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dd7bbb476e..f7d15f905e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -62,8 +62,6 @@ When [opening a new issue](https://github.com/sveltejs/svelte/issues/new/choose) ## Pull requests -> HEADS UP: Svelte 5 will likely change a lot on the compiler. For that reason, please don't open PRs that are large in scope, touch more than a couple of files etc. In other words, bug fixes are fine, but big feature PRs will likely not be merged. - ### Proposing a change If you would like to request a new feature or enhancement but are not yet thinking about opening a pull request, you can also file an issue with [feature template](https://github.com/sveltejs/svelte/issues/new?template=feature_request.yml). From 36ef59df1f35635d53947b357d4211f3bf1f713a Mon Sep 17 00:00:00 2001 From: Dominic Gannaway <trueadm@users.noreply.github.com> Date: Mon, 13 Jan 2025 21:14:07 +0000 Subject: [PATCH 61/63] chore: improve test cases (#14984) * chore: improve test cases * lint --- .../camel-case-attribute/_config.js | 7 ++-- .../custom-method/_config.js | 4 ++- .../element-effect-context/_config.js | 3 +- .../_config.js | 6 ++-- .../_config.js | 6 ++-- .../_config.js | 6 ++-- .../_config.js | 6 ++-- .../action-custom-event-handler/_config.js | 6 ++-- .../samples/action-this/_config.js | 4 ++- .../samples/await-mutate-array/_config.js | 5 ++- .../await-then-destruct-object-if/_config.js | 3 ++ .../samples/before-render-chain/_config.js | 6 ++-- .../_config.js | 6 ++-- .../binding-contenteditable-text/_config.js | 6 ++-- .../_config.js | 6 ++-- .../binding-select-in-yield/_config.js | 15 +++++---- .../samples/bindings-coalesced/_config.js | 6 ++-- .../component-props-mutated/_config.js | 6 ++-- .../samples/component-slot-let-g/_config.js | 6 ++-- .../samples/destructured-props-2/_config.js | 3 +- .../samples/destructured-props-3/_config.js | 4 ++- .../samples/destructured-props-5/_config.js | 3 +- .../destructuring-assignment-array/_config.js | 7 ++-- .../samples/key-block-expression-2/_config.js | 15 ++++++--- .../samples/prop-const/_config.js | 6 ++-- .../samples/props-reactive-b/_config.js | 9 +++-- .../_config.js | 6 ++-- .../_config.js | 33 +++++++++++-------- .../reactive-value-function/_config.js | 6 ++-- .../reactive-values-text-node/_config.js | 3 ++ .../samples/spread-own-props/_config.js | 6 ++-- .../_config.js | 8 ++--- .../_config.js | 7 ++-- .../samples/store-unreferenced/_config.js | 6 ++-- .../samples/window-event-custom/_config.js | 6 ++-- .../samples/derived-unowned-2/_config.js | 3 +- .../samples/derived-unowned-5/_config.js | 3 +- .../samples/runes-from-func/_config.js | 3 +- 38 files changed, 164 insertions(+), 86 deletions(-) diff --git a/packages/svelte/tests/runtime-browser/custom-elements-samples/camel-case-attribute/_config.js b/packages/svelte/tests/runtime-browser/custom-elements-samples/camel-case-attribute/_config.js index ba3be3c25b..b9bfdd7782 100644 --- a/packages/svelte/tests/runtime-browser/custom-elements-samples/camel-case-attribute/_config.js +++ b/packages/svelte/tests/runtime-browser/custom-elements-samples/camel-case-attribute/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../assert'; const tick = () => Promise.resolve(); @@ -14,8 +15,7 @@ export default test({ el.setAttribute('camel-case', 'universe'); el.setAttribute('an-array', '[3,4]'); el.setAttribute('camelcase2', 'Hi'); - await tick(); - await tick(); + flushSync(); assert.htmlEqual(el.shadowRoot.innerHTML, '<h1>Hi universe!</h1> <p>3</p><p>4</p>'); assert.htmlEqual( target.innerHTML, @@ -25,8 +25,7 @@ export default test({ el.camelCase = 'galaxy'; el.camelCase2 = 'Hey'; el.anArray = [5, 6]; - await tick(); - await tick(); + flushSync(); assert.htmlEqual(el.shadowRoot.innerHTML, '<h1>Hey galaxy!</h1> <p>5</p><p>6</p>'); assert.htmlEqual( target.innerHTML, diff --git a/packages/svelte/tests/runtime-browser/custom-elements-samples/custom-method/_config.js b/packages/svelte/tests/runtime-browser/custom-elements-samples/custom-method/_config.js index dbdf006be5..4314926a94 100644 --- a/packages/svelte/tests/runtime-browser/custom-elements-samples/custom-method/_config.js +++ b/packages/svelte/tests/runtime-browser/custom-elements-samples/custom-method/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../assert'; const tick = () => Promise.resolve(); @@ -8,7 +9,8 @@ export default test({ /** @type {any} */ const el = target.querySelector('custom-element'); - await el.updateFoo(42); + el.updateFoo(42); + flushSync(); const p = el.shadowRoot.querySelector('p'); assert.equal(p.textContent, '42'); diff --git a/packages/svelte/tests/runtime-browser/custom-elements-samples/element-effect-context/_config.js b/packages/svelte/tests/runtime-browser/custom-elements-samples/element-effect-context/_config.js index 3cf7a66df1..7f2ba9f331 100644 --- a/packages/svelte/tests/runtime-browser/custom-elements-samples/element-effect-context/_config.js +++ b/packages/svelte/tests/runtime-browser/custom-elements-samples/element-effect-context/_config.js @@ -1,4 +1,5 @@ import { test } from '../../assert'; +import { flushSync } from 'svelte'; const tick = () => Promise.resolve(); export default test({ @@ -16,7 +17,7 @@ export default test({ assert.equal(p.innerHTML, 'false'); button.click(); - await tick(); + flushSync(); assert.equal(button.innerHTML, '1'); assert.equal(p.innerHTML, 'false'); diff --git a/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-in-each-destructured/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-in-each-destructured/_config.js index 650d0ec360..fe13d43bc8 100644 --- a/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-in-each-destructured/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-in-each-destructured/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ @@ -10,12 +11,13 @@ export default test({ <p>second: </p> `, - async test({ assert, component, target, window }) { + test({ assert, component, target, window }) { const event = new window.MouseEvent('click'); const buttons = target.querySelectorAll('button'); - await buttons[1].dispatchEvent(event); + buttons[1].dispatchEvent(event); + flushSync(); assert.htmlEqual( target.innerHTML, diff --git a/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-in-each/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-in-each/_config.js index 21fb167873..83b14cb8a3 100644 --- a/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-in-each/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-in-each/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ @@ -10,12 +11,13 @@ export default test({ <p>fromState: </p> `, - async test({ assert, component, target, window }) { + test({ assert, component, target, window }) { const event = new window.MouseEvent('click'); const buttons = target.querySelectorAll('button'); - await buttons[1].dispatchEvent(event); + buttons[1].dispatchEvent(event); + flushSync(); assert.htmlEqual( target.innerHTML, diff --git a/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-node-context/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-node-context/_config.js index a2edd90f8b..9276ca8a59 100644 --- a/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-node-context/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-node-context/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { ok, test } from '../../test'; export default test({ @@ -5,13 +6,14 @@ export default test({ html: '<button>10</button>', - async test({ assert, target, window }) { + test({ assert, target, window }) { const event = new window.MouseEvent('click'); const button = target.querySelector('button'); ok(button); - await button.dispatchEvent(event); + button.dispatchEvent(event); + flushSync(); assert.htmlEqual(target.innerHTML, '<button>11</button>'); } diff --git a/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-with-context/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-with-context/_config.js index c4d84fc2b3..2e6aa4dfee 100644 --- a/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-with-context/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-with-context/_config.js @@ -1,9 +1,10 @@ +import { flushSync } from 'svelte'; import { ok, test } from '../../test'; export default test({ html: '<button>???</button>', - async test({ assert, target, window }) { + test({ assert, target, window }) { const event = new window.MouseEvent('click', { clientX: 42, clientY: 42 @@ -12,7 +13,8 @@ export default test({ const button = target.querySelector('button'); ok(button); - await button.dispatchEvent(event); + button.dispatchEvent(event); + flushSync(); assert.htmlEqual(target.innerHTML, '<button>42</button>'); } diff --git a/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler/_config.js index 279171692d..3769a8bd81 100644 --- a/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler/_config.js @@ -1,9 +1,10 @@ +import { flushSync } from 'svelte'; import { ok, test } from '../../test'; export default test({ html: '<button>0, 0</button>', - async test({ assert, target, window }) { + test({ assert, target, window }) { const event = new window.MouseEvent('click', { clientX: 42, clientY: 42 @@ -12,7 +13,8 @@ export default test({ const button = target.querySelector('button'); ok(button); - await button.dispatchEvent(event); + button.dispatchEvent(event); + flushSync(); assert.htmlEqual(target.innerHTML, '<button>42, 42</button>'); } diff --git a/packages/svelte/tests/runtime-legacy/samples/action-this/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-this/_config.js index d296fc5a28..0ab9305ade 100644 --- a/packages/svelte/tests/runtime-legacy/samples/action-this/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/action-this/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { ok, test } from '../../test'; export default test({ @@ -8,7 +9,8 @@ export default test({ const click = new window.MouseEvent('click'); assert.htmlEqual(target.innerHTML, '<button>1</button>'); - await button.dispatchEvent(click); + button.dispatchEvent(click); + flushSync(); assert.htmlEqual(target.innerHTML, '<button>2</button>'); } }); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-mutate-array/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-mutate-array/_config.js index 67ea2cb0a3..70268a0e1d 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-mutate-array/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-mutate-array/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ @@ -11,7 +12,9 @@ export default test({ const [b1] = target.querySelectorAll('button'); b1.click(); - await Promise.resolve(); + Promise.resolve(); + flushSync(); + assert.htmlEqual( target.innerHTML, `<button>2</button><button>3</button><button>4</button>\n-------\n<button>1</button>` diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-object-if/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-object-if/_config.js index e823c21c9a..af04467749 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-object-if/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-object-if/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ @@ -11,6 +12,7 @@ export default test({ async test({ assert, component, target }) { await (component.thePromise = Promise.resolve({ result: 1 })); + flushSync(); assert.htmlEqual( target.innerHTML, @@ -21,6 +23,7 @@ export default test({ ); await new Promise((resolve) => setTimeout(resolve, 1)); + flushSync(); assert.htmlEqual( target.innerHTML, diff --git a/packages/svelte/tests/runtime-legacy/samples/before-render-chain/_config.js b/packages/svelte/tests/runtime-legacy/samples/before-render-chain/_config.js index 9364bd9f9e..580df5ca81 100644 --- a/packages/svelte/tests/runtime-legacy/samples/before-render-chain/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/before-render-chain/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ @@ -9,8 +10,9 @@ export default test({ <span>1</span> `, - async test({ assert, component, target }) { - await component.list.update(); + test({ assert, component, target }) { + component.list.update(); + flushSync(); assert.htmlEqual( target.innerHTML, diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-text-initial/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-text-initial/_config.js index e2a28e8dd9..83ad9c2558 100644 --- a/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-text-initial/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-text-initial/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { ok, test } from '../../test'; export default test({ @@ -18,7 +19,7 @@ export default test({ <p>hello</p> `, - async test({ assert, component, target, window }) { + test({ assert, component, target, window }) { assert.equal(component.name, 'world'); const el = target.querySelector('editor'); @@ -27,7 +28,8 @@ export default test({ const event = new window.Event('input'); el.textContent = 'everybody'; - await el.dispatchEvent(event); + el.dispatchEvent(event); + flushSync(); assert.htmlEqual( target.innerHTML, diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-text/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-text/_config.js index afecc5b3cd..494c338bfe 100644 --- a/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-text/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-text/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { ok, test } from '../../test'; export default test({ @@ -10,7 +11,7 @@ export default test({ <p>hello world</p> `, - async test({ assert, component, target, window }) { + test({ assert, component, target, window }) { const el = target.querySelector('editor'); ok(el); assert.equal(el.textContent, 'world'); @@ -18,7 +19,8 @@ export default test({ const event = new window.Event('input'); el.textContent = 'everybody'; - await el.dispatchEvent(event); + el.dispatchEvent(event); + flushSync(); assert.htmlEqual( target.innerHTML, diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-indeterminate/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-indeterminate/_config.js index 631423feaf..eba77322a1 100644 --- a/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-indeterminate/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-indeterminate/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { ok, test } from '../../test'; export default test({ @@ -17,7 +18,7 @@ export default test({ <p>indeterminate? true</p> `, - async test({ assert, component, target, window }) { + test({ assert, component, target, window }) { const input = target.querySelector('input'); ok(input); @@ -28,7 +29,8 @@ export default test({ input.checked = true; input.indeterminate = false; - await input.dispatchEvent(event); + input.dispatchEvent(event); + flushSync(); assert.equal(component.indeterminate, false); assert.equal(component.checked, true); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-in-yield/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-in-yield/_config.js index f7e5445072..b8f6a9a74a 100644 --- a/packages/svelte/tests/runtime-legacy/samples/binding-select-in-yield/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-in-yield/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { ok, test } from '../../test'; export default test({ @@ -7,8 +8,9 @@ export default test({ return { letter: 'b' }; }, - async test({ assert, component, target, window }) { - await component.modal.toggle(); + test({ assert, component, target, window }) { + component.modal.toggle(); + flushSync(); assert.htmlEqual( target.innerHTML, @@ -28,7 +30,8 @@ export default test({ const change = new window.MouseEvent('change'); select.options[2].selected = true; - await select.dispatchEvent(change); + select.dispatchEvent(change); + flushSync(); assert.equal(component.letter, 'c'); assert.deepEqual( @@ -49,9 +52,9 @@ export default test({ ` ); - await component.modal.toggle(); - await component.modal.toggle(); - await Promise.resolve(); + component.modal.toggle(); + component.modal.toggle(); + flushSync(); select = target.querySelector('select'); ok(select); diff --git a/packages/svelte/tests/runtime-legacy/samples/bindings-coalesced/_config.js b/packages/svelte/tests/runtime-legacy/samples/bindings-coalesced/_config.js index 85e1faeb73..3bc5d845a1 100644 --- a/packages/svelte/tests/runtime-legacy/samples/bindings-coalesced/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/bindings-coalesced/_config.js @@ -1,7 +1,8 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ - async test({ assert, component }) { + test({ assert, component }) { const { foo, p } = component; /** @type {string[]} */ @@ -13,7 +14,8 @@ export default test({ } }); - await foo.double(); + foo.double(); + flushSync(); assert.deepEqual(values, ['6']); } diff --git a/packages/svelte/tests/runtime-legacy/samples/component-props-mutated/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-props-mutated/_config.js index 91d0aaa0d3..4a5c102ba2 100644 --- a/packages/svelte/tests/runtime-legacy/samples/component-props-mutated/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/component-props-mutated/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; const data = { @@ -15,9 +16,10 @@ export default test({ html: '<p>hello</p>', - async test({ assert, component, target }) { + test({ assert, component, target }) { data.message = 'goodbye'; - await component.$set({ data }); + component.$set({ data }); + flushSync(); assert.htmlEqual(target.innerHTML, '<p>goodbye</p>'); } diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-g/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-g/_config.js index db9afae1b0..f3f5e04be1 100644 --- a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-g/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-g/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ @@ -5,7 +6,7 @@ export default test({ <span slot="foo" class="1">1</span> 0 `, - async test({ assert, target, component, window }) { + test({ assert, target, component, window }) { component.x = 2; assert.htmlEqual( @@ -17,7 +18,8 @@ export default test({ ); const span = target.querySelector('span'); - await span?.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + span?.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + flushSync(); assert.htmlEqual( target.innerHTML, diff --git a/packages/svelte/tests/runtime-legacy/samples/destructured-props-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/destructured-props-2/_config.js index 950ee4f1ff..0f3fcedce5 100644 --- a/packages/svelte/tests/runtime-legacy/samples/destructured-props-2/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/destructured-props-2/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ @@ -10,7 +11,7 @@ export default test({ async test({ component, assert, target }) { await component.update(); - await Promise.resolve(); + flushSync(); assert.htmlEqual( target.innerHTML, diff --git a/packages/svelte/tests/runtime-legacy/samples/destructured-props-3/_config.js b/packages/svelte/tests/runtime-legacy/samples/destructured-props-3/_config.js index 9ec2810e71..c78b84ec8c 100644 --- a/packages/svelte/tests/runtime-legacy/samples/destructured-props-3/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/destructured-props-3/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ @@ -8,7 +9,8 @@ export default test({ `, async test({ component, target, assert }) { await component.update(); - await Promise.resolve(); + flushSync(); + assert.htmlEqual( target.innerHTML, ` diff --git a/packages/svelte/tests/runtime-legacy/samples/destructured-props-5/_config.js b/packages/svelte/tests/runtime-legacy/samples/destructured-props-5/_config.js index 8f7a544bfe..103ce64d7c 100644 --- a/packages/svelte/tests/runtime-legacy/samples/destructured-props-5/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/destructured-props-5/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ @@ -10,7 +11,7 @@ export default test({ async test({ component, assert, target }) { await component.update(); - await Promise.resolve(); + flushSync(); assert.htmlEqual( target.innerHTML, diff --git a/packages/svelte/tests/runtime-legacy/samples/destructuring-assignment-array/_config.js b/packages/svelte/tests/runtime-legacy/samples/destructuring-assignment-array/_config.js index 2df8753114..9c09581097 100644 --- a/packages/svelte/tests/runtime-legacy/samples/destructuring-assignment-array/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/destructuring-assignment-array/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ @@ -10,9 +11,9 @@ export default test({ </ul> `, - async test({ assert, component, target }) { - await component.swap(0, 1); - await Promise.resolve(); + test({ assert, component, target }) { + component.swap(0, 1); + flushSync(); assert.htmlEqual( target.innerHTML, diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-expression-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/key-block-expression-2/_config.js index a661ec2596..99fa84e2a9 100644 --- a/packages/svelte/tests/runtime-legacy/samples/key-block-expression-2/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-expression-2/_config.js @@ -1,19 +1,26 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ html: '<div>3</div>', - async test({ assert, component, target }) { + test({ assert, component, target }) { const div = target.querySelector('div'); - await component.mutate(); + component.mutate(); + flushSync(); + assert.htmlEqual(target.innerHTML, '<div>5</div>'); assert.strictEqual(div, target.querySelector('div')); - await component.reassign(); + component.reassign(); + flushSync(); + assert.htmlEqual(target.innerHTML, '<div>7</div>'); assert.strictEqual(div, target.querySelector('div')); - await component.changeKey(); + component.changeKey(); + flushSync(); + assert.htmlEqual(target.innerHTML, '<div>7</div>'); assert.notStrictEqual(div, target.querySelector('div')); } diff --git a/packages/svelte/tests/runtime-legacy/samples/prop-const/_config.js b/packages/svelte/tests/runtime-legacy/samples/prop-const/_config.js index 040b911cc6..804ee53342 100644 --- a/packages/svelte/tests/runtime-legacy/samples/prop-const/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/prop-const/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ @@ -10,11 +11,12 @@ export default test({ <p>b: 2</p> `, - async test({ assert, component, target }) { - await component.$set({ + test({ assert, component, target }) { + component.$set({ a: 5, b: 6 }); + flushSync(); assert.htmlEqual( target.innerHTML, diff --git a/packages/svelte/tests/runtime-legacy/samples/props-reactive-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/props-reactive-b/_config.js index b92d81bd53..91133f0bf4 100644 --- a/packages/svelte/tests/runtime-legacy/samples/props-reactive-b/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/props-reactive-b/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ @@ -11,8 +12,9 @@ export default test({ <p>c: 3</p> `, - async test({ assert, component, target }) { - await component.$set({ a: 4 }); + test({ assert, component, target }) { + component.$set({ a: 4 }); + flushSync(); assert.htmlEqual( target.innerHTML, @@ -23,7 +25,8 @@ export default test({ ` ); - await component.$set({ b: 5 }); + component.$set({ b: 5 }); + flushSync(); assert.htmlEqual( target.innerHTML, diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store-3/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store-3/_config.js index 2325d17cd5..1a67e46b38 100644 --- a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store-3/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store-3/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; import { store } from './store.js'; @@ -6,10 +7,9 @@ export default test({ before_test() { store.reset(); }, - async test({ assert, target }) { + test({ assert, target }) { store.set(42); - - await Promise.resolve(); + flushSync(); assert.htmlEqual(target.innerHTML, '<h1>42</h1>'); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-value-dependency-not-referenced/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-value-dependency-not-referenced/_config.js index f2f7fe92b1..3b31ee766e 100644 --- a/packages/svelte/tests/runtime-legacy/samples/reactive-value-dependency-not-referenced/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-value-dependency-not-referenced/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ @@ -6,29 +7,35 @@ export default test({ <p>42</p> `, - async test({ assert, component, target }) { - await component.updateStore(undefined); - await Promise.resolve(); + test({ assert, component, target }) { + component.updateStore(undefined); + flushSync(); + assert.htmlEqual(target.innerHTML, '<p></p><p>42</p>'); - await component.updateStore(33); - await Promise.resolve(); + component.updateStore(33); + flushSync(); + assert.htmlEqual(target.innerHTML, '<p>33</p><p>42</p>'); - await component.updateStore(undefined); - await Promise.resolve(); + component.updateStore(undefined); + flushSync(); + assert.htmlEqual(target.innerHTML, '<p></p><p>42</p>'); - await component.updateVar(undefined); - await Promise.resolve(); + component.updateVar(undefined); + flushSync(); + assert.htmlEqual(target.innerHTML, '<p></p><p></p>'); - await component.updateVar(33); - await Promise.resolve(); + component.updateVar(33); + flushSync(); + assert.htmlEqual(target.innerHTML, '<p></p><p>33</p>'); - await component.updateVar(undefined); - await Promise.resolve(); + component.updateVar(undefined); + flushSync(); + assert.htmlEqual(target.innerHTML, '<p></p><p></p>'); } }); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-value-function/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-value-function/_config.js index cbcb19d95e..5317ab496f 100644 --- a/packages/svelte/tests/runtime-legacy/samples/reactive-value-function/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-value-function/_config.js @@ -1,10 +1,12 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ html: '1-2', - async test({ assert, component, target }) { - await component.update(); + test({ assert, component, target }) { + component.update(); + flushSync(); assert.htmlEqual(target.innerHTML, '3-4'); } diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-text-node/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-values-text-node/_config.js index e05c8c80dd..e97a046f68 100644 --- a/packages/svelte/tests/runtime-legacy/samples/reactive-values-text-node/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-text-node/_config.js @@ -1,5 +1,6 @@ import { test } from '../../test'; import { create_deferred } from '../../../helpers'; +import { flushSync } from 'svelte'; /** @type {ReturnType<typeof create_deferred>} */ let deferred; @@ -17,6 +18,8 @@ export default test({ async test({ assert, target }) { await deferred.promise; + flushSync(); + assert.htmlEqual( target.innerHTML, ` diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-own-props/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-own-props/_config.js index 708e3615f1..7486055440 100644 --- a/packages/svelte/tests/runtime-legacy/samples/spread-own-props/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/spread-own-props/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ @@ -17,13 +18,14 @@ export default test({ <p>quux: core</p></div> `, - async test({ assert, component, target }) { - await component.$set({ + test({ assert, component, target }) { + component.$set({ foo: 'wut', baz: 40 + 3, qux: `this is a ${'rather boring'} string`, quux: 'heart' }); + flushSync(); assert.htmlEqual( target.innerHTML, diff --git a/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-in-reactive-declaration-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-in-reactive-declaration-2/_config.js index 8e0886c668..d380150e55 100644 --- a/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-in-reactive-declaration-2/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-in-reactive-declaration-2/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ @@ -6,10 +7,9 @@ export default test({ <div>Hello World</div> `, - async test({ assert, component, target }) { - await component.update_value('Hi Svelte'); - await Promise.resolve(); - await Promise.resolve(); + test({ assert, component, target }) { + component.update_value('Hi Svelte'); + flushSync(); assert.htmlEqual( target.innerHTML, diff --git a/packages/svelte/tests/runtime-legacy/samples/store-increment-updates-reactive/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-increment-updates-reactive/_config.js index 1c81f7c4e8..89ff695d9d 100644 --- a/packages/svelte/tests/runtime-legacy/samples/store-increment-updates-reactive/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/store-increment-updates-reactive/_config.js @@ -1,10 +1,13 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ html: '0', - async test({ assert, component, target }) { - await component.increment(); + test({ assert, component, target }) { + component.increment(); + flushSync(); + assert.htmlEqual(target.innerHTML, '1'); } }); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-unreferenced/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-unreferenced/_config.js index 808ed899d3..7096f5d1fe 100644 --- a/packages/svelte/tests/runtime-legacy/samples/store-unreferenced/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/store-unreferenced/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; import { count } from './store.js'; @@ -8,8 +9,9 @@ export default test({ count.set(0); }, - async test({ assert, component, target }) { - await component.increment(); + test({ assert, component, target }) { + component.increment(); + flushSync(); assert.htmlEqual(target.innerHTML, '<p>count: 1</p>'); } diff --git a/packages/svelte/tests/runtime-legacy/samples/window-event-custom/_config.js b/packages/svelte/tests/runtime-legacy/samples/window-event-custom/_config.js index 32b1c65154..f6b7a8af42 100644 --- a/packages/svelte/tests/runtime-legacy/samples/window-event-custom/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/window-event-custom/_config.js @@ -1,14 +1,16 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ html: '<p>escaped: false</p>', - async test({ assert, target, window }) { + test({ assert, target, window }) { const event = new window.KeyboardEvent('keydown', { key: 'Escape' }); - await window.dispatchEvent(event); + window.dispatchEvent(event); + flushSync(); assert.htmlEqual( target.innerHTML, diff --git a/packages/svelte/tests/runtime-runes/samples/derived-unowned-2/_config.js b/packages/svelte/tests/runtime-runes/samples/derived-unowned-2/_config.js index 3604000543..3ca98bb0c6 100644 --- a/packages/svelte/tests/runtime-runes/samples/derived-unowned-2/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/derived-unowned-2/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ @@ -7,7 +8,7 @@ export default test({ async test({ assert, target }) { await Promise.resolve(); - await Promise.resolve(); + flushSync(); assert.htmlEqual( target.innerHTML, '<div>d2: 3,4,5</div><div>d3: 3,4,5</div><div>d4: 3,4,5</div>' diff --git a/packages/svelte/tests/runtime-runes/samples/derived-unowned-5/_config.js b/packages/svelte/tests/runtime-runes/samples/derived-unowned-5/_config.js index 20c3cc112e..5f38394d06 100644 --- a/packages/svelte/tests/runtime-runes/samples/derived-unowned-5/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/derived-unowned-5/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ @@ -5,7 +6,7 @@ export default test({ // The test has a bunch of queueMicrotasks await Promise.resolve(); await Promise.resolve(); - await Promise.resolve(); + flushSync(); assert.htmlEqual(target.innerHTML, `<div>Zeeba Neighba</div>`); } diff --git a/packages/svelte/tests/runtime-runes/samples/runes-from-func/_config.js b/packages/svelte/tests/runtime-runes/samples/runes-from-func/_config.js index 7d3dd9993f..5ed7579c62 100644 --- a/packages/svelte/tests/runtime-runes/samples/runes-from-func/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/runes-from-func/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ @@ -5,7 +6,7 @@ export default test({ async test({ assert, target }) { await Promise.resolve(); - await Promise.resolve(); + flushSync(); assert.htmlEqual(target.innerHTML, `<span>1</span>`); } }); From 8a1acac084096d9c9bd15a1356d3251383e8d258 Mon Sep 17 00:00:00 2001 From: Paolo Ricciuti <ricciutipaolo@gmail.com> Date: Mon, 13 Jan 2025 22:17:39 +0100 Subject: [PATCH 62/63] fix: never consider inert boundary effects (#14999) * fix: never consider inert boundary effects * chore: inline bitwise --- .changeset/healthy-hairs-run.md | 5 +++++ .../src/internal/client/reactivity/effects.js | 5 +++-- .../samples/error-boundary-21/Child.svelte | 3 +++ .../samples/error-boundary-21/_config.js | 17 +++++++++++++++++ .../samples/error-boundary-21/main.svelte | 14 ++++++++++++++ 5 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 .changeset/healthy-hairs-run.md create mode 100644 packages/svelte/tests/runtime-runes/samples/error-boundary-21/Child.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/error-boundary-21/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/error-boundary-21/main.svelte diff --git a/.changeset/healthy-hairs-run.md b/.changeset/healthy-hairs-run.md new file mode 100644 index 0000000000..5f0ccd5234 --- /dev/null +++ b/.changeset/healthy-hairs-run.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: never consider inert boundary effects diff --git a/packages/svelte/src/internal/client/reactivity/effects.js b/packages/svelte/src/internal/client/reactivity/effects.js index 16f076edde..149cbd2d38 100644 --- a/packages/svelte/src/internal/client/reactivity/effects.js +++ b/packages/svelte/src/internal/client/reactivity/effects.js @@ -35,7 +35,8 @@ import { INSPECT_EFFECT, HEAD_EFFECT, MAYBE_DIRTY, - EFFECT_HAS_DERIVED + EFFECT_HAS_DERIVED, + BOUNDARY_EFFECT } from '../constants.js'; import { set } from './sources.js'; import * as e from '../errors.js'; @@ -142,7 +143,7 @@ function create_effect(type, fn, sync, push = true) { effect.first === null && effect.nodes_start === null && effect.teardown === null && - (effect.f & EFFECT_HAS_DERIVED) === 0; + (effect.f & (EFFECT_HAS_DERIVED | BOUNDARY_EFFECT)) === 0; if (!inert && !is_root && push) { if (parent_effect !== null) { diff --git a/packages/svelte/tests/runtime-runes/samples/error-boundary-21/Child.svelte b/packages/svelte/tests/runtime-runes/samples/error-boundary-21/Child.svelte new file mode 100644 index 0000000000..ea60542af9 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/error-boundary-21/Child.svelte @@ -0,0 +1,3 @@ +<script> + throw new Error(); +</script> diff --git a/packages/svelte/tests/runtime-runes/samples/error-boundary-21/_config.js b/packages/svelte/tests/runtime-runes/samples/error-boundary-21/_config.js new file mode 100644 index 0000000000..e301f83e60 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/error-boundary-21/_config.js @@ -0,0 +1,17 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: '<button></button><div>0</div>', + mode: ['client'], + test({ assert, target }) { + let btn = target.querySelector('button'); + let div = target.querySelector('div'); + + flushSync(() => { + btn?.click(); + }); + + assert.equal(div?.innerHTML, `1`); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/error-boundary-21/main.svelte b/packages/svelte/tests/runtime-runes/samples/error-boundary-21/main.svelte new file mode 100644 index 0000000000..ed3140b1ef --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/error-boundary-21/main.svelte @@ -0,0 +1,14 @@ +<script> + import Child from "./Child.svelte" + + let count = $state(0); +</script> + +<button onclick={()=>count++}></button> +<svelte:boundary> + <Child /> + + {#snippet failed()} + <div>{count}</div> + {/snippet} +</svelte:boundary> From efa5acf24e040160172550eb5f7fa7ca9390f2e0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 13 Jan 2025 17:18:43 -0500 Subject: [PATCH 63/63] Version Packages (#14970) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> --- .changeset/healthy-hairs-run.md | 5 ----- .changeset/hot-kings-shout.md | 5 ----- .changeset/spicy-insects-check.md | 5 ----- .changeset/tender-apples-scream.md | 5 ----- packages/svelte/CHANGELOG.md | 12 ++++++++++++ packages/svelte/package.json | 2 +- packages/svelte/src/version.js | 2 +- 7 files changed, 14 insertions(+), 22 deletions(-) delete mode 100644 .changeset/healthy-hairs-run.md delete mode 100644 .changeset/hot-kings-shout.md delete mode 100644 .changeset/spicy-insects-check.md delete mode 100644 .changeset/tender-apples-scream.md diff --git a/.changeset/healthy-hairs-run.md b/.changeset/healthy-hairs-run.md deleted file mode 100644 index 5f0ccd5234..0000000000 --- a/.changeset/healthy-hairs-run.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: never consider inert boundary effects diff --git a/.changeset/hot-kings-shout.md b/.changeset/hot-kings-shout.md deleted file mode 100644 index afba164abf..0000000000 --- a/.changeset/hot-kings-shout.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: store access on component destroy diff --git a/.changeset/spicy-insects-check.md b/.changeset/spicy-insects-check.md deleted file mode 100644 index b998d36400..0000000000 --- a/.changeset/spicy-insects-check.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: correctly transform `pre` with no content diff --git a/.changeset/tender-apples-scream.md b/.changeset/tender-apples-scream.md deleted file mode 100644 index 836bdaffdf..0000000000 --- a/.changeset/tender-apples-scream.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: wrap each block expression in derived to encapsulate effects diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index 6023c6d4e1..4f3b9a168a 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,17 @@ # svelte +## 5.17.4 + +### Patch Changes + +- fix: never consider inert boundary effects ([#14999](https://github.com/sveltejs/svelte/pull/14999)) + +- fix: store access on component destroy ([#14968](https://github.com/sveltejs/svelte/pull/14968)) + +- fix: correctly transform `pre` with no content ([#14973](https://github.com/sveltejs/svelte/pull/14973)) + +- fix: wrap each block expression in derived to encapsulate effects ([#14967](https://github.com/sveltejs/svelte/pull/14967)) + ## 5.17.3 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 47aec9ee93..f426b97be4 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -2,7 +2,7 @@ "name": "svelte", "description": "Cybernetically enhanced web apps", "license": "MIT", - "version": "5.17.3", + "version": "5.17.4", "type": "module", "types": "./types/index.d.ts", "engines": { diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js index 0fd7d2f039..69a8833938 100644 --- a/packages/svelte/src/version.js +++ b/packages/svelte/src/version.js @@ -4,5 +4,5 @@ * The current version, as set in package.json. * @type {string} */ -export const VERSION = '5.17.3'; +export const VERSION = '5.17.4'; export const PUBLIC_VERSION = '5';