001/*
002 * Minify Maven Plugin
003 * https://github.com/samaxes/minify-maven-plugin
004 *
005 * Copyright (c) 2009 samaxes.com
006 *
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019package com.samaxes.maven.minify.common;
020
021import org.apache.maven.plugin.logging.Log;
022import org.mozilla.javascript.ErrorReporter;
023import org.mozilla.javascript.EvaluatorException;
024
025/**
026 * A Rhino compatible error reporter.
027 */
028public class JavaScriptErrorReporter implements ErrorReporter {
029
030    private Log log;
031
032    private String filename;
033
034    /**
035     * Error reporter constructor.
036     *
037     * @param log      Maven plugin log
038     * @param filename JavaScript source file name
039     */
040    public JavaScriptErrorReporter(Log log, String filename) {
041        this.log = log;
042        this.filename = filename;
043    }
044
045    /**
046     * Reports a warning.
047     *
048     * @param message    a String describing the warning
049     * @param sourceName a String describing the JavaScript source where the warning occurred; typically a file name or
050     *                   URL
051     * @param line       the line number associated with the warning
052     * @param lineSource the text of the line (may be null)
053     * @param lineOffset the offset into lineSource where problem was detected
054     */
055    @Override
056    public void warning(String message, String sourceName, int line, String lineSource, int lineOffset) {
057        log.warn(constructMessage(message, sourceName, line, lineSource, lineOffset));
058    }
059
060    /**
061     * Reports an error. If execution has not yet begun, the JavaScript engine is free to find additional errors rather
062     * than terminating the translation. However, it will not execute a script that had errors.
063     *
064     * @param message    a String describing the warning
065     * @param sourceName a String describing the JavaScript source where the warning occurred; typically a file name or
066     *                   URL
067     * @param line       the line number associated with the warning
068     * @param lineSource the text of the line (may be null)
069     * @param lineOffset the offset into lineSource where problem was detected
070     */
071    @Override
072    public void error(String message, String sourceName, int line, String lineSource, int lineOffset) {
073        log.error(constructMessage(message, sourceName, line, lineSource, lineOffset));
074    }
075
076    /**
077     * Creates an EvaluatorException that may be thrown. runtimeErrors, unlike errors, will always terminate the current
078     * script.
079     *
080     * @param message    a String describing the warning
081     * @param sourceName a String describing the JavaScript source where the warning occurred; typically a file name or
082     *                   URL
083     * @param line       the line number associated with the warning
084     * @param lineSource the text of the line (may be null)
085     * @param lineOffset the offset into lineSource where problem was detected
086     */
087    @Override
088    public EvaluatorException runtimeError(String message, String sourceName, int line, String lineSource,
089                                           int lineOffset) {
090        log.error(message);
091
092        return new EvaluatorException(message, sourceName, line, lineSource, lineOffset);
093    }
094
095    private String constructMessage(String message, String sourceName, int line, String lineSource, int lineOffset) {
096        StringBuilder stringBuilder = new StringBuilder();
097
098        stringBuilder.append(message).append(" at ");
099        if (sourceName != null) {
100            stringBuilder.append(sourceName);
101        } else if (filename != null) {
102            stringBuilder.append(filename);
103        } else {
104            stringBuilder.append("(unknown source)");
105        }
106        stringBuilder.append(" line ");
107        if (line > 0) {
108            stringBuilder.append(line);
109        } else {
110            stringBuilder.append("(unknown line)");
111        }
112        stringBuilder.append(":");
113        if (lineOffset >= 0) {
114            stringBuilder.append(lineOffset);
115        } else {
116            stringBuilder.append("(unknown column)");
117        }
118        if (lineSource != null) {
119            stringBuilder.append('\n');
120            stringBuilder.append(lineSource);
121            if (lineOffset >= 0 && lineOffset <= lineSource.length()) {
122                stringBuilder.append('\n');
123                for (int i = 0; i < lineOffset; i++) {
124                    char c = lineSource.charAt(i);
125                    if (Character.isWhitespace(c)) {
126                        stringBuilder.append(c);
127                    } else {
128                        stringBuilder.append(' ');
129                    }
130                }
131                stringBuilder.append("^\n");
132            }
133        }
134
135        return stringBuilder.toString();
136    }
137}