1
2
3
4
5
6
7
8
9
10
11
12
13
14 package gr.abiss.mvn.plugins.jstools;
15
16 import gr.abiss.mvn.plugins.jstools.utils.FileSystemDirectoryUtils;
17 import java.io.File;
18 import java.io.FileNotFoundException;
19 import java.io.FileOutputStream;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.OutputStream;
23 import java.io.ByteArrayOutputStream;
24 import java.io.PrintStream;
25 import java.util.Iterator;
26 import java.util.Locale;
27 import java.util.Set;
28 import org.apache.commons.io.IOUtils;
29 import org.apache.maven.reporting.MavenReportException;
30 import org.codehaus.doxia.sink.Sink;
31 import org.mozilla.javascript.Context;
32 import org.mozilla.javascript.Scriptable;
33
34 /***
35 * Goal to generate JavaScript coverage reports using JSLint
36 *
37 * @goal jslint
38 * @phase post-site
39 * @version $Id$
40 * @author manos
41 */
42 public class JsLintMojo extends AbstractBaseJstoolsReport {
43
44 /***
45 * A path pointing to some custom JS code to drive JSLint via Rhino. You can provide your own,
46 * or let the plugin use its own internal version.
47 * @parameter expression="${project.build.directory}/jslint/fulljslint_init.js"
48 */
49 private String jslintInitJsFilePath;
50 /***
51 * A path pointing to a full version of JSLint (e.g.
52 * /home/username/stuff/fulljslint.js). If no value is provided the plugin wil
53 * use its own internal version. You can find the file at
54 * <a href="http://www.jslint.com/fulljslint.js">http://www.jslint.com/fulljslint.js</a>
55 *
56 * @parameter expression="${project.build.directory}/jslint/fulljslint.js"
57 */
58 private String jslintJsFilePath;
59
60 /***
61 * Wether to only include errors in the report. Default is true (errors only)
62 * @parameter expression="true"
63 */
64 private boolean reportJslintErrorsOnly;
65
66 /***
67 * if use of some browser features should be restricted (unused JSLint
68 * option)
69 */
70 boolean adsafe = true;
71
72 /*** if bitwise operators should not be allowed (JSLint option) */
73 boolean bitwise = true;
74
75 /*** if the standard browser globals should be predefined (JSLint option) */
76 boolean browser = true;
77
78 /*** if upper case HTML should be allowed (JSLint option) */
79 boolean cap = true;
80
81 /*** if debugger statements should be allowed (JSLint option) */
82 boolean debug = true;
83
84 /*** if === should be required (JSLint option) */
85 boolean eqeqeq = true;
86
87 /*** if eval should be allowed (JSLint option) */
88 boolean evil = true;
89
90 /*** if HTML fragments should be allowed (JSLint option) */
91 boolean fragment = true;
92
93 /*** if line breaks should not be checked (JSLint option) */
94 boolean laxbreak = true;
95
96 /*** if names should be checked (JSLint option) */
97 boolean nomen = true;
98
99 /*** if the scan should stop on first error (JSLint option) */
100 boolean passfail = true;
101
102 /*** if increment/decrement should not be allowed (JSLint option) */
103 boolean plusplus = true;
104
105 /*** if the Rhino environment globals should be predefined (JSLint option) */
106 boolean rhino = true;
107
108 /*** if variables should be declared before used (JSLint option) */
109 boolean undef = true;
110
111 /*** if strict whitespace rules apply (JSLint option) */
112 boolean white = true;
113
114 /*** if the Yahoo Widgets globals should be predefined (JSLint option) */
115 boolean widget = true;
116
117 /***
118 * Use JSLint to generate a code analysis report
119 * @see gr.abiss.mvn.plugins.jstools.AbstractBaseJstoolsReport#doGenerateReport(java.util.Locale)
120 */
121 public void doGenerateReport(Locale defaultLocale) throws MavenReportException {
122 try {
123 File outDir = new File(this.getOutputDirectory());
124 if (!outDir.exists()) {
125 outDir.mkdirs();
126 }
127 Set jsFiles = this.getJavaScriptFiles();
128 Sink sink = getSink();
129 sink.head();
130 sink.title();
131 sink.text("JSLint Coverage Report");
132 sink.title_();
133 sink.head_();
134 sink.body();
135 sink.section1();
136 sink.sectionTitle1();
137 sink.text("Overview");
138 sink.sectionTitle1_();
139 sink.paragraph();
140 sink.rawText("This report was build with <a href=\"http://www.jslint.com/\">JSLint</a>, the JavaScript Verifier. " +
141 "JSLint is a JavaScript program that looks for problems in other JavaScript programs.");
142 sink.paragraph_();
143 if (jsFiles.size() > 0) {
144 String jsLintCode = getFileAsString(this.jslintJsFilePath) + this.getFileAsString(this.jslintInitJsFilePath);
145 sink.paragraph();
146 sink.text("Here is the list of files in this report:");
147 sink.paragraph_();
148 sink.list();
149 for (Iterator iter = jsFiles.iterator(); iter.hasNext();) {
150 File jsFile = (File) iter.next();
151 sink.listItem();
152 sink.rawText("<a href=\"#_"
153 + jsFile.getName().replaceAll(" ", "") + "\">"
154 + jsFile.getName() + "</a>");
155 sink.listItem_();
156 }
157 sink.list_();
158 sink.section1_();
159 for (Iterator iter = jsFiles.iterator(); iter.hasNext();) {
160 File jsFile = (File) iter.next();
161 ByteArrayOutputStream buff = runJslintOnSource(jsLintCode, jsFile
162 .getAbsolutePath());
163 sink.rawText("<a id=\"_"
164 + jsFile.getName().replaceAll(" ", "")
165 + "\"> </a>");
166 sink.sectionTitle1();
167 sink.text(jsFile.getName());
168 sink.sectionTitle1_();
169 sink.rawText("<div class=\"source\"><pre>"
170 + (buff.size() > 0 ? buff.toString()
171 : "No problems found") + "</pre></div>");
172 }
173 } else {
174 sink.paragraph();
175 sink.text("There are currently no files in this report.");
176 sink.paragraph_();
177 }
178 sink.body_();
179 sink.flush();
180 sink.close();
181 } catch (Exception e) {
182 e.printStackTrace();
183 throw new MavenReportException("Error building JSLint report", e);
184 }
185 }
186
187 /***
188 * @param jsLintCode
189 * @param sourceFilePath
190 * @return
191 */
192 private ByteArrayOutputStream runJslintOnSource(String jsLintCode, String sourceFilePath){
193 ByteArrayOutputStream buff = new ByteArrayOutputStream();
194 PrintStream out = new PrintStream(buff);
195 Context context = Context.enter();
196 Scriptable scope = context.initStandardObjects(null);
197 Scriptable varOut = Context.toObject(out, scope);
198 scope.put("out", scope, varOut);
199 Scriptable varSourceFilePath = Context.toObject(sourceFilePath, scope);
200 scope.put("sourceFilePath", scope, varSourceFilePath);
201 Scriptable varReportJslintErrorsOnly = Context.toObject(this.reportJslintErrorsOnly, scope);
202 scope.put("reportJslintErrorsOnly", scope, varReportJslintErrorsOnly);
203 context.evaluateString(scope, jsLintCode,
204 "mvn-jstools jslint script", 1, null);
205 return buff;
206 }
207
208 /***
209 * Setup the plugin's internal JSLint version
210 *
211 * @param defaultLocale
212 * @throws MavenReportException
213 */
214 protected void setUp(Locale defaultLocale) throws MavenReportException {
215
216
217 try {
218 File destDir = new File(this.buildDir+"/jslint");
219 destDir.mkdirs();
220 copyScript("/jslint/fulljslint.js", this.buildDir+"/jslint/fulljslint.js");
221 copyScript("/jslint/fulljslint_init.js", this.buildDir+"/jslint/fulljslint_init.js");
222
223 } catch (FileNotFoundException fe) {
224 throw new MavenReportException("Cannot find resource in classpath", fe);
225 } catch (IOException ioe) {
226 throw new MavenReportException("Error copying resource to target dir", ioe);
227 }
228 }
229 /***
230 * Tear down the plugin's internal JSLint version
231 *
232 * @param defaultLocale
233 * @throws MavenReportException
234 */
235 protected void tearDown(Locale defaultLocale) throws MavenReportException {
236 try {
237 File runDir = new File(this.buildDir+"/jslint");
238 if(runDir.exists()){
239 FileSystemDirectoryUtils.deleteDirectory(runDir);
240 }
241 } catch (Exception ioe) {
242 throw new MavenReportException("Error clearing up", ioe);
243 }
244 }
245
246 /***
247 * @param jslintSemiPath
248 * @throws FileNotFoundException
249 * @throws IOException
250 */
251 private void copyScript(String classpath, String filePath)
252 throws FileNotFoundException, IOException {
253 InputStream input = this.getClass().getResourceAsStream(classpath);
254 OutputStream output = new FileOutputStream(filePath);
255 IOUtils.copy(input, output);
256 input.close();
257 output.close();
258 }
259
260
261 /***
262 * @see org.apache.maven.reporting.AbstractMavenReport#isExternalReport()
263 */
264 public boolean isExternalReport() {
265 return false;
266 }
267
268
269
270 /***
271 * @see gr.abiss.mvn.plugins.jstools.AbstractBaseJstoolsReport#getBundleKey()
272 */
273 public String getBundleKey() {
274 return "jslint";
275 }
276
277 }