From fc896a779f031ef27c8f85734abf9f4d14394748 Mon Sep 17 00:00:00 2001 From: paoloricciuti Date: Sun, 18 May 2025 15:36:43 +0200 Subject: [PATCH] fix: add warning when you read object property within attachments in legacy mode --- .changeset/breezy-pears-punch.md | 5 +++++ .../98-reference/.generated/compile-warnings.md | 6 ++++++ .../svelte/messages/compile-warnings/template.md | 4 ++++ .../phases/2-analyze/visitors/AttachTag.js | 13 +++++++++++++ packages/svelte/src/compiler/warnings.js | 9 +++++++++ .../attachment-legacy-member-access/input.svelte | 14 ++++++++++++++ .../attachment-legacy-member-access/warnings.json | 14 ++++++++++++++ 7 files changed, 65 insertions(+) create mode 100644 .changeset/breezy-pears-punch.md create mode 100644 packages/svelte/tests/validator/samples/attachment-legacy-member-access/input.svelte create mode 100644 packages/svelte/tests/validator/samples/attachment-legacy-member-access/warnings.json diff --git a/.changeset/breezy-pears-punch.md b/.changeset/breezy-pears-punch.md new file mode 100644 index 0000000000..e0ff7e746c --- /dev/null +++ b/.changeset/breezy-pears-punch.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: add warning when you read object property within attachments in legacy mode diff --git a/documentation/docs/98-reference/.generated/compile-warnings.md b/documentation/docs/98-reference/.generated/compile-warnings.md index 7069f90206..3f2aa11618 100644 --- a/documentation/docs/98-reference/.generated/compile-warnings.md +++ b/documentation/docs/98-reference/.generated/compile-warnings.md @@ -556,6 +556,12 @@ Elements with ARIA roles must use a valid, non-abstract ARIA role. A reference t
``` +### attachment_legacy_member_access + +``` +Using `@attach` with a function from an object in legacy mode can cause unnecessary reruns of the attachment function if you mutate that object. +``` + ### attribute_avoid_is ``` diff --git a/packages/svelte/messages/compile-warnings/template.md b/packages/svelte/messages/compile-warnings/template.md index c1675e5995..a62882a9cf 100644 --- a/packages/svelte/messages/compile-warnings/template.md +++ b/packages/svelte/messages/compile-warnings/template.md @@ -1,3 +1,7 @@ +## attachment_legacy_member_access + +> Using `@attach` with a function from an object in legacy mode can cause unnecessary reruns of the attachment function if you mutate that object. + ## attribute_avoid_is > The "is" attribute is not supported cross-browser and should be avoided diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/AttachTag.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/AttachTag.js index 1e318f228d..40333e9bd1 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/AttachTag.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/AttachTag.js @@ -1,7 +1,9 @@ /** @import { AST } from '#compiler' */ /** @import { Context } from '../types' */ +import { walk } from 'zimmerframe'; import { mark_subtree_dynamic } from './shared/fragment.js'; +import * as w from '../../../warnings.js'; /** * @param {AST.AttachTag} node @@ -9,5 +11,16 @@ import { mark_subtree_dynamic } from './shared/fragment.js'; */ export function AttachTag(node, context) { mark_subtree_dynamic(context.path); + if (!context.state.analysis.runes) { + walk( + node.expression, + {}, + { + MemberExpression(node) { + w.attachment_legacy_member_access(node); + } + } + ); + } context.next({ ...context.state, expression: node.metadata.expression }); } diff --git a/packages/svelte/src/compiler/warnings.js b/packages/svelte/src/compiler/warnings.js index c281433213..4740bdaeb4 100644 --- a/packages/svelte/src/compiler/warnings.js +++ b/packages/svelte/src/compiler/warnings.js @@ -106,6 +106,7 @@ export const codes = [ 'state_referenced_locally', 'store_rune_conflict', 'css_unused_selector', + 'attachment_legacy_member_access', 'attribute_avoid_is', 'attribute_global_event_reference', 'attribute_illegal_colon', @@ -677,6 +678,14 @@ export function css_unused_selector(node, name) { w(node, 'css_unused_selector', `Unused CSS selector "${name}"\nhttps://svelte.dev/e/css_unused_selector`); } +/** + * Using `@attach` with a function from an object in legacy mode can cause unnecessary reruns of the attachment function if you mutate that object. + * @param {null | NodeLike} node + */ +export function attachment_legacy_member_access(node) { + w(node, 'attachment_legacy_member_access', `Using \`@attach\` with a function from an object can cause unnecessary reruns of the attachment function if you mutate that object in legacy mode.\nhttps://svelte.dev/e/attachment_legacy_member_access`); +} + /** * The "is" attribute is not supported cross-browser and should be avoided * @param {null | NodeLike} node diff --git a/packages/svelte/tests/validator/samples/attachment-legacy-member-access/input.svelte b/packages/svelte/tests/validator/samples/attachment-legacy-member-access/input.svelte new file mode 100644 index 0000000000..cc56759f13 --- /dev/null +++ b/packages/svelte/tests/validator/samples/attachment-legacy-member-access/input.svelte @@ -0,0 +1,14 @@ + + + + +
\ No newline at end of file diff --git a/packages/svelte/tests/validator/samples/attachment-legacy-member-access/warnings.json b/packages/svelte/tests/validator/samples/attachment-legacy-member-access/warnings.json new file mode 100644 index 0000000000..ff981c4fff --- /dev/null +++ b/packages/svelte/tests/validator/samples/attachment-legacy-member-access/warnings.json @@ -0,0 +1,14 @@ +[ + { + "code": "attachment_legacy_member_access", + "message": "Using `@attach` with a function from an object in legacy mode can cause unnecessary reruns of the attachment function if you mutate that object.", + "start": { + "line": 14, + "column": 14 + }, + "end": { + "line": 14, + "column": 30 + } + } +]