com.google.javascript.jscomp.BasicErrorManager Maven / Gradle / Ivy
Show all versions of com.liferay.frontend.js.minifier
/*
* Copyright 2007 The Closure Compiler Authors.
*
* 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.
*/
package com.google.javascript.jscomp;
import com.google.common.base.Objects;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Set;
/**
* A basic error manager that sorts all errors and warnings reported to it to
* generate a sorted report when the {@link #generateReport()} method
* is called.
*
* This error manager does not produce any output, but subclasses can
* override the {@link #println(CheckLevel, JSError)} method to generate custom
* output.
*
*/
public abstract class BasicErrorManager implements ErrorManager {
final PriorityQueue messages =
new PriorityQueue<>(1, new LeveledJSErrorComparator());
private final Set alreadyAdded = new HashSet<>();
private int errorCount = 0;
private int warningCount = 0;
private double typedPercent = 0.0;
@Override
public void report(CheckLevel level, JSError error) {
ErrorWithLevel e = new ErrorWithLevel(error, level);
if (alreadyAdded.add(e)) {
messages.add(e);
if (level == CheckLevel.ERROR) {
errorCount++;
} else if (level == CheckLevel.WARNING) {
warningCount++;
}
}
}
@Override
public void generateReport() {
List list = new ArrayList<>();
for (ErrorWithLevel message = messages.poll(); message != null; message = messages.poll()) {
println(message.level, message.error);
list.add(message);
}
// Restore the messages since some tests assert the values after generating the report.
messages.addAll(list);
printSummary();
}
/**
* Print a message with a trailing new line. This method is called by the
* {@link #generateReport()} method when generating messages.
*/
public abstract void println(CheckLevel level, JSError error);
/**
* Print the summary of the compilation - number of errors and warnings.
*/
protected abstract void printSummary();
@Override
public int getErrorCount() {
return errorCount;
}
@Override
public int getWarningCount() {
return warningCount;
}
@Override
public JSError[] getErrors() {
return toArray(CheckLevel.ERROR);
}
@Override
public JSError[] getWarnings() {
return toArray(CheckLevel.WARNING);
}
@Override
public void setTypedPercent(double typedPercent) {
this.typedPercent = typedPercent;
}
@Override
public double getTypedPercent() {
return typedPercent;
}
private JSError[] toArray(CheckLevel level) {
List errors = new ArrayList<>(messages.size());
for (ErrorWithLevel p : messages) {
if (p.level == level) {
errors.add(p.error);
}
}
return errors.toArray(new JSError[0]);
}
/**
* Comparator of {@link JSError} with an associated {@link CheckLevel}. The ordering is the
* standard lexical ordering on the quintuple (file name, line number, {@link CheckLevel},
* character number, description).
*
* Note: this comparator imposes orderings that are inconsistent with {@link
* JSError#equals(Object)}.
*/
static final class LeveledJSErrorComparator implements Comparator {
private static final int P1_LT_P2 = -1;
private static final int P1_GT_P2 = 1;
@Override
public int compare(ErrorWithLevel p1, ErrorWithLevel p2) {
// null is the smallest value
if (p2 == null) {
if (p1 == null) {
return 0;
} else {
return P1_GT_P2;
}
}
// check level
if (p1.level != p2.level) {
return p2.level.compareTo(p1.level);
}
// sourceName comparison
String source1 = p1.error.sourceName;
String source2 = p2.error.sourceName;
if (source1 != null && source2 != null) {
int sourceCompare = source1.compareTo(source2);
if (sourceCompare != 0) {
return sourceCompare;
}
} else if (source1 == null && source2 != null) {
return P1_LT_P2;
} else if (source1 != null && source2 == null) {
return P1_GT_P2;
}
// lineno comparison
int lineno1 = p1.error.lineNumber;
int lineno2 = p2.error.lineNumber;
if (lineno1 != lineno2) {
return lineno1 - lineno2;
} else if (lineno1 < 0 && 0 <= lineno2) {
return P1_LT_P2;
} else if (0 <= lineno1 && lineno2 < 0) {
return P1_GT_P2;
}
// charno comparison
int charno1 = p1.error.getCharno();
int charno2 = p2.error.getCharno();
if (charno1 != charno2) {
return charno1 - charno2;
} else if (charno1 < 0 && 0 <= charno2) {
return P1_LT_P2;
} else if (0 <= charno1 && charno2 < 0) {
return P1_GT_P2;
}
// description
return p1.error.description.compareTo(p2.error.description);
}
}
static class ErrorWithLevel {
final JSError error;
final CheckLevel level;
ErrorWithLevel(JSError error, CheckLevel level) {
this.error = error;
this.level = level;
}
@Override
public int hashCode() {
return Objects.hashCode(
level, error.description, error.sourceName, error.lineNumber, error.getCharno());
}
@Override
public boolean equals(Object obj) {
return obj.hashCode() == this.hashCode();
}
}
}