UNPKG

lit-analyzer

Version:

CLI that type checks bindings in lit-html templates

88 lines (87 loc) 4.89 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var ts_simple_type_1 = require("ts-simple-type"); var constants_js_1 = require("../analyze/constants.js"); var html_node_attr_assignment_types_js_1 = require("../analyze/types/html-node/html-node-attr-assignment-types.js"); 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"); var is_assignable_in_attribute_binding_js_1 = require("./util/type/is-assignable-in-attribute-binding.js"); var is_assignable_to_type_js_1 = require("./util/type/is-assignable-to-type.js"); /** * This rule validates that you are not binding a boolean type in an attribute binding * This would result in binding the string 'true' or 'false' and a '?' binding should be used instead. */ var rule = { id: "no-boolean-in-attribute-binding", meta: { priority: "medium" }, visitHtmlAssignment: function (assignment, context) { // Don't validate boolean attribute bindings. if (assignment.kind === html_node_attr_assignment_types_js_1.HtmlNodeAttrAssignmentKind.BOOLEAN) return; // Only validate attribute bindings. var htmlAttr = assignment.htmlAttr; if (htmlAttr.kind !== html_node_attr_types_js_1.HtmlNodeAttrKind.ATTRIBUTE) return; var _a = (0, extract_binding_types_js_1.extractBindingTypes)(assignment, context), typeA = _a.typeA, typeB = _a.typeB; // Return early if the attribute is like 'required=""' because this is assignable to boolean. if (typeB.kind === "STRING_LITERAL" && typeB.value.length === 0) return; // Check that typeB is not of any|unknown type and typeB is assignable to boolean. // Report a diagnostic if typeB is assignable to boolean type because this would result in binding the boolean coerced to string. if (!(0, ts_simple_type_1.isAssignableToSimpleTypeKind)(typeB, ["ANY", "UNKNOWN"]) && (0, is_assignable_to_type_js_1.isAssignableToType)({ typeA: { kind: "BOOLEAN" }, typeB: typeB }, context)) { // Don't emit error if typeB is assignable to typeA with string coercion. if ((0, is_assignable_to_type_js_1.isAssignableToType)({ typeA: typeA, typeB: typeB }, context, { isAssignable: is_assignable_in_attribute_binding_js_1.isAssignableToTypeWithStringCoercion })) { return; } context.report({ location: (0, range_util_js_1.rangeFromHtmlNodeAttr)(htmlAttr), message: "The value being assigned is a boolean type, but you are not using a boolean binding.", fixMessage: "Change to boolean binding?", fix: function () { var newName = "".concat(constants_js_1.LIT_HTML_BOOLEAN_ATTRIBUTE_MODIFIER).concat(htmlAttr.name); return { message: "Change to '".concat(newName, "'"), actions: [ { kind: "changeAttributeName", htmlAttr: htmlAttr, newName: newName } ] }; } }); } // Check that typeA is not of any|unknown type and typeA is assignable to boolean. // Report a diagnostic if typeA is assignable to boolean type because then // we should probably be using a boolean binding instead of an attribute binding. else if (!(0, ts_simple_type_1.isAssignableToSimpleTypeKind)(typeA, ["ANY", "UNKNOWN"]) && (0, is_assignable_to_type_js_1.isAssignableToType)({ typeA: { kind: "BOOLEAN" }, typeB: typeA }, context)) { context.report({ location: (0, range_util_js_1.rangeFromHtmlNodeAttr)(htmlAttr), message: "The '".concat(htmlAttr.name, "' attribute is of boolean type but you are not using a boolean binding."), fixMessage: "Change to boolean binding?", fix: function () { var newName = "".concat(constants_js_1.LIT_HTML_BOOLEAN_ATTRIBUTE_MODIFIER).concat(htmlAttr.name); return { message: "Change to '".concat(newName, "'"), actions: [ { kind: "changeAttributeName", htmlAttr: htmlAttr, newName: newName } ] }; } }); } } }; exports.default = rule;