Skip to content

Commit 879d88f

Browse files
fix: show correct errors for invalid runes in .svelte.js files (#12432)
* fix: show correct error for renamed runes in `.svelte.js` files * better * changeset * comment * cleanup * types & lint * lint * revert src changes * move existing validation logic --------- Co-authored-by: Rich Harris <[email protected]>
1 parent 8d3c026 commit 879d88f

File tree

6 files changed

+59
-35
lines changed

6 files changed

+59
-35
lines changed

.changeset/hip-months-breathe.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: show correct errors for invalid runes in `.svelte.js` files

packages/svelte/src/compiler/phases/2-analyze/validation.js

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,41 @@ export const validation_runes_js = {
10431043
if (node.callee.type === 'ClassExpression' && context.state.scope.function_depth > 0) {
10441044
w.perf_avoid_inline_class(node);
10451045
}
1046+
},
1047+
Identifier(node, { path, state }) {
1048+
let i = path.length;
1049+
let parent = /** @type {import('estree').Expression} */ (path[--i]);
1050+
1051+
if (
1052+
Runes.includes(/** @type {Runes[number]} */ (node.name)) &&
1053+
is_reference(node, parent) &&
1054+
state.scope.get(node.name) === null &&
1055+
state.scope.get(node.name.slice(1)) === null
1056+
) {
1057+
/** @type {import('estree').Expression} */
1058+
let current = node;
1059+
let name = node.name;
1060+
1061+
while (parent.type === 'MemberExpression') {
1062+
if (parent.computed) e.rune_invalid_computed_property(parent);
1063+
name += `.${/** @type {import('estree').Identifier} */ (parent.property).name}`;
1064+
1065+
current = parent;
1066+
parent = /** @type {import('estree').Expression} */ (path[--i]);
1067+
1068+
if (!Runes.includes(/** @type {Runes[number]} */ (name))) {
1069+
if (name === '$effect.active') {
1070+
e.rune_renamed(parent, '$effect.active', '$effect.tracking');
1071+
}
1072+
1073+
e.rune_invalid_name(parent, name);
1074+
}
1075+
}
1076+
1077+
if (parent.type !== 'CallExpression') {
1078+
e.rune_missing_parentheses(current);
1079+
}
1080+
}
10461081
}
10471082
};
10481083

@@ -1153,41 +1188,6 @@ export const validation_runes = merge(validation, a11y_validators, {
11531188
e.import_svelte_internal_forbidden(node);
11541189
}
11551190
},
1156-
Identifier(node, { path, state }) {
1157-
let i = path.length;
1158-
let parent = /** @type {import('estree').Expression} */ (path[--i]);
1159-
1160-
if (
1161-
Runes.includes(/** @type {Runes[number]} */ (node.name)) &&
1162-
is_reference(node, parent) &&
1163-
state.scope.get(node.name) === null &&
1164-
state.scope.get(node.name.slice(1)) === null
1165-
) {
1166-
/** @type {import('estree').Expression} */
1167-
let current = node;
1168-
let name = node.name;
1169-
1170-
while (parent.type === 'MemberExpression') {
1171-
if (parent.computed) e.rune_invalid_computed_property(parent);
1172-
name += `.${/** @type {import('estree').Identifier} */ (parent.property).name}`;
1173-
1174-
current = parent;
1175-
parent = /** @type {import('estree').Expression} */ (path[--i]);
1176-
1177-
if (!Runes.includes(/** @type {Runes[number]} */ (name))) {
1178-
if (name === '$effect.active') {
1179-
e.rune_renamed(parent, '$effect.active', '$effect.tracking');
1180-
}
1181-
1182-
e.rune_invalid_name(parent, name);
1183-
}
1184-
}
1185-
1186-
if (parent.type !== 'CallExpression') {
1187-
e.rune_missing_parentheses(current);
1188-
}
1189-
}
1190-
},
11911191
LabeledStatement(node, { path }) {
11921192
if (node.label.name !== '$' || path.at(-1)?.type !== 'Program') return;
11931193
e.legacy_reactive_statement_invalid(node);
@@ -1368,5 +1368,6 @@ export const validation_runes = merge(validation, a11y_validators, {
13681368
// TODO this is a code smell. need to refactor this stuff
13691369
ClassBody: validation_runes_js.ClassBody,
13701370
ClassDeclaration: validation_runes_js.ClassDeclaration,
1371+
Identifier: validation_runes_js.Identifier,
13711372
NewExpression: validation_runes_js.NewExpression
13721373
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
error: {
5+
code: 'rune_renamed',
6+
message: '`$effect.active` is now `$effect.tracking`'
7+
}
8+
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
$effect.active();
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
error: {
5+
code: 'rune_invalid_name',
6+
message: '`$effect.imnotarune` is not a valid rune'
7+
}
8+
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
$effect.imnotarune();

0 commit comments

Comments
 (0)