com.google.javascript.jscomp.RhinoErrorReporter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of closure-compiler-linter Show documentation
Show all versions of closure-compiler-linter Show documentation
Closure Compiler is a JavaScript optimizing compiler. It parses your
JavaScript, analyzes it, removes dead code and rewrites and minimizes
what's left. It also checks syntax, variable references, and types, and
warns about common JavaScript pitfalls. It is used in many of Google's
JavaScript apps, including Gmail, Google Web Search, Google Maps, and
Google Docs.
This binary checks for style issues such as incorrect or missing JSDoc
usage, and missing goog.require() statements. It does not do more advanced
checks such as typechecking.
/*
* Copyright 2009 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.collect.ImmutableMap;
import com.google.javascript.rhino.ErrorReporter;
import com.google.javascript.rhino.SimpleErrorReporter;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;
/**
* An error reporter for serializing Rhino errors into our error format.
* @author [email protected] (Nick Santos)
*/
class RhinoErrorReporter {
static final DiagnosticType PARSE_ERROR =
DiagnosticType.error("JSC_PARSE_ERROR", "Parse error. {0}");
static final DiagnosticType TYPE_PARSE_ERROR =
DiagnosticType.warning("JSC_TYPE_PARSE_ERROR", "{0}");
static final DiagnosticType UNRECOGNIZED_TYPE_ERROR =
DiagnosticType.warning("JSC_UNRECOGNIZED_TYPE_ERROR", "{0}");
// This is separate from TYPE_PARSE_ERROR because there are many instances of this warning
// and it is unfeasible to fix them all right away.
static final DiagnosticType JSDOC_MISSING_BRACES_WARNING =
DiagnosticType.disabled("JSC_JSDOC_MISSING_BRACES_WARNING", "{0}");
// This is separate from TYPE_PARSE_ERROR because there are many instances of this warning
// and it is unfeasible to fix them all right away.
static final DiagnosticType JSDOC_MISSING_TYPE_WARNING =
DiagnosticType.disabled("JSC_JSDOC_MISSING_TYPE_WARNING", "{0}");
// Import is supported by VSCode and is pretty much a standard now.
static final DiagnosticType JSDOC_IMPORT_TYPE_WARNING =
DiagnosticType.disabled("JSC_JSDOC_IMPORT_TYPE_WARNING", "{0}");
static final DiagnosticType TOO_MANY_TEMPLATE_PARAMS =
DiagnosticType.disabled("JSC_TOO_MANY_TEMPLATE_PARAMS", "{0}");
// Special-cased errors, so that they can be configured via the
// warnings API.
static final DiagnosticType TRAILING_COMMA =
DiagnosticType.error("JSC_TRAILING_COMMA",
"Parse error. IE8 (and below) will parse trailing commas in " +
"array and object literals incorrectly. " +
"If you are targeting newer versions of JS, " +
"set the appropriate language_in option.");
static final DiagnosticType DUPLICATE_PARAM =
DiagnosticType.error("JSC_DUPLICATE_PARAM", "Parse error. {0}");
static final DiagnosticType UNNECESSARY_ESCAPE =
DiagnosticType.disabled("JSC_UNNECESSARY_ESCAPE", "Parse error. {0}");
static final DiagnosticType INVALID_PARAM =
DiagnosticType.warning("JSC_INVALID_PARAM", "Parse error. {0}");
static final DiagnosticType BAD_JSDOC_ANNOTATION =
DiagnosticType.warning("JSC_BAD_JSDOC_ANNOTATION", "Parse error. {0}");
static final DiagnosticType INVALID_ES3_PROP_NAME = DiagnosticType.warning(
"JSC_INVALID_ES3_PROP_NAME",
"Keywords and reserved words are not allowed as unquoted property " +
"names in older versions of JavaScript. " +
"If you are targeting newer versions of JavaScript, " +
"set the appropriate language_in option.");
static final DiagnosticType PARSE_TREE_TOO_DEEP =
DiagnosticType.error("JSC_PARSE_TREE_TOO_DEEP", "Parse tree too deep.");
static final DiagnosticType INVALID_OCTAL_LITERAL =
DiagnosticType.warning(
"JSC_INVALID_OCTAL_LITERAL",
"This style of octal literal is not supported in strict mode.");
static final DiagnosticType STRING_CONTINUATION =
DiagnosticType.warning("JSC_STRING_CONTINUATION", "{0}");
static final DiagnosticType LANGUAGE_FEATURE =
DiagnosticType.error("JSC_LANGUAGE_FEATURE", "{0}.");
static final DiagnosticType UNSUPPORTED_LANGUAGE_FEATURE =
DiagnosticType.error("JSC_UNSUPPORTED_LANGUAGE_FEATURE", "{0}.");
static final DiagnosticType ES6_TYPED =
DiagnosticType.error(
"JSC_ES6_TYPED",
"{0}. Use --language_in=ECMASCRIPT6_TYPED to enable ES6 typed features.");
static final DiagnosticType MISPLACED_TYPE_SYNTAX =
DiagnosticType.error(
"JSC_MISPLACED_TYPE_SYNTAX", "Can only have JSDoc or inline type annotations, not both");
// A map of Rhino messages to their DiagnosticType.
private static final Map typeMap =
ImmutableMap.builder()
// Trailing comma
.put(
Pattern.compile("Trailing comma is not legal in an ECMA-262 object initializer"),
TRAILING_COMMA)
// Duplicate parameter
.put(replacePlaceHolders("Duplicate parameter name \"{0}\""), DUPLICATE_PARAM)
.put(Pattern.compile("Unnecessary escape:.*"), UNNECESSARY_ESCAPE)
.put(Pattern.compile("^invalid param name.*"), INVALID_PARAM)
// Unknown @annotations.
.put(
replacePlaceHolders(SimpleErrorReporter.getMessage0("msg.bad.jsdoc.tag")),
BAD_JSDOC_ANNOTATION)
.put(
Pattern.compile(
"^Keywords and reserved words are not allowed as unquoted property.*"),
INVALID_ES3_PROP_NAME)
.put(Pattern.compile("^Too many template parameters"), TOO_MANY_TEMPLATE_PARAMS)
// Type annotation warnings.
.put(
Pattern.compile(".*Type annotations should have curly braces.*"),
JSDOC_MISSING_BRACES_WARNING)
.put(Pattern.compile("Missing type declaration\\."), JSDOC_MISSING_TYPE_WARNING)
// Unresolved types that aren't forward declared.
.put(Pattern.compile(".*Unknown type.*"), UNRECOGNIZED_TYPE_ERROR)
.put(Pattern.compile(".*Unknown type.*\n.*"), UNRECOGNIZED_TYPE_ERROR)
// Import annotation errors.
.put(
Pattern.compile("^Bad type annotation. Import in typedef.*"),
JSDOC_IMPORT_TYPE_WARNING)
// Type annotation errors.
.put(Pattern.compile("^Bad type annotation.*"), TYPE_PARSE_ERROR)
// Parse tree too deep.
.put(Pattern.compile("Too deep recursion while parsing"), PARSE_TREE_TOO_DEEP)
// Old-style octal literals
.put(Pattern.compile("^Octal .*literal.*"), INVALID_OCTAL_LITERAL)
.put(Pattern.compile("^String continuations.*"), STRING_CONTINUATION)
.put(Pattern.compile("^This language feature is only supported for .*"), LANGUAGE_FEATURE)
.put(
Pattern.compile(
"^This language feature is not currently supported by the internalReporter:"
+ " .*"),
UNSUPPORTED_LANGUAGE_FEATURE)
.put(Pattern.compile("^type syntax is only supported in ES6 typed mode.*"), ES6_TYPED)
.put(Pattern.compile("^Can only have JSDoc or inline type.*"), MISPLACED_TYPE_SYNTAX)
.build();
private final ErrorHandler internalReporter;
/**
* For each message such as "Not a good use of {0}", replace the place holder {0} with a wild card
* that matches all possible strings. Also put the any non-place-holder in quotes for regex
* matching later.
*/
private static Pattern replacePlaceHolders(String s) {
s = Pattern.quote(s);
return Pattern.compile(s.replaceAll("\\{\\d+\\}", "\\\\E.*\\\\Q"));
}
private RhinoErrorReporter(ErrorHandler internalReporter) {
this.internalReporter = internalReporter;
}
public static ErrorReporter forOldRhino(ErrorHandler internalReporter) {
return new OldRhinoErrorReporter(internalReporter);
}
void warningAtLine(String message, String sourceName, int line,
int lineOffset) {
internalReporter.report(
null, makeError(message, sourceName, line, lineOffset, CheckLevel.WARNING));
}
void errorAtLine(String message, String sourceName, int line,
int lineOffset) {
internalReporter.report(
null, makeError(message, sourceName, line, lineOffset, CheckLevel.ERROR));
}
protected static DiagnosticType mapError(String message) {
for (Entry entry : typeMap.entrySet()) {
if (entry.getKey().matcher(message).matches()) {
return entry.getValue();
}
}
return null;
}
private static JSError makeError(
String message, String sourceName, int line, int lineOffset, CheckLevel defaultLevel) {
// Try to see if the message is one of the rhino errors we want to
// expose as DiagnosticType by matching it with the regex key.
DiagnosticType type = mapError(message);
return (type != null)
? JSError.make(sourceName, line, lineOffset, type, message)
: JSError.make(sourceName, line, lineOffset, defaultLevel, PARSE_ERROR, message);
}
private static class OldRhinoErrorReporter extends RhinoErrorReporter
implements ErrorReporter {
private OldRhinoErrorReporter(ErrorHandler internalReporter) {
super(internalReporter);
}
@Override
public void error(String message, String sourceName, int line,
int lineOffset) {
super.errorAtLine(message, sourceName, line, lineOffset);
}
@Override
public void warning(String message, String sourceName, int line,
int lineOffset) {
super.warningAtLine(message, sourceName, line, lineOffset);
}
}
}