Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/cool-spoons-tap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: warn on undeclared shorthand event handlers on `<svelte:window>`, `<svelte:document>` and `<svelte:body>`
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/** @import { Context } from '../types' */
import * as e from '../../../errors.js';
import { is_event_attribute } from '../../../utils/ast.js';
import { disallow_children } from './shared/special-element.js';
import { check_global_event_reference, disallow_children } from './shared/special-element.js';

/**
* @param {AST.SvelteBody} node
Expand All @@ -11,10 +11,9 @@ import { disallow_children } from './shared/special-element.js';
export function SvelteBody(node, context) {
disallow_children(node);
for (const attribute of node.attributes) {
if (
attribute.type === 'SpreadAttribute' ||
(attribute.type === 'Attribute' && !is_event_attribute(attribute))
) {
if (attribute.type === 'Attribute' && is_event_attribute(attribute)) {
check_global_event_reference(attribute, context);
} else if (attribute.type === 'SpreadAttribute' || attribute.type === 'Attribute') {
e.svelte_body_illegal_attribute(attribute);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/** @import { AST } from '#compiler' */
/** @import { Context } from '../types' */
import { disallow_children } from './shared/special-element.js';
import { check_global_event_reference, disallow_children } from './shared/special-element.js';
import * as e from '../../../errors.js';
import { is_event_attribute } from '../../../utils/ast.js';

Expand All @@ -12,10 +12,9 @@ export function SvelteDocument(node, context) {
disallow_children(node);

for (const attribute of node.attributes) {
if (
attribute.type === 'SpreadAttribute' ||
(attribute.type === 'Attribute' && !is_event_attribute(attribute))
) {
if (attribute.type === 'Attribute' && is_event_attribute(attribute)) {
check_global_event_reference(attribute, context);
} else if (attribute.type === 'SpreadAttribute' || attribute.type === 'Attribute') {
e.illegal_element_attribute(attribute, 'svelte:document');
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/** @import { AST } from '#compiler' */
/** @import { Context } from '../types' */
import { disallow_children } from './shared/special-element.js';
import { check_global_event_reference, disallow_children } from './shared/special-element.js';
import * as e from '../../../errors.js';
import { is_event_attribute } from '../../../utils/ast.js';

Expand All @@ -12,10 +12,9 @@ export function SvelteWindow(node, context) {
disallow_children(node);

for (const attribute of node.attributes) {
if (
attribute.type === 'SpreadAttribute' ||
(attribute.type === 'Attribute' && !is_event_attribute(attribute))
) {
if (attribute.type === 'Attribute' && is_event_attribute(attribute)) {
check_global_event_reference(attribute, context);
} else if (attribute.type === 'SpreadAttribute' || attribute.type === 'Attribute') {
e.illegal_element_attribute(attribute, 'svelte:window');
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
/** @import { AST } from '#compiler' */
/** @import { Context } from '../../types' */
import { get_attribute_expression } from '../../../../utils/ast.js';
import * as e from '../../../../errors.js';
import * as w from '../../../../warnings.js';

/**
* Warns when an event attribute uses the shorthand form (`{onclick}`) but the
* referenced name isn't declared, so it silently resolves to the global handler.
* @param {AST.Attribute} attribute
* @param {Context} context
*/
export function check_global_event_reference(attribute, context) {
const value = get_attribute_expression(
/** @type {AST.Attribute & { value: [AST.ExpressionTag] | AST.ExpressionTag }} */ (attribute)
);

if (
value.type === 'Identifier' &&
value.name === attribute.name &&
!context.state.scope.get(value.name)
) {
w.attribute_global_event_reference(attribute, attribute.name);
}
}

/**
* @param {AST.SvelteBody | AST.SvelteDocument | AST.SvelteOptionsRaw | AST.SvelteWindow} node
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { test } from '../../test';

export default test({});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script>
let onkeydown;
</script>

<svelte:window {onkeydown} {onresize} />
<svelte:document {onvisibilitychange} />
<svelte:body {onfocus} />
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[
{
"code": "attribute_global_event_reference",
"message": "You are referencing `globalThis.onresize`. Did you forget to declare a variable with that name?",
"start": {
"column": 27,
"line": 5
},
"end": {
"column": 37,
"line": 5
}
},
{
"code": "attribute_global_event_reference",
"message": "You are referencing `globalThis.onvisibilitychange`. Did you forget to declare a variable with that name?",
"start": {
"column": 17,
"line": 6
},
"end": {
"column": 37,
"line": 6
}
},
{
"code": "attribute_global_event_reference",
"message": "You are referencing `globalThis.onfocus`. Did you forget to declare a variable with that name?",
"start": {
"column": 13,
"line": 7
},
"end": {
"column": 22,
"line": 7
}
}
]