Package com.googlecode.jslint4java.maven

Source Code of com.googlecode.jslint4java.maven.JSLintMojo

package com.googlecode.jslint4java.maven;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.io.Closeables;
import com.googlecode.jslint4java.JSLint;
import com.googlecode.jslint4java.JSLintBuilder;
import com.googlecode.jslint4java.JSLintResult;
import com.googlecode.jslint4java.Option;
import com.googlecode.jslint4java.UnicodeBomInputStream;
import com.googlecode.jslint4java.formatter.CheckstyleXmlFormatter;
import com.googlecode.jslint4java.formatter.JSLintResultFormatter;
import com.googlecode.jslint4java.formatter.JSLintXmlFormatter;
import com.googlecode.jslint4java.formatter.JUnitXmlFormatter;
import com.googlecode.jslint4java.formatter.PlainFormatter;
import com.googlecode.jslint4java.formatter.ReportFormatter;

/**
* Validates JavaScript using jslint4java.
*
* @author dom
*/
// TODO Support alternate jslint
// TODO Support HTML reports (site plugin mojo?)
@Mojo(name = "lint", defaultPhase = LifecyclePhase.VERIFY)
public class JSLintMojo extends AbstractMojo {

    /** Where to write the HTML report. */
    private static final String REPORT_HTML = "report.html";

    /** Where to write the plain text report. */
    private static final String REPORT_TXT = "report.txt";

    /** Where to write the checkstyle report. */
    private static final String CHECKSTYLE_XML = "checkstyle.xml";

    private static final String DEFAULT_INCLUDES = "**/*.js";

    private static final String JSLINT_XML = "jslint.xml";

    /** Where to write the junit report. */
    private static final String JUNIT_XML = "junit.xml";

    /**
     * Specifies the the source files to be excluded for JSLint (relative to
     * {@link #defaultSourceFolder}). Maven applies its own defaults.
     */
    @Parameter(property = "excludes")
    private final List<String> excludes = Lists.newArrayList();

    /**
     * Specifies the the source files to be used for JSLint (relative to
     * {@link #defaultSourceFolder}). If none are given, defaults to <code>**&#47;*.js</code>.
     */
    @Parameter(property = "includes")
    private final List<String> includes = Lists.newArrayList();

    /**
     * Specifies the location of the default source folder to be used for JSLint. Note that this is
     * just used for filling in the default, as it resolves the default value correctly. Anything
     * you specify will override it.
     */
    @Parameter(readonly = true, required = true, defaultValue = "${basedir}/src/main/webapp")
    private File defaultSourceFolder;

    /**
     * Which locations should JSLint look for JavaScript files in? Defaults to
     * ${basedir}/src/main/webapp.
     */
    @Parameter
    private File[] sourceFolders = new File[] {};

    /**
     * Which JSLint {@link Option}s to set.
     */
    @Parameter
    private final Map<String, String> options = Maps.newHashMap();

    /**
     * What encoding should we use to read the JavaScript files? Defaults to UTF-8.
     */
    @Parameter(property = "encoding", defaultValue = "${project.build.sourceEncoding}")
    private String encoding = "UTF-8";

    /**
     * Base folder for report output.
     */
    @Parameter(property = "jslint.outputFolder", defaultValue = "${project.build.directory}/jslint4java")
    private File outputFolder = new File("target");

    /**
     * Fail the build if JSLint detects any problems.
     */
    @Parameter(property = "jslint.failOnError", defaultValue = "true")
    private boolean failOnError = true;

    /**
     * An alternative JSLint to use.
     */
    @Parameter(property = "jslint.source")
    private File jslintSource;

    /**
     * How many seconds JSLint is allowed to run.
     */
    @Parameter(property = "jslint.timeout")
    private long timeout;

    /**
     * Skip linting files if true.
     */
    @Parameter(property = "jslint.skip", defaultValue = "false")
    private boolean skip = false;

    /** Add a single option. For testing only. */
    void addOption(Option sloppy, String value) {
        options.put(sloppy.name().toLowerCase(Locale.ENGLISH), value);
    }

    /**
     * Set the default includes.
     */
    private void applyDefaults() {
        if (includes.isEmpty()) {
            includes.add(DEFAULT_INCLUDES);
        }
        if (sourceFolders.length == 0) {
            sourceFolders = new File[] { defaultSourceFolder };
        }
    }

    private void applyOptions(JSLint jsLint) throws MojoExecutionException {
        for (Entry<String, String> entry : options.entrySet()) {
            if (entry.getValue() == null || entry.getValue().equals("")) {
                continue;
            }
            Option option;
            try {
                option = Option.valueOf(entry.getKey().toUpperCase(Locale.ENGLISH));
            } catch (IllegalArgumentException e) {
                throw new MojoExecutionException("unknown option: " + entry.getKey());
            }
            jsLint.addOption(option, entry.getValue());
        }
    }

    public void execute() throws MojoExecutionException, MojoFailureException {
        if (skip) {
            getLog().info("skipping JSLint");
            return;
        }
        JSLint jsLint = applyJSlintSource();
        applyDefaults();
        applyOptions(jsLint);
        List<File> files = getFilesToProcess();
        int failures = 0;
        ReportWriter reporter = makeReportWriter();
        try {
            reporter.open();
            for (File file : files) {
                JSLintResult result = lintFile(jsLint, file);
                failures += result.getIssues().size();
                logIssues(result, reporter);
            }
        } finally {
            reporter.close();
        }
        if (failures > 0) {
            String message = "JSLint found " + failures + " problems in " + files.size() + " files";
            if (failOnError) {
                throw new MojoFailureException(message);
            } else {
                getLog().info(message);
            }
        }
    }

    private JSLint applyJSlintSource() throws MojoExecutionException {
        JSLintBuilder builder = new JSLintBuilder();
        if (timeout > 0) {
            builder.timeout(timeout);
        }
        if (jslintSource != null) {
            try {
                return builder.fromFile(jslintSource, Charset.forName(encoding));
            } catch (IOException e) {
                throw new MojoExecutionException("Cant' load jslint.js", e);
            }
        } else {
            return builder.fromDefault();
        }
    }

    @VisibleForTesting
    String getEncoding() {
        return encoding;
    }

    /**
     * Process includes and excludes to work out which files we are interested in. Originally nicked
     * from CheckstyleReport, now looks nothing like it.
     *
     * @return a {@link List} of {@link File}s.
     */
    private List<File> getFilesToProcess() throws MojoExecutionException {
        // Defaults.
        getLog().debug("includes=" + includes);
        getLog().debug("excludes=" + excludes);

        List<File> files = Lists.newArrayList();
        for (File folder : sourceFolders) {
            getLog().debug("searching " + folder);
            try {
                files.addAll(new FileLister(folder, includes, excludes).files());
            } catch (IOException e) {
                // Looking in FileUtils, this is a "can never happen". *sigh*
                throw new MojoExecutionException("Error listing files", e);
            }
        }

        return files;
    }

    @VisibleForTesting
    Map<String, String> getOptions() {
        return options;
    }

    private JSLintResult lintFile(JSLint jsLint, File file) throws MojoExecutionException {
        getLog().debug("lint " + file);
        BufferedReader reader = null;
        try {
            UnicodeBomInputStream stream = new UnicodeBomInputStream(new FileInputStream(file));
            stream.skipBOM();
            reader = new BufferedReader(new InputStreamReader(stream, getEncoding()));
            return jsLint.lint(file.toString(), reader);
        } catch (FileNotFoundException e) {
            throw new MojoExecutionException("file not found: " + file, e);
        } catch (UnsupportedEncodingException e) {
            // Can never happen.
            throw new MojoExecutionException("unsupported character encoding UTF-8", e);
        } catch (IOException e) {
            throw new MojoExecutionException("problem whilst linting " + file, e);
        } finally {
            Closeables.closeQuietly(reader);
        }
    }

    private void logIssues(JSLintResult result, ReportWriter reporter) {
        reporter.report(result);
        if (result.getIssues().isEmpty()) {
            return;
        }
        logIssuesToConsole(result);
    }

    private void logIssuesToConsole(JSLintResult result) {
        JSLintResultFormatter formatter = new PlainFormatter();
        String report = formatter.format(result);
        for (String line : report.split("\n")) {
            getLog().info(line);
        }
    }

    private ReportWriter makeReportWriter() {
        ReportWriterImpl f1 = new ReportWriterImpl(new File(outputFolder, JSLINT_XML),
                new JSLintXmlFormatter());
        ReportWriterImpl f2 = new ReportWriterImpl(new File(outputFolder, JUNIT_XML),
                new JUnitXmlFormatter());
        ReportWriterImpl f3 = new ReportWriterImpl(new File(outputFolder, CHECKSTYLE_XML),
                new CheckstyleXmlFormatter());
        ReportWriterImpl f4 = new ReportWriterImpl(new File(outputFolder, REPORT_TXT),
                new PlainFormatter());
        ReportWriterImpl f5 = new ReportWriterImpl(new File(outputFolder, REPORT_HTML),
                new ReportFormatter());
        return new MultiReportWriter(f1, f2, f3, f4, f5);
    }

    public void setDefaultSourceFolder(File defaultSourceFolder) {
        this.defaultSourceFolder = defaultSourceFolder;
    }

    public void setEncoding(String encoding) {
        this.encoding = encoding;
    }

    public void setExcludes(List<String> excludes) {
        this.excludes.clear();
        this.excludes.addAll(excludes);
    }

    public void setFailOnError(boolean b) {
        failOnError = b;
    }

    public void setIncludes(List<String> includes) {
        this.includes.clear();
        this.includes.addAll(includes);
    }

    /** The location of the JSLint source file. */
    public void setJslint(File jslintSource) {
        this.jslintSource = jslintSource;
    }

    public void setOptions(Map<String, String> options) {
        this.options.clear();
        this.options.putAll(options);
    }

    public void setOutputFolder(File outputFolder) {
        this.outputFolder = outputFolder;
    }

    public void setSkip(boolean skip) {
        this.skip = skip;
    }

    public void setSourceFolders(List<File> sourceFolders) {
        this.sourceFolders = sourceFolders.toArray(new File[sourceFolders.size()]);
    }

}
TOP

Related Classes of com.googlecode.jslint4java.maven.JSLintMojo

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.