add some more modifier validation tests

pull/1819/head
Rich Harris 6 years ago
parent 769e03296f
commit aa203973e0

@ -14,6 +14,7 @@ import mapChildren from './shared/mapChildren';
import { dimensions } from '../../utils/patterns';
import fuzzymatch from '../validate/utils/fuzzymatch';
import Ref from './Ref';
import list from '../../utils/list';
const svg = /^(?:altGlyph|altGlyphDef|altGlyphItem|animate|animateColor|animateMotion|animateTransform|circle|clipPath|color-profile|cursor|defs|desc|discard|ellipse|feBlend|feColorMatrix|feComponentTransfer|feComposite|feConvolveMatrix|feDiffuseLighting|feDisplacementMap|feDistantLight|feDropShadow|feFlood|feFuncA|feFuncB|feFuncG|feFuncR|feGaussianBlur|feImage|feMerge|feMergeNode|feMorphology|feOffset|fePointLight|feSpecularLighting|feSpotLight|feTile|feTurbulence|filter|font|font-face|font-face-format|font-face-name|font-face-src|font-face-uri|foreignObject|g|glyph|glyphRef|hatch|hatchpath|hkern|image|line|linearGradient|marker|mask|mesh|meshgradient|meshpatch|meshrow|metadata|missing-glyph|mpath|path|pattern|polygon|polyline|radialGradient|rect|set|solidcolor|stop|switch|symbol|text|textPath|tref|tspan|unknown|use|view|vkern)$/;
@ -228,6 +229,7 @@ export default class Element extends Node {
this.validateAttributes();
this.validateBindings();
this.validateContent();
this.validateEventHandlers();
}
validateAttributes() {
@ -563,6 +565,58 @@ export default class Element extends Node {
}
}
validateEventHandlers() {
const { component } = this;
const validModifiers = new Set([
'preventDefault',
'stopPropagation',
'capture',
'once',
'passive'
]);
const passiveEvents = new Set([
'wheel',
'touchstart',
'touchmove',
'touchend',
'touchcancel'
]);
this.handlers.forEach(handler => {
handler.modifiers.forEach(modifier => {
if (!validModifiers.has(modifier)) {
component.error(handler, {
code: 'invalid-event-modifier',
message: `Valid event modifiers are ${list([...validModifiers])}`
});
}
if (modifier === 'passive') {
if (passiveEvents.has(handler.name)) {
const usesEvent = (
handler.callee.name === 'event' ||
handler.args.some(x => x.usesEvent)
);
if (!usesEvent) {
component.warn(handler, {
code: 'redundant-event-modifier',
message: `Touch event handlers that don't use the 'event' object are passive by default`
});
}
} else {
component.warn(handler, {
code: 'redundant-event-modifier',
message: `The passive modifier only works with wheel and touch events`
});
}
}
});
});
}
getStaticAttributeValue(name: string) {
const attribute = this.attributes.find(
(attr: Attribute) => attr.type === 'Attribute' && attr.name.toLowerCase() === name

@ -9,6 +9,7 @@ const validBuiltins = new Set(['set', 'fire', 'destroy']);
export default class EventHandler extends Node {
name: string;
modifiers: Set<string>;
dependencies: Set<string>;
expression: Node;
callee: any; // TODO
@ -26,6 +27,8 @@ export default class EventHandler extends Node {
super(component, parent, scope, info);
this.name = info.name;
this.modifiers = new Set(info.modifiers);
component.used.events.add(this.name);
this.dependencies = new Set();

@ -57,11 +57,12 @@ export default class Expression {
component: Component;
node: any;
snippet: string;
usesContext: boolean;
references: Set<string>;
dependencies: Set<string>;
usesContext = false;
usesEvent = false;
thisReferences: Array<{ start: number, end: number }>;
constructor(component, parent, scope, info) {
@ -77,8 +78,6 @@ export default class Expression {
this.snippet = `[✂${info.start}-${info.end}✂]`;
this.usesContext = false;
const dependencies = new Set();
const { code, helpers } = component;
@ -109,7 +108,12 @@ export default class Expression {
if (isReference(node, parent)) {
const { name, nodes } = flattenReference(node);
if (currentScope.has(name) || (name === 'event' && isEventHandler)) return;
if (name === 'event' && isEventHandler) {
expression.usesEvent = true;
return;
}
if (currentScope.has(name)) return;
if (component.helpers.has(name)) {
let object = node;

@ -25,8 +25,9 @@ const DIRECTIVES: Record<string, {
EventHandler: {
names: ['on'],
attribute(start, end, type, name, expression) {
return { start, end, type, name, expression };
attribute(start, end, type, lhs, expression) {
const [name, ...modifiers] = lhs.split('|');
return { start, end, type, name, modifiers, expression };
},
allowedExpressionTypes: ['CallExpression'],
error: 'Expected a method call'

@ -1,6 +1,6 @@
[{
"message": "Valid event modifiers are stopPropagation, preventDefault, capture, once, passive.",
"code": "invalid-event-modifiers",
"message": "Valid event modifiers are preventDefault, stopPropagation, capture, once or passive",
"code": "invalid-event-modifier",
"start": {
"line": 1,
"column": 8,

@ -0,0 +1,16 @@
<button on:click|passive="handleClick()"></button>
<div on:touchstart|passive="handleTouchstart()"></div>
<script>
export default {
methods: {
handleTouchstart() {
// ...
},
handleClick() {
// ...
}
}
};
</script>

@ -0,0 +1,32 @@
[
{
"message": "The passive modifier only works with wheel and touch events",
"code": "redundant-event-modifier",
"start": {
"line": 1,
"column": 8,
"character": 8
},
"end": {
"line": 1,
"column": 40,
"character": 40
},
"pos": 8
},
{
"message": "Touch event handlers that don't use the 'event' object are passive by default",
"code": "redundant-event-modifier",
"start": {
"line": 2,
"column": 5,
"character": 56
},
"end": {
"line": 2,
"column": 47,
"character": 98
},
"pos": 56
}
]
Loading…
Cancel
Save