lit-analyzer
Version:
CLI that type checks bindings in lit-html templates
116 lines (115 loc) • 5.82 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.getDirective = void 0;
var ts_simple_type_1 = require("ts-simple-type");
var html_node_attr_assignment_types_js_1 = require("../../../analyze/types/html-node/html-node-attr-assignment-types.js");
var general_util_js_1 = require("../../../analyze/util/general-util.js");
var remove_undefined_from_type_js_1 = require("../type/remove-undefined-from-type.js");
var is_lit_directive_js_1 = require("./is-lit-directive.js");
function getDirective(assignment, context) {
var ts = context.ts, program = context.program;
var checker = program.getTypeChecker();
if (assignment.kind !== html_node_attr_assignment_types_js_1.HtmlNodeAttrAssignmentKind.EXPRESSION)
return;
// Type check lit-html directives
if (ts.isCallExpression(assignment.expression)) {
var functionName = assignment.expression.expression.getText();
var args_1 = Array.from(assignment.expression.arguments);
switch (functionName) {
case "ifDefined": {
// Example: html`<img src="${ifDefined(imageUrl)}">`;
// Take the argument to ifDefined and remove undefined from the type union (if possible).
// This new type becomes the actual type of the expression
var actualType = (0, general_util_js_1.lazy)(function () {
if (args_1.length >= 1) {
var returnType = (0, ts_simple_type_1.toSimpleType)(checker.getTypeAtLocation(args_1[0]), checker);
return (0, remove_undefined_from_type_js_1.removeUndefinedFromType)(returnType);
}
return undefined;
});
return {
kind: "ifDefined",
actualType: actualType,
args: args_1
};
}
case "live": {
// Example: html`<input .value=${live(x)}>`
// The actual type will be the type of the first argument to live
var actualType = (0, general_util_js_1.lazy)(function () {
if (args_1.length >= 1) {
return (0, ts_simple_type_1.toSimpleType)(checker.getTypeAtLocation(args_1[0]), checker);
}
return undefined;
});
return {
kind: "live",
actualType: actualType,
args: args_1
};
}
case "guard": {
// Example: html`<img src="${guard([imageUrl], () => Math.random() > 0.5 ? imageUrl : "nothing.png")}>`;
// The return type of the function becomes the actual type of the expression
var actualType = (0, general_util_js_1.lazy)(function () {
if (args_1.length >= 2) {
var returnFunctionType = (0, ts_simple_type_1.toSimpleType)(checker.getTypeAtLocation(args_1[1]), checker);
if ("call" in returnFunctionType && returnFunctionType.call != null) {
returnFunctionType = returnFunctionType.call;
}
if (returnFunctionType.kind === "FUNCTION") {
return returnFunctionType.returnType;
}
}
return undefined;
});
return {
kind: "guard",
actualType: actualType,
args: args_1
};
}
case "classMap":
case "styleMap":
return {
kind: functionName,
actualType: function () { return ({ kind: "STRING" }); },
args: args_1
};
case "unsafeHTML":
case "unsafeSVG":
case "cache":
case "repeat":
case "templateContent":
case "asyncReplace":
case "asyncAppend":
return {
kind: functionName,
args: args_1
};
default:
// Grab the type of the expression and get a SimpleType
if (assignment.kind === html_node_attr_assignment_types_js_1.HtmlNodeAttrAssignmentKind.EXPRESSION) {
var typeB_1 = (0, ts_simple_type_1.toSimpleType)(checker.getTypeAtLocation(assignment.expression), checker);
if ((0, is_lit_directive_js_1.isLitDirective)(typeB_1)) {
// Factories can mark which parameters might be assigned to the property with the generic type in DirectiveFn<T>
// Here we get the actual type of the directive if the it is a generic directive with type. Example: DirectiveFn<string>
// Read more: https://github.com/Polymer/lit-html/pull/1151
var actualType = typeB_1.kind === "GENERIC_ARGUMENTS" && typeB_1.target.name === "DirectiveFn" && typeB_1.typeArguments.length > 0 // && typeB.typeArguments[0].kind !== "UNKNOWN"
? function () { return typeB_1.typeArguments[0]; }
: undefined;
// Now we have an unknown (user defined) directive.
return {
kind: {
name: functionName
},
args: args_1,
actualType: actualType
};
}
}
}
}
return;
}
exports.getDirective = getDirective;
;