Skip to content

Commit 267f247

Browse files
committed
fix: throw on duplicate class field declarations
1 parent 9412c58 commit 267f247

File tree

5 files changed

+61
-2
lines changed

5 files changed

+61
-2
lines changed

.changeset/odd-phones-taste.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: throw on duplicate class field declarations

documentation/docs/98-reference/.generated/compile-errors.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,12 @@ The $ name is reserved, and cannot be used for variables and imports
364364
The $ prefix is reserved, and cannot be used for variables and imports
365365
```
366366

367+
### duplicate_class_field
368+
369+
```
370+
`%name%` has already been declared
371+
```
372+
367373
### each_item_invalid_assignment
368374

369375
```

packages/svelte/messages/compile-errors/script.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@
3030

3131
> The $ prefix is reserved, and cannot be used for variables and imports
3232
33+
## duplicate_class_field
34+
35+
> `%name%` has already been declared
36+
3337
## each_item_invalid_assignment
3438

3539
> 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}`)

packages/svelte/src/compiler/errors.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,16 @@ export function dollar_prefix_invalid(node) {
152152
e(node, 'dollar_prefix_invalid', `The $ prefix is reserved, and cannot be used for variables and imports\nhttps://svelte.dev/e/dollar_prefix_invalid`);
153153
}
154154

155+
/**
156+
* `%name%` has already been declared
157+
* @param {null | number | NodeLike} node
158+
* @param {string} name
159+
* @returns {never}
160+
*/
161+
export function duplicate_class_field(node, name) {
162+
e(node, 'duplicate_class_field', `\`${name}\` has already been declared\nhttps://svelte.dev/e/duplicate_class_field`);
163+
}
164+
155165
/**
156166
* 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}`)
157167
* @param {null | number | NodeLike} node

packages/svelte/src/compiler/phases/2-analyze/visitors/ClassBody.js

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ export function ClassBody(node, context) {
3333
/** @type {Map<string, StateField>} */
3434
const state_fields = new Map();
3535

36+
/** @type {Map<string, Array<MethodDefinition['kind'] | 'prop'>>} */
37+
const fields = new Map();
38+
3639
context.state.analysis.classes.set(node, state_fields);
3740

3841
/** @type {MethodDefinition | null} */
@@ -67,10 +70,41 @@ export function ClassBody(node, context) {
6770
for (const child of node.body) {
6871
if (child.type === 'PropertyDefinition' && !child.computed && !child.static) {
6972
handle(child, child.key, child.value);
73+
const key = (child.key.type === 'PrivateIdentifier' ? '#' : '') + get_name(child.key);
74+
const field = fields.get(key);
75+
if (!field) {
76+
fields.set(key, ['prop']);
77+
continue;
78+
}
79+
field.push('prop');
7080
}
7181

72-
if (child.type === 'MethodDefinition' && child.kind === 'constructor') {
73-
constructor = child;
82+
if (child.type === 'MethodDefinition') {
83+
if (child.kind === 'constructor') {
84+
constructor = child;
85+
} else if (!child.computed) {
86+
const key = (child.key.type === 'PrivateIdentifier' ? '#' : '') + get_name(child.key);
87+
const field = fields.get(key);
88+
if (!field) {
89+
fields.set(key, [child.kind]);
90+
continue;
91+
}
92+
if (child.kind === 'get') {
93+
if (field.length === 1 && field[0] === 'set') {
94+
field.push('get');
95+
continue;
96+
}
97+
} else if (child.kind === 'set') {
98+
if (field.length === 1 && field[0] === 'get') {
99+
field.push('set');
100+
continue;
101+
}
102+
} else {
103+
field.push(child.kind);
104+
continue;
105+
}
106+
e.duplicate_class_field(child, key);
107+
}
74108
}
75109
}
76110

0 commit comments

Comments
 (0)