Skip to content

Commit e1b940c

Browse files
committed
restrict which symbols are recognised as attachment keys
1 parent 1988ba4 commit e1b940c

File tree

8 files changed

+39
-7
lines changed

8 files changed

+39
-7
lines changed

packages/svelte/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@
3333
"types": "./types/index.d.ts",
3434
"default": "./src/animate/index.js"
3535
},
36+
"./attachments": {
37+
"types": "./types/index.d.ts",
38+
"default": "./src/attachments/index.js"
39+
},
3640
"./compiler": {
3741
"types": "./types/index.d.ts",
3842
"require": "./compiler/index.js",

packages/svelte/scripts/generate-types.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ await createBundle({
3030
[pkg.name]: `${dir}/src/index.d.ts`,
3131
[`${pkg.name}/action`]: `${dir}/src/action/public.d.ts`,
3232
[`${pkg.name}/animate`]: `${dir}/src/animate/public.d.ts`,
33+
[`${pkg.name}/attachments`]: `${dir}/src/attachments/public.d.ts`,
3334
[`${pkg.name}/compiler`]: `${dir}/src/compiler/public.d.ts`,
3435
[`${pkg.name}/easing`]: `${dir}/src/easing/index.js`,
3536
[`${pkg.name}/legacy`]: `${dir}/src/legacy/legacy-client.js`,
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export {
2+
create_attachment_key as createAttachmentKey,
3+
is_attachment_key as isAttachmentKey
4+
} from '../internal/client/dom/elements/attachments.js';

packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ export function build_component(node, component_name, context, anchor = context.
257257
push_prop(
258258
b.prop(
259259
'get',
260-
b.call('Symbol', b.literal('@attach')),
260+
b.call('$.create_attachment_key'),
261261
/** @type {Expression} */ (context.visit(attribute.expression)),
262262
true
263263
)

packages/svelte/src/internal/client/dom/elements/attachments.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
11
import { effect } from '../../reactivity/effects.js';
22

3+
const key = `@attach-${Math.random().toString(36).slice(2)}`;
4+
const name = `Symbol(${key})`;
5+
6+
// TODO this feels a bit belt-and-braces to me, tbh — are we sure we need it?
7+
/**
8+
* Creates a `Symbol` that Svelte recognises as an attachment key
9+
*/
10+
export function create_attachment_key() {
11+
return Symbol(key);
12+
}
13+
14+
/**
15+
* Returns `true` if the symbol was created with `createAttachmentKey`
16+
* @param {string | symbol} key
17+
*/
18+
export function is_attachment_key(key) {
19+
return typeof key === 'symbol' && key.toString() === name;
20+
}
21+
322
/**
423
* @param {Element} node
524
* @param {() => (node: Element) => void} get_fn

packages/svelte/src/internal/client/dom/elements/attributes.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
set_active_effect,
1414
set_active_reaction
1515
} from '../../runtime.js';
16-
import { attach } from './attachments.js';
16+
import { attach, is_attachment_key } from './attachments.js';
1717

1818
/**
1919
* The value/checked attribute in the template actually corresponds to the defaultValue property, so we need
@@ -242,8 +242,8 @@ export function set_custom_element_data(node, prop, value) {
242242
/**
243243
* Spreads attributes onto a DOM element, taking into account the currently set attributes
244244
* @param {Element & ElementCSSInlineStyle} element
245-
* @param {Record<string, any> | undefined} prev
246-
* @param {Record<string, any>} next New attributes - this function mutates this object
245+
* @param {Record<string | symbol, any> | undefined} prev
246+
* @param {Record<string | symbol, any>} next New attributes - this function mutates this object
247247
* @param {string} [css_hash]
248248
* @param {boolean} [preserve_attribute_case]
249249
* @param {boolean} [is_custom_element]
@@ -409,7 +409,9 @@ export function set_attributes(
409409
}
410410

411411
for (let symbol of Object.getOwnPropertySymbols(next)) {
412-
attach(element, () => next[symbol]);
412+
if (is_attachment_key(symbol)) {
413+
attach(element, () => next[symbol]);
414+
}
413415
}
414416

415417
return current;

packages/svelte/src/internal/client/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export { element } from './dom/blocks/svelte-element.js';
2727
export { head } from './dom/blocks/svelte-head.js';
2828
export { append_styles } from './dom/css.js';
2929
export { action } from './dom/elements/actions.js';
30-
export { attach } from './dom/elements/attachments.js';
30+
export { attach, create_attachment_key, is_attachment_key } from './dom/elements/attachments.js';
3131
export {
3232
remove_input_defaults,
3333
set_attribute,

packages/svelte/tests/runtime-runes/samples/attachment-spread/main.svelte

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<script>
2+
import { createAttachmentKey } from 'svelte/attachments';
3+
24
let stuff = $state({
3-
[Symbol()]: () => console.log('hello')
5+
[createAttachmentKey()]: () => console.log('hello')
46
});
57
</script>
68

0 commit comments

Comments
 (0)