alm
Version:
The best IDE for TypeScript
198 lines (197 loc) • 8.86 kB
JavaScript
;
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;