blob: b94ab9941d3ef31434cde3f6945518b16cf379a2 [file] [log] [blame]
// Copyright 2009 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Class to receive errors found by the checkers.
*/
goog.provide('bidichecker.ErrorCollector');
goog.require('bidichecker.Error');
goog.require('bidichecker.Filter');
goog.require('bidichecker.FrameStack');
goog.require('bidichecker.utils');
goog.require('goog.array');
/**
* Class that collects errors found by the checkers and stores a filtered list.
* @param {!bidichecker.FrameStack} frameStack Stack of parent frames.
* @param {Array.<!bidichecker.Filter>=} opt_filters Error suppression filters.
* @constructor
*/
bidichecker.ErrorCollector = function(frameStack, opt_filters) {
/**
* Stack of parent frames of the current traversal location.
* @type {!bidichecker.FrameStack}
* @private
*/
this.frameStack_ = frameStack;
/**
* Filters to be applied to each error to determine whether to suppress it.
* @type {!Array.<!bidichecker.Filter>}
* @private
*/
this.filters_ = opt_filters || [];
/**
* Non-suppressed errors collected from the checkers.
* @type {!Array.<!bidichecker.Error>}
* @private
*/
this.errors_ = [];
};
/**
* If true, every non-suppressed error is thrown as an exception.
* @type {boolean}
* @private
*/
bidichecker.ErrorCollector.prototype.throwOnError_ = false;
/**
* Turns on throwing an exception for any non-suppressed error collected.
*/
bidichecker.ErrorCollector.prototype.SetThrowOnError = function() {
this.throwOnError_ = true;
};
/**
* @return {!Array.<!bidichecker.Error>} Non-suppressed errors collected from
* the checkers.
*/
bidichecker.ErrorCollector.prototype.getErrors = function() {
return this.errors_;
};
/**
* Adds an error to the collection if it passes the suppression filters.
* If {@code SetThrowOnError()} has been called, also throws an exception.
* @param {!bidichecker.Error} error The error to add.
* @param {Element=} opt_locationElement Element representing the error's
* location in the DOM, if applicable.
*/
bidichecker.ErrorCollector.prototype.addError = function(
error, opt_locationElement) {
// Copy the array of parent frames.
var locationElements = this.frameStack_.getFrames().slice(0);
if (opt_locationElement) {
locationElements.push(opt_locationElement);
}
// Accept an error if every filter fails to suppress it.
var isAccepted = goog.array.every(this.filters_, function(filter) {
return !filter.isSuppressed(error, locationElements);
});
if (isAccepted) {
var description = this.generateLocationDescription_(locationElements);
if (description != '') {
error.setLocationDescription(description);
}
this.errors_.push(error);
if (this.throwOnError_) {
// Add a newline to clarify where the error message ends in case the
// runtime environment appends a stack trace.
throw error.toString() + '\n';
}
}
};
/**
* Generates a textual description of the error location in the DOM.
* @param {Array.<!Element>} locationElements Elements representing the error
* location in the DOM, if available. The last element in the array is the
* actual element where the error occurs; previous elements represent the
* frames within which the error appears, if relevant.
* @return {string} The location description.
* @private
*/
bidichecker.ErrorCollector.prototype.generateLocationDescription_ = function(
locationElements) {
// Build up the description in the reverse order of the location elements,
// starting with the lowest level and ascending through any parent frames.
var descriptionParts = [];
goog.array.forEachRight(locationElements, function(frame) {
descriptionParts.push(bidichecker.utils.describeLocation(frame));
});
return descriptionParts.join(' in ');
};