UNPKG

alm

Version:

The best IDE for TypeScript

198 lines (197 loc) 8.86 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var events_1 = require("../../common/events"); var utils_1 = require("../../common/utils"); var equal = require("deep-equal"); // What we use to identify a unique error var errorKey = function (error) { return error.from.line + ":" + error.from.ch + ":" + error.message; }; /** * Maintains the list of errors that have been encountered, * and notifies anyone who is concerned of updated values */ var ErrorsCache = /** @class */ (function () { function ErrorsCache() { var _this = this; /** * When a cache boots up (e.g. server restart). Its good to know if its an initial errors delta * If so the client might want to clear all previous errors */ this.initial = true; /** * Event that can be wired up to sync one error cache with another */ this.errorsDelta = new events_1.TypedEvent(); /** * You can wire up an errors Delta from one cache to this one. */ this.applyDelta = function (delta) { // Added: Object.keys(delta.added).forEach(function (fp) { if (!_this._errorsByFilePath[fp]) _this._errorsByFilePath[fp] = delta.added[fp]; else _this._errorsByFilePath[fp] = _this._errorsByFilePath[fp].concat(delta.added[fp]); }); // Removed: Object.keys(delta.removed).forEach(function (fp) { var removedErrorsMap = utils_1.createMapByKey(delta.removed[fp], errorKey); _this._errorsByFilePath[fp] = (_this._errorsByFilePath[fp] || []).filter(function (e) { return !removedErrorsMap[errorKey(e)]; }); }); _this.sendErrors(); }; /** * DELTA MAINTAINANCE */ this.lastErrorsByFilePath = {}; /** * current errors */ this._errorsByFilePath = {}; /** * debounced as constantly sending errors quickly degrades the web experience */ this.sendErrors = utils_1.debounce(function () { // Create a delta var oldErrorsByFilePath = _this.lastErrorsByFilePath; var newErrorsByFilePath = _this._errorsByFilePath; var delta = { added: {}, removed: {}, initial: _this.initial, }; _this.initial = false; // Added: Object.keys(newErrorsByFilePath).forEach(function (filePath) { var newErrors = newErrorsByFilePath[filePath]; // All new if (!oldErrorsByFilePath[filePath]) { delta.added[filePath] = newErrors; } else { var oldErrors = oldErrorsByFilePath[filePath]; var oldErrorMap_1 = utils_1.createMapByKey(oldErrors, errorKey); newErrors.forEach(function (ne) { var newErrorKey = errorKey(ne); if (!oldErrorMap_1[newErrorKey]) { if (!delta.added[filePath]) delta.added[filePath] = []; delta.added[filePath].push(ne); } }); } }); // Removed: Object.keys(oldErrorsByFilePath).forEach(function (filePath) { var oldErrors = oldErrorsByFilePath[filePath]; // All gone if (!newErrorsByFilePath[filePath]) { delta.removed[filePath] = oldErrors; } else { var newErrors = newErrorsByFilePath[filePath]; var newErrorMap_1 = utils_1.createMapByKey(newErrors, errorKey); oldErrors.forEach(function (oe) { var oldErrorKey = errorKey(oe); if (!newErrorMap_1[oldErrorKey]) { if (!delta.removed[filePath]) delta.removed[filePath] = []; delta.removed[filePath].push(oe); } }); } }); // Send out the delta _this.errorsDelta.emit(delta); // Preserve for future delta _this.lastErrorsByFilePath = {}; Object.keys(_this._errorsByFilePath).map(function (fp) { return _this.lastErrorsByFilePath[fp] = _this._errorsByFilePath[fp]; }); }, 250); /** The pased errors are considered *the only current* errors for the filePath */ this.setErrorsByFilePaths = function (filePaths, errors) { var somethingNew = false; // For all found errors add them var errorsByFile = utils_1.createMapByKey(errors, function (e) { return e.filePath; }); for (var filePath in errorsByFile) { if (!equal(_this._errorsByFilePath[filePath], errorsByFile[filePath])) { somethingNew = true; _this._errorsByFilePath[filePath] = errorsByFile[filePath]; } } // For not found errors clear them for (var _i = 0, filePaths_1 = filePaths; _i < filePaths_1.length; _i++) { var filePath = filePaths_1[_i]; if (!errorsByFile[filePath] && (_this._errorsByFilePath[filePath] && _this._errorsByFilePath[filePath].length)) { somethingNew = true; _this._errorsByFilePath[filePath] = []; } } if (somethingNew) { _this.sendErrors(); } }; /** * * Sending massive error lists *constantly* can quickly degrade the web experience * - only send 50 errors per file or 200+ errors total */ this.getErrorsLimited = function () { var limitedCopy = {}; var total = 0; for (var filePath in _this._errorsByFilePath) { var errors = _this._errorsByFilePath[filePath]; if (errors.length > 50) errors = errors.slice(0, 50); limitedCopy[filePath] = errors; total += errors.length; if (total > 200) break; } var totalCount = Object.keys(_this._errorsByFilePath) .map(function (x) { return _this._errorsByFilePath[x].length; }) .reduce(function (acc, i) { return acc + i; }, 0); return { errorsByFilePath: limitedCopy, totalCount: totalCount, syncCount: total, tooMany: total !== totalCount }; }; /** * Get/Set all the errors for an initial sync between error caches */ this.getErrors = function () { return _this._errorsByFilePath; }; this.setErrors = function (errorsByFilePath) { return _this._errorsByFilePath = errorsByFilePath; }; /** Only used for debugging */ this.debugGetErrorsFlattened = function () { return Object.keys(_this._errorsByFilePath) .map(function (x) { return _this._errorsByFilePath[x]; }) .reduce(function (acc, x) { return acc.concat(x); }, []); }; /** * Clear all errors. Resets the cache. * * Also good or an initial sync. * e.g. when the socket server reboots * it wants to clear any errors that any connected clicks might have */ this.clearErrors = function () { _this._errorsByFilePath = {}; _this.sendErrors(); }; /** Utility to provide a semantic name to *clearing errors* */ this.clearErrorsForFilePath = function (filePath) { _this._errorsByFilePath[filePath] = []; _this.sendErrors(); }; /** If a source goes down (crashes) and it comes back we want to clear any knowledge of previous errors by source */ this.clearErrorsForSource = function (source) { var errorsByFilePath = Object.create(null); for (var filePath in _this._errorsByFilePath) { var errors = _this._errorsByFilePath[filePath]; errorsByFilePath[filePath] = errors.filter(function (e) { return e.source !== source; }); } _this._errorsByFilePath = errorsByFilePath; _this.sendErrors(); }; /** Utility to query */ this.getErrorsForFilePath = function (filePath) { return _this._errorsByFilePath[filePath] || []; }; } return ErrorsCache; }()); exports.ErrorsCache = ErrorsCache;