UNPKG

lit-analyzer

Version:

CLI that type checks bindings in lit-html templates

61 lines (60 loc) 2.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var ts_simple_type_1 = require("ts-simple-type"); var html_node_attr_types_js_1 = require("../analyze/types/html-node/html-node-attr-types.js"); var range_util_js_1 = require("../analyze/util/range-util.js"); var extract_binding_types_js_1 = require("./util/type/extract-binding-types.js"); /** * This rule validates that only callable types are used within event binding expressions. * This rule catches typos like: @click="onClick()" */ var rule = { id: "no-noncallable-event-binding", meta: { priority: "high" }, visitHtmlAssignment: function (assignment, context) { // Only validate event listener bindings. var htmlAttr = assignment.htmlAttr; if (htmlAttr.kind !== html_node_attr_types_js_1.HtmlNodeAttrKind.EVENT_LISTENER) return; var typeB = (0, extract_binding_types_js_1.extractBindingTypes)(assignment, context).typeB; // Make sure that the expression given to the event listener binding a function or an object with "handleEvent" property. if (!isTypeBindableToEventListener(typeB)) { context.report({ location: (0, range_util_js_1.rangeFromHtmlNodeAttr)(htmlAttr), message: "You are setting up an event listener with a non-callable type '".concat((0, ts_simple_type_1.typeToString)(typeB), "'") }); } } }; exports.default = rule; /** * Returns if this type can be used in a event listener binding * @param type */ function isTypeBindableToEventListener(type) { // Return "true" if the type has a call signature if ("call" in type && type.call != null) { return true; } // Callable types can be used in the binding if ((0, ts_simple_type_1.isAssignableToSimpleTypeKind)(type, ["FUNCTION", "METHOD", "UNKNOWN"], { matchAny: true })) { return true; } return (0, ts_simple_type_1.validateType)(type, function (simpleType) { switch (simpleType.kind) { // Object types with attributes for the setup function of the event listener can be used case "OBJECT": case "INTERFACE": { // The "handleEvent" property must be present var handleEventFunction = simpleType.members != null ? simpleType.members.find(function (m) { return m.name === "handleEvent"; }) : undefined; // The "handleEvent" property must be callable if (handleEventFunction != null) { return isTypeBindableToEventListener(handleEventFunction.type); } } } return undefined; }); }