All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.googlecode.jslint4java.ant.JSLintTask Maven / Gradle / Ivy

package com.googlecode.jslint4java.ant;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.taskdefs.LogOutputStream;
import org.apache.tools.ant.types.Resource;
import org.apache.tools.ant.types.ResourceCollection;
import org.apache.tools.ant.types.resources.Union;

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;

/**
 * Run {@link JSLint} over a tree of files in order to pick holes in your
 * JavaScript.
 *
 * 

* Example build.xml usage: * *

 * <project name="build-test" xmlns:jsl="antlib:com.googlecode.jslint4java">
 *   <target name="jslint">
 *     <jsl:jslint options="undef">
 *       <formatter type="plain" />
 *       <fileset dir="." includes="*.js" excludes="*.pack.js" />
 *     </jsl:jslint>
 *   </target>
 * </project
 * 
* *

* You have to specify one or more nested fileset elements. You may * optionally specify a formatter element in order to generate output (as * opposed to just a build failed message). Usually, you will want the plain * formatter, but in case you want to generate a report, the xml formatter * mighht be useful. * *

Attributes

* *
*
encoding
*
Optional. The encoding of the JavaScript files. Defaults to system * encoding.
*
haltOnFailure
*
Optional. Specify if the build should fail if there are files which do * not pass JSLint. Defaults to true.
*
options
*
Optional. A comma separated list of {@link Option} names. No default.
*
timeout *
Optional. The maximum amount of time that JSLint can run. *
* * @author dom * @see jslint.com * @see FormatterElement */ public class JSLintTask extends Task { private static final String NO_FILES_TO_LINT = "no files to lint!"; private final Union resources = new Union(); private final List formatters = new ArrayList(); private boolean haltOnFailure = true; private String encoding = System.getProperty("file.encoding", "UTF-8"); private String failureProperty = null; private File jslintSource = null; private final Map options = new HashMap(); private PredefElement predef = null; private long timeout = 0; /** * Check the contents of this {@link ResourceCollection}. * * @param rc * Any kind of resource collection, e.g. fileset. */ public void add(ResourceCollection rc) { resources.add(rc); } /** * Add in a {@link ResultFormatter} through the medium of a * {@link FormatterElement}. * * @param fe */ public void addConfiguredFormatter(FormatterElement fe) { fe.setDefaultOutputStream(getDefaultOutput()); formatters.add(fe.getResultFormatter()); } /** * Capture a predef element. */ public void addPredef(PredefElement predef) { this.predef = predef; } public void applyOptions(JSLint lint) { for (Entry entry : options.entrySet()) { String value = entry.getValue(); try { if (value == null) { lint.addOption(entry.getKey()); } else { lint.addOption(entry.getKey(), value); } } catch (IllegalArgumentException e) { String optName = entry.getKey().getLowerName(); String className = e.getClass().getName(); throw new BuildException(optName + ": " + className + ": " + e.getMessage()); } } // Handle predefs separately. They don't work too well in the options // string. if (predef != null) { lint.addOption(Option.PREDEF, predef.getText()); } } /** * Scan the specified directories for JavaScript files and lint them. */ @Override public void execute() throws BuildException { if (resources.size() == 0) { // issue 53: this isn't a fail, just a notice. log(NO_FILES_TO_LINT); } JSLint lint = makeLint(); applyOptions(lint); for (ResultFormatter rf : formatters) { rf.begin(); } int failedCount = 0; int totalErrorCount = 0; for (Resource resource : resources.listResources()) { try { int errorCount = lintStream(lint, resource); if (errorCount > 0) { totalErrorCount += errorCount; failedCount++; } } catch (IOException e) { throw new BuildException(e); } } for (ResultFormatter rf : formatters) { rf.end(); } if (failedCount != 0) { String msg = failureMessage(failedCount, totalErrorCount); if (haltOnFailure) { throw new BuildException(msg); } else { log(msg); if (failureProperty != null) { getProject().setProperty(failureProperty, msg); } } } } private String failureMessage(int failedCount, int totalErrorCount) { return "JSLint: " + totalErrorCount + " " + plural(totalErrorCount, "error") + " in " + failedCount + " " + plural(failedCount, "file"); } /** * Return a logging {@link OutputStream} that can be passed to formatters. */ private OutputStream getDefaultOutput() { return new LogOutputStream(this, Project.MSG_INFO); } /** * Lint a given stream. Closes the stream after use. * * @param lint * * @throws IOException */ private int lintStream(JSLint lint, Resource resource) throws UnsupportedEncodingException, IOException { BufferedReader reader = null; try { UnicodeBomInputStream stream = new UnicodeBomInputStream(resource.getInputStream()); stream.skipBOM(); reader = new BufferedReader(new InputStreamReader(stream, encoding)); String name = resource.toString(); JSLintResult result = lint.lint(name, reader); log("Found " + result.getIssues().size() + " issues in " + name, Project.MSG_VERBOSE); for (ResultFormatter rf : formatters) { rf.output(result); } return result.getIssues().size(); } finally { if (reader != null) { reader.close(); } } } /** * Create a new {@link JSLint} object. */ public JSLint makeLint() throws BuildException { try { JSLintBuilder builder = new JSLintBuilder(); if (timeout > 0) { builder.timeout(timeout); } if (jslintSource == null) { return builder.fromDefault(); } else { return builder.fromFile(jslintSource); } } catch (IOException e) { throw new BuildException(e); } } /** * Quick and nasty hack to pluralise words. Works enough for my needs. */ private String plural(int count, String word) { return count == 1 ? word : word + "s"; } /** * Set the encoding of the source files that JSLint will read. If not * specified, the default is the system encoding (via the * file.encoding property). If that isn't present, default to * UTF-8. * * @param encoding * a valid charset identifier. */ public void setEncoding(String encoding) { this.encoding = encoding; } /** * The name of a property to set upon failure. This property will contain * the log message. */ public void setFailureProperty(String failureProperty) { this.failureProperty = failureProperty; } /** * Specify an alternative version of jslint. */ public void setJslint(File jslint) { jslintSource = jslint; } /** * Should the build stop if JSLint fails? Defaults to true. * * @param haltOnFailure */ public void setHaltOnFailure(boolean haltOnFailure) { this.haltOnFailure = haltOnFailure; } /** * Set the options for running JSLint. This is a comma separated list of * {@link Option} names. The names are case-insensitive. * *

* NB: If you want to put an {@link Option#PREDEF} in here, you should use a * {@code } child element instead. Otherwise, it could be difficult * to specify a comma separated list as an element of a comma separated * list… */ public void setOptions(String optionList) throws BuildException { for (String name : optionList.split("\\s*,\\s*")) { String[] parts = name.split("=", 2); String optName = parts[0]; try { // The Option constants are upper case… Option o = Option.valueOf(optName.toUpperCase(Locale.getDefault())); // If an argument has been specified, use it. String value = parts.length == 2 ? parts[1] : null; options.put(o, value); } catch (IllegalArgumentException e) { throw new BuildException("Unknown option " + optName); } } } /** Set the maximum time JSLint can run for in seconds. */ public void setTimeout(long timeout) { this.timeout = timeout; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy