UNPKG

lit-analyzer

Version:

CLI that type checks bindings in lit-html templates

358 lines (357 loc) 18.5 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DefaultLitAnalyzerContext = void 0; var tsMod = __importStar(require("typescript")); var web_component_analyzer_1 = require("web-component-analyzer"); var all_rules_js_1 = require("../rules/all-rules.js"); var constants_js_1 = require("./constants.js"); var get_built_in_html_collection_js_1 = require("./data/get-built-in-html-collection.js"); var get_user_config_html_collection_js_1 = require("./data/get-user-config-html-collection.js"); var lit_analyzer_config_js_1 = require("./lit-analyzer-config.js"); var lit_analyzer_logger_js_1 = require("./lit-analyzer-logger.js"); var convert_component_definitions_to_html_collection_js_1 = require("./parse/convert-component-definitions-to-html-collection.js"); var parse_dependencies_js_1 = require("./parse/parse-dependencies/parse-dependencies.js"); var rule_collection_js_1 = require("./rule-collection.js"); var default_analyzer_definition_store_js_1 = require("./store/definition-store/default-analyzer-definition-store.js"); var default_analyzer_dependency_store_js_1 = require("./store/dependency-store/default-analyzer-dependency-store.js"); var default_analyzer_document_store_js_1 = require("./store/document-store/default-analyzer-document-store.js"); var default_analyzer_html_store_js_1 = require("./store/html-store/default-analyzer-html-store.js"); var html_data_source_merged_js_1 = require("./store/html-store/html-data-source-merged.js"); var changed_source_file_iterator_js_1 = require("./util/changed-source-file-iterator.js"); var DefaultLitAnalyzerContext = /** @class */ (function () { function DefaultLitAnalyzerContext(handler) { this.handler = handler; this.componentSourceFileIterator = (0, changed_source_file_iterator_js_1.changedSourceFileIterator)(); this.hasAnalyzedSubclassExtensions = false; this._config = (0, lit_analyzer_config_js_1.makeConfig)({}); this._currentStartTime = Date.now(); this._currentTimeout = constants_js_1.MAX_RUNNING_TIME_PER_OPERATION; this._currentCancellationToken = undefined; this._hasRequestedCancellation = false; this._throwOnRequestedCancellation = false; this.htmlStore = new default_analyzer_html_store_js_1.DefaultAnalyzerHtmlStore(); this.dependencyStore = new default_analyzer_dependency_store_js_1.DefaultAnalyzerDependencyStore(); this.documentStore = new default_analyzer_document_store_js_1.DefaultAnalyzerDocumentStore(); this.definitionStore = new default_analyzer_definition_store_js_1.DefaultAnalyzerDefinitionStore(); this.logger = new lit_analyzer_logger_js_1.DefaultLitAnalyzerLogger(); // Add all HTML5 tags and attributes var builtInCollection = (0, get_built_in_html_collection_js_1.getBuiltInHtmlCollection)(); this.htmlStore.absorbCollection(builtInCollection, html_data_source_merged_js_1.HtmlDataSourceKind.BUILT_IN); } Object.defineProperty(DefaultLitAnalyzerContext.prototype, "ts", { get: function () { return this.handler.ts || tsMod; }, enumerable: false, configurable: true }); Object.defineProperty(DefaultLitAnalyzerContext.prototype, "program", { get: function () { return this.handler.getProgram(); }, enumerable: false, configurable: true }); Object.defineProperty(DefaultLitAnalyzerContext.prototype, "project", { get: function () { return this.handler.getProject != null ? this.handler.getProject() : undefined; }, enumerable: false, configurable: true }); Object.defineProperty(DefaultLitAnalyzerContext.prototype, "config", { get: function () { return this._config; }, enumerable: false, configurable: true }); Object.defineProperty(DefaultLitAnalyzerContext.prototype, "currentRunningTime", { get: function () { return Date.now() - this._currentStartTime; }, enumerable: false, configurable: true }); Object.defineProperty(DefaultLitAnalyzerContext.prototype, "isCancellationRequested", { get: function () { var _a; if (this._hasRequestedCancellation) { return true; } if (this._currentCancellationToken == null) { // Never cancel if "cancellation token" is not present // This means that we are in a CLI context, and are willing to wait for the operation to finish for correctness reasons return false; } if ((_a = this._currentCancellationToken) === null || _a === void 0 ? void 0 : _a.isCancellationRequested()) { if (!this._hasRequestedCancellation) { this.logger.error("Cancelling current operation because project host has requested cancellation"); } this._hasRequestedCancellation = true; } if (this.currentRunningTime > this._currentTimeout) { if (!this._hasRequestedCancellation) { this.logger.error("Cancelling current operation because it has been running for more than ".concat(this._currentTimeout, "ms (").concat(this.currentRunningTime, "ms)")); } this._hasRequestedCancellation = true; } // Throw if necessary if (this._hasRequestedCancellation && this._throwOnRequestedCancellation) { throw new this.ts.OperationCanceledException(); } return this._hasRequestedCancellation; }, enumerable: false, configurable: true }); Object.defineProperty(DefaultLitAnalyzerContext.prototype, "currentFile", { get: function () { if (this._currentFile == null) { throw new Error("Current file is not set"); } return this._currentFile; }, enumerable: false, configurable: true }); Object.defineProperty(DefaultLitAnalyzerContext.prototype, "rules", { get: function () { var _a; if (this._rules == null) { this._rules = new rule_collection_js_1.RuleCollection(); (_a = this._rules).push.apply(_a, __spreadArray([], __read(all_rules_js_1.ALL_RULES), false)); } return this._rules; }, enumerable: false, configurable: true }); DefaultLitAnalyzerContext.prototype.setContextBase = function (_a) { var _b; var file = _a.file, timeout = _a.timeout, throwOnCancellation = _a.throwOnCancellation; this._currentFile = file; this._currentStartTime = Date.now(); this._currentTimeout = timeout !== null && timeout !== void 0 ? timeout : constants_js_1.MAX_RUNNING_TIME_PER_OPERATION; this._currentCancellationToken = (_b = this.project) === null || _b === void 0 ? void 0 : _b.getCancellationToken(); this._throwOnRequestedCancellation = throwOnCancellation !== null && throwOnCancellation !== void 0 ? throwOnCancellation : false; this._hasRequestedCancellation = false; }; DefaultLitAnalyzerContext.prototype.updateConfig = function (config) { this._config = config; this.logger.level = (function () { switch (config.logging) { case "off": return lit_analyzer_logger_js_1.LitAnalyzerLoggerLevel.OFF; case "error": return lit_analyzer_logger_js_1.LitAnalyzerLoggerLevel.ERROR; case "warn": return lit_analyzer_logger_js_1.LitAnalyzerLoggerLevel.WARN; case "debug": return lit_analyzer_logger_js_1.LitAnalyzerLoggerLevel.DEBUG; case "verbose": return lit_analyzer_logger_js_1.LitAnalyzerLoggerLevel.VERBOSE; default: return lit_analyzer_logger_js_1.LitAnalyzerLoggerLevel.OFF; } })(); // Add user configured HTML5 collection var collection = (0, get_user_config_html_collection_js_1.getUserConfigHtmlCollection)(config); this.htmlStore.absorbCollection(collection, html_data_source_merged_js_1.HtmlDataSourceKind.USER); }; DefaultLitAnalyzerContext.prototype.updateDependencies = function (file) { this.findDependenciesInFile(file); }; DefaultLitAnalyzerContext.prototype.updateComponents = function (file) { this.findInvalidatedComponents(); this.analyzeSubclassExtensions(); }; Object.defineProperty(DefaultLitAnalyzerContext.prototype, "checker", { get: function () { return this.program.getTypeChecker(); }, enumerable: false, configurable: true }); DefaultLitAnalyzerContext.prototype.findInvalidatedComponents = function () { var e_1, _a, e_2, _b; var _this = this; var startTime = Date.now(); var seenFiles = new Set(); var invalidatedFiles = new Set(); var getRunningTime = function () { return Date.now() - startTime; }; try { // Find components in all changed files for (var _c = __values(this.componentSourceFileIterator(this.program.getSourceFiles())), _d = _c.next(); !_d.done; _d = _c.next()) { var sourceFile = _d.value; if (this.isCancellationRequested) { break; } seenFiles.add(sourceFile); // All components definitions that use this file must be invidalited this.definitionStore.getDefinitionsWithDeclarationInFile(sourceFile).forEach(function (definition) { var sf = _this.program.getSourceFile(definition.sourceFile.fileName); if (sf != null) { invalidatedFiles.add(sf); } }); this.logger.debug("Analyzing components in ".concat(sourceFile.fileName, " (changed) (").concat(getRunningTime(), "ms total)")); this.findComponentsInFile(sourceFile); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_d && !_d.done && (_a = _c.return)) _a.call(_c); } finally { if (e_1) throw e_1.error; } } try { for (var invalidatedFiles_1 = __values(invalidatedFiles), invalidatedFiles_1_1 = invalidatedFiles_1.next(); !invalidatedFiles_1_1.done; invalidatedFiles_1_1 = invalidatedFiles_1.next()) { var sourceFile = invalidatedFiles_1_1.value; if (this.isCancellationRequested) { break; } if (!seenFiles.has(sourceFile)) { seenFiles.add(sourceFile); this.logger.debug("Analyzing components in ".concat(sourceFile.fileName, " (invalidated) (").concat(getRunningTime(), "ms total)")); this.findComponentsInFile(sourceFile); } } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (invalidatedFiles_1_1 && !invalidatedFiles_1_1.done && (_b = invalidatedFiles_1.return)) _b.call(invalidatedFiles_1); } finally { if (e_2) throw e_2.error; } } this.logger.verbose("Analyzed ".concat(seenFiles.size, " files (").concat(invalidatedFiles.size, " invalidated) in ").concat(getRunningTime(), "ms")); }; DefaultLitAnalyzerContext.prototype.findComponentsInFile = function (sourceFile) { var _a, _b, _c, _d, _e, _f; var isDefaultLibrary = this.program.isSourceFileDefaultLibrary(sourceFile); var isExternalLibrary = this.program.isSourceFileFromExternalLibrary(sourceFile); // Only analyzing specific default libs of interest can save us up to 500ms in startup time if ((isDefaultLibrary && sourceFile.fileName.match(/(lib\.dom\.d\.ts)/) == null) || (isExternalLibrary && sourceFile.fileName.match(/(@types\/node)/) != null)) { return; } var analyzeResult = (0, web_component_analyzer_1.analyzeSourceFile)(sourceFile, { program: this.program, ts: this.ts, config: { features: ["event", "member", "slot", "csspart", "cssproperty"], analyzeGlobalFeatures: !isDefaultLibrary, analyzeDefaultLib: true, analyzeDependencies: true, analyzeAllDeclarations: false, excludedDeclarationNames: ["HTMLElement"] } }); var reg = isDefaultLibrary ? html_data_source_merged_js_1.HtmlDataSourceKind.BUILT_IN_DECLARED : html_data_source_merged_js_1.HtmlDataSourceKind.DECLARED; // Forget var existingResult = this.definitionStore.getAnalysisResultForFile(sourceFile); if (existingResult != null) { this.htmlStore.forgetCollection({ tags: existingResult.componentDefinitions.map(function (d) { return d.tagName; }), global: { events: (_a = existingResult.globalFeatures) === null || _a === void 0 ? void 0 : _a.events.map(function (e) { return e.name; }), slots: (_b = existingResult.globalFeatures) === null || _b === void 0 ? void 0 : _b.slots.map(function (s) { return s.name || ""; }), cssParts: (_c = existingResult.globalFeatures) === null || _c === void 0 ? void 0 : _c.cssParts.map(function (s) { return s.name || ""; }), cssProperties: (_d = existingResult.globalFeatures) === null || _d === void 0 ? void 0 : _d.cssProperties.map(function (s) { return s.name || ""; }), attributes: (_e = existingResult.globalFeatures) === null || _e === void 0 ? void 0 : _e.members.filter(function (m) { return m.kind === "attribute"; }).map(function (m) { return m.attrName || ""; }), properties: (_f = existingResult.globalFeatures) === null || _f === void 0 ? void 0 : _f.members.filter(function (m) { return m.kind === "property"; }).map(function (m) { return m.propName || ""; }) } }, reg); this.definitionStore.forgetAnalysisResultForFile(sourceFile); } // Absorb this.definitionStore.absorbAnalysisResult(sourceFile, analyzeResult); var htmlCollection = (0, convert_component_definitions_to_html_collection_js_1.convertAnalyzeResultToHtmlCollection)(analyzeResult, { checker: this.checker, addDeclarationPropertiesAsAttributes: this.program.isSourceFileFromExternalLibrary(sourceFile) }); this.htmlStore.absorbCollection(htmlCollection, reg); }; DefaultLitAnalyzerContext.prototype.analyzeSubclassExtensions = function () { if (this.hasAnalyzedSubclassExtensions) return; var result = (0, web_component_analyzer_1.analyzeHTMLElement)(this.program, this.ts); if (result != null) { var extension = (0, convert_component_definitions_to_html_collection_js_1.convertComponentDeclarationToHtmlTag)(result, undefined, { checker: this.checker }); this.htmlStore.absorbSubclassExtension("HTMLElement", extension); this.hasAnalyzedSubclassExtensions = true; } }; DefaultLitAnalyzerContext.prototype.findDependenciesInFile = function (file) { if ((0, lit_analyzer_config_js_1.isRuleDisabled)(this.config, "no-missing-import")) return; // Build a graph of component dependencies var res = (0, parse_dependencies_js_1.parseDependencies)(file, this); this.dependencyStore.absorbComponentDefinitionsForFile(file, res); }; return DefaultLitAnalyzerContext; }()); exports.DefaultLitAnalyzerContext = DefaultLitAnalyzerContext;