package org.pkg.jstools;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.NativeArray;
import org.mozilla.javascript.NativeObject;
import org.mozilla.javascript.Scriptable;
import org.pkg.jstools.preferences.PreferenceConstants;
/**
* @author praveen.kailas@gmail.com
*
*/
public class JSLint {
private Context context = null;
private Scriptable scope = null;
/**
*
*/
public JSLint() {
}
/**
* Invokes the JSLint validator on the file.
*
* @param file
* the file to validate.
*/
public void validate(IFile file) {
if (file == null) {
return;
}
if (!file.getFileExtension().equalsIgnoreCase("js")) {
return;
}
initContext();
String contents = "";
String options = "/*jslint maxerr: 50 */";
try {
contents = getFileContents(file.getContents());
options = getLintPreferences().toString().replaceAll("=", ": ")
.replaceFirst("\\{", "/*jslint ").replaceAll("\\}", " */");
contents = options + "\n\n" + contents;
scope.put("contents", scope, contents);
context.evaluateString(scope, "results = JSLINT(contents, null);", "JSLint", 1, null);
Scriptable lint = (Scriptable) scope.get("JSLINT", scope);
NativeArray errors = (NativeArray) lint.get("errors", null);
clearMarkers(file);
for (int i = 0; i < errors.getLength(); i++) {
NativeObject error = (NativeObject) errors.get(i, null);
if(error == null) continue;
Double lineNo = ((Double) error.get("line", null)) - 2;
Object reason = error.get("reason", null);
IMarker marker = file.createMarker("org.eclipse.core.resources.problemmarker");
marker.setAttribute(IMarker.LINE_NUMBER, lineNo.intValue());
marker.setAttribute(IMarker.MESSAGE, reason);
marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH);
marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
// Needed to delete own markers!
marker.setAttribute("org.pkg.jstools.marker", true);
}
if (errors.getLength() == 0) {
MessageDialog.openInformation(null, "JSLint", "No errors found.");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
scope = null;
context = null;
}
}
public void clearMarkers(IResource resource) {
IMarker[] markers = null;
try {
markers = resource.findMarkers(
"org.eclipse.core.resources.problemmarker", true,
IResource.DEPTH_INFINITE);
} catch (Exception e) {
e.printStackTrace();
}
for (IMarker marker : markers) {
try {
if (marker.getAttribute("org.pkg.jstools.marker") != null
&& marker.getAttribute("org.pkg.jstools.marker")
.toString() == "true") {
marker.delete();
}
} catch (CoreException e) {
e.printStackTrace();
}
}
}
/**
* @return
*/
private void initContext() {
try {
context = Context.enter();
context.setLanguageVersion(Context.VERSION_1_6);
scope = context.initStandardObjects();
String jsLintCode = getFileContents(JSLint.class
.getResourceAsStream("fulljslint.js"));
context.evaluateString(scope, jsLintCode, "JSLint", 1, null);
} catch (Exception e) {
e.printStackTrace();
}
}
private String getFileContents(InputStream stream) {
StringBuffer contents = new StringBuffer("");
try {
byte[] readBytes = new byte[1024];
int i = 0;
while ((i = stream.read(readBytes)) > 0) {
contents.append(new String(readBytes, 0, i));
}
} catch (Exception e) {
e.printStackTrace();
}
return contents.toString();
}
private Map<String, Object> getLintPreferences() {
Map<String, Object> map = new HashMap<String, Object>();
IPreferenceStore prefs = JSToolsActivator.getDefault().getPreferenceStore();
map.put(PreferenceConstants.JSLINT_ADSAFE, prefs.getBoolean(PreferenceConstants.JSLINT_ADSAFE));
map.put(PreferenceConstants.JSLINT_BITWISE, prefs.getBoolean(PreferenceConstants.JSLINT_BITWISE));
map.put(PreferenceConstants.JSLINT_BROWSER, prefs.getBoolean(PreferenceConstants.JSLINT_BROWSER));
map.put(PreferenceConstants.JSLINT_CAP, prefs.getBoolean(PreferenceConstants.JSLINT_CAP));
map.put(PreferenceConstants.JSLINT_CONFUSION, prefs.getBoolean(PreferenceConstants.JSLINT_CONFUSION));
map.put(PreferenceConstants.JSLINT_CONTINUE, prefs.getBoolean(PreferenceConstants.JSLINT_CONTINUE));
map.put(PreferenceConstants.JSLINT_CSS, prefs.getBoolean(PreferenceConstants.JSLINT_CSS));
map.put(PreferenceConstants.JSLINT_DEBUG, prefs.getBoolean(PreferenceConstants.JSLINT_DEBUG));
map.put(PreferenceConstants.JSLINT_DEVEL, prefs.getBoolean(PreferenceConstants.JSLINT_DEVEL));
map.put(PreferenceConstants.JSLINT_EQEQ, prefs.getBoolean(PreferenceConstants.JSLINT_EQEQ));
map.put(PreferenceConstants.JSLINT_ES5, prefs.getBoolean(PreferenceConstants.JSLINT_ES5));
map.put(PreferenceConstants.JSLINT_EVIL, prefs.getBoolean(PreferenceConstants.JSLINT_EVIL));
map.put(PreferenceConstants.JSLINT_FORIN, prefs.getBoolean(PreferenceConstants.JSLINT_FORIN));
map.put(PreferenceConstants.JSLINT_FRAGMENT, prefs.getBoolean(PreferenceConstants.JSLINT_FRAGMENT));
map.put(PreferenceConstants.JSLINT_NEWCAP, prefs.getBoolean(PreferenceConstants.JSLINT_NEWCAP));
map.put(PreferenceConstants.JSLINT_NODE, prefs.getBoolean(PreferenceConstants.JSLINT_NODE));
map.put(PreferenceConstants.JSLINT_NOMEN, prefs.getBoolean(PreferenceConstants.JSLINT_NOMEN));
map.put(PreferenceConstants.JSLINT_ON, prefs.getBoolean(PreferenceConstants.JSLINT_ON));
map.put(PreferenceConstants.JSLINT_PASSFAIL, prefs.getBoolean(PreferenceConstants.JSLINT_PASSFAIL));
map.put(PreferenceConstants.JSLINT_PLUSPLUS, prefs.getBoolean(PreferenceConstants.JSLINT_PLUSPLUS));
map.put(PreferenceConstants.JSLINT_REGEXP, prefs.getBoolean(PreferenceConstants.JSLINT_REGEXP));
map.put(PreferenceConstants.JSLINT_RHINO, prefs.getBoolean(PreferenceConstants.JSLINT_RHINO));
map.put(PreferenceConstants.JSLINT_SAFE, prefs.getBoolean(PreferenceConstants.JSLINT_SAFE));
map.put(PreferenceConstants.JSLINT_SLOPPY, prefs.getBoolean(PreferenceConstants.JSLINT_SLOPPY));
map.put(PreferenceConstants.JSLINT_SUB, prefs.getBoolean(PreferenceConstants.JSLINT_SUB));
map.put(PreferenceConstants.JSLINT_UNDEF, prefs.getBoolean(PreferenceConstants.JSLINT_UNDEF));
map.put(PreferenceConstants.JSLINT_UNPARAM, prefs.getBoolean(PreferenceConstants.JSLINT_UNPARAM));
map.put(PreferenceConstants.JSLINT_VARS, prefs.getBoolean(PreferenceConstants.JSLINT_VARS));
map.put(PreferenceConstants.JSLINT_WHITE, prefs.getBoolean(PreferenceConstants.JSLINT_WHITE));
map.put(PreferenceConstants.JSLINT_WIDGET, prefs.getBoolean(PreferenceConstants.JSLINT_WIDGET));
map.put(PreferenceConstants.JSLINT_WINDOWS, prefs.getBoolean(PreferenceConstants.JSLINT_WINDOWS));
cleanPrefs(map);
if (prefs.getInt(PreferenceConstants.JSLINT_INDENT) > 0) {
map.put(PreferenceConstants.JSLINT_INDENT, prefs.getInt(PreferenceConstants.JSLINT_INDENT));
}
if (prefs.getInt(PreferenceConstants.JSLINT_LINELEN) > 0) {
map.put(PreferenceConstants.JSLINT_LINELEN, prefs.getInt(PreferenceConstants.JSLINT_LINELEN));
}
if (prefs.getInt(PreferenceConstants.JSLINT_ERRS) > 0) {
map.put(PreferenceConstants.JSLINT_ERRS, prefs.getInt(PreferenceConstants.JSLINT_ERRS));
}
if (prefs.getString(PreferenceConstants.JSLINT_PREDEF).length() > 0) {
//map.put(PreferenceConstants.JSLINT_PREDEF, "[" + prefs.getString(PreferenceConstants.JSLINT_PREDEF) + "]");
}
return map;
}
/**
* @param map
*/
private void cleanPrefs(Map<String, Object> map) {
Set<String> keys = map.keySet();
Map<String, Object> nMap = new HashMap<String, Object>();
for(String key : keys) {
nMap.put(key, map.get(key).toString() != "false");
}
map.clear();
map.putAll(nMap);
}
}