fix: raising an error when mixing both old and new event-handling syntaxes

pull/11295/head
Caique Torres 2 years ago
parent f1986da755
commit 3f5616c141

@ -172,6 +172,10 @@
> `let:` directive at invalid position
## mixed_event_handler_syntaxes
> Mixing old (on:%name%) and new syntaxes for event handling is not allowed. Use only the on%name% syntax.
## node_invalid_placement
> %thing% is invalid inside <%parent%>

@ -918,6 +918,16 @@ export function let_directive_invalid_placement(node) {
e(node, "let_directive_invalid_placement", "`let:` directive at invalid position");
}
/**
* Mixing old (on:%name%) and new syntaxes for event handling is not allowed. Use only the on%name% syntax.
* @param {null | number | NodeLike} node
* @param {string} name
* @returns {never}
*/
export function mixed_event_handler_syntaxes(node, name) {
e(node, "mixed_event_handler_syntaxes", `Mixing old (on:${name}) and new syntaxes for event handling is not allowed. Use only the on${name} syntax.`);
}
/**
* %thing% is invalid inside <%parent%>
* @param {null | number | NodeLike} node

@ -372,6 +372,8 @@ export function analyze_component(root, source, options) {
uses_render_tags: false,
needs_context: false,
needs_props: false,
event_directive_node: null,
uses_event_attributes: false,
custom_element: options.customElementOptions ?? options.customElement,
inject_styles: options.css === 'injected' || options.customElement,
accessors: options.customElement
@ -1153,6 +1155,8 @@ const common_visitors = {
});
if (is_event_attribute(node)) {
context.state.analysis.uses_event_attributes = true;
const expression = node.value[0].expression;
const delegated_event = get_delegated_event(node.name.slice(2), expression, context);
@ -1286,6 +1290,13 @@ const common_visitors = {
context.next();
},
OnDirective(node, { state, path, next }) {
const parent = path.at(-1);
if (parent?.type === 'SvelteElement' || parent?.type === 'RegularElement') {
state.analysis.event_directive_node ??= node;
}
next();
},
BindDirective(node, context) {
let i = context.path.length;
while (i--) {

@ -8,6 +8,7 @@ import * as e from '../../errors.js';
import {
extract_identifiers,
get_parent,
is_event_attribute,
is_expression_attribute,
is_text_attribute,
object,
@ -104,6 +105,18 @@ function validate_element(node, context) {
for (const attribute of node.attributes) {
if (attribute.type === 'Attribute') {
const parent_type = node.type;
// Don't warn on component events; these might not be under the author's control so the warning would be unactionable
if (
(parent_type === 'RegularElement' || parent_type === 'SvelteElement') &&
is_event_attribute(attribute) &&
context.state.analysis.event_directive_node
) {
const { event_directive_node } = context.state.analysis;
e.mixed_event_handler_syntaxes(event_directive_node, event_directive_node.name);
}
const is_expression = is_expression_attribute(attribute);
if (context.state.analysis.runes && is_expression) {
@ -1204,10 +1217,13 @@ export const validation_runes = merge(validation, a11y_validators, {
w.slot_element_deprecated(node);
}
},
OnDirective(node, { path }) {
OnDirective(node, { state, path }) {
const parent_type = path.at(-1)?.type;
// Don't warn on component events; these might not be under the author's control so the warning would be unactionable
if (parent_type === 'RegularElement' || parent_type === 'SvelteElement') {
if (state.analysis.uses_event_attributes) {
e.mixed_event_handler_syntaxes(node, node.name);
}
w.event_directive_deprecated(node, node.name);
}
},

@ -2,6 +2,7 @@ import type {
Binding,
Css,
Fragment,
OnDirective,
RegularElement,
SlotElement,
SvelteElement,
@ -59,6 +60,8 @@ export interface ComponentAnalysis extends Analysis {
uses_render_tags: boolean;
needs_context: boolean;
needs_props: boolean;
event_directive_node: OnDirective | null;
uses_event_attributes: boolean;
custom_element: boolean | SvelteOptions['customElement'];
/** If `true`, should append styles through JavaScript */
inject_styles: boolean;

@ -0,0 +1,14 @@
[
{
"code": "mixed_event_handler_syntaxes",
"message": "Mixing old (on:click) and new syntaxes for event handling is not allowed. Use only the onclick syntax.",
"start": {
"line": 11,
"column": 8
},
"end": {
"line": 11,
"column": 22
}
}
]

@ -0,0 +1,11 @@
<script>
let { foo } = $props();
</script>
<!-- ok -->
<button onclick={foo}>click me</button>
<Button on:click={foo}>click me</Button>
<Button on:click={foo}>click me</Button>
<!-- error -->
<button on:click={foo}>click me</button>
Loading…
Cancel
Save