if (arguments.length == 0) {
arguments[0] = ".";
}
const File = Java.type("java.io.File");
const file = new File(arguments[0]);
if (!file.exists()) {
print(arguments[0] + " is neither a file nor a directory");
exit(1);
}
const Files = Java.type("java.nio.file.Files");
const EmptyStatementTree = Java.type("jdk.nashorn.api.tree.EmptyStatementTree");
const IdentifierTree = Java.type("jdk.nashorn.api.tree.IdentifierTree");
const MemberSelectTree = Java.type("jdk.nashorn.api.tree.MemberSelectTree");
const Parser = Java.type("jdk.nashorn.api.tree.Parser");
const SimpleTreeVisitor = Java.type("jdk.nashorn.api.tree.SimpleTreeVisitorES6");
const Tree = Java.type("jdk.nashorn.api.tree.Tree");
const parser = Parser.create("-scripting", "--language=es6");
const globals = new Set();
for (let name of Object.getOwnPropertyNames(this)) {
globals.add(name);
}
const checkFile = function(file) {
print("Parsing " + file);
const ast = parser.parse(file, print);
if (!ast) {
print("FAILED to parse: " + file);
return;
}
const checker = new (Java.extend(SimpleTreeVisitor)) {
lineMap: null,
printWarning(node, msg) {
var pos = node.startPosition;
var line = this.lineMap.getLineNumber(pos);
var column = this.lineMap.getColumnNumber(pos);
print(`WARNING: ${msg} in ${file} @ ${line}:${column}`);
},
printWithWarning(node) {
this.printWarning(node, "'with' usage");
},
printProtoWarning(node) {
this.printWarning(node, "__proto__ usage");
},
printScopeDeleteWarning(node, varName) {
this.printWarning(node, `delete ${varName}`);
},
hasOnlyEmptyStats(stats) {
const itr = stats.iterator();
while (itr.hasNext()) {
if (! (itr.next() instanceof EmptyStatementTree)) {
return false;
}
}
return true;
},
checkProto(node, name) {
if (name == "__proto__") {
this.printProtoWarning(node);
}
},
checkAssignment(lhs) {
if (lhs instanceof IdentifierTree && globals.has(lhs.name)) {
this.printWarning(lhs, `assignment to standard global "${lhs.name}"`);
} else if (lhs instanceof MemberSelectTree) {
const expr = lhs.expression;
if (expr instanceof MemberSelectTree &&
expr.expression instanceof IdentifierTree &&
globals.has(expr.expression.name) &&
"prototype" == expr.identifier) {
this.printWarning(lhs,
`property set "${expr.expression.name}.prototype.${lhs.identifier}"`);
}
}
},
visitAssignment(node, extra) {
this.checkAssignment(node.variable);
Java.super(checker).visitAssignment(node, extra);
},
visitCatch(node, extra) {
var stats = node.block.statements;
if (stats.empty || this.hasOnlyEmptyStats(stats)) {
this.printWarning(node, "exception swallow");
}
Java.super(checker).visitCatch(node, extra);
},
visitCompilationUnit(node, extra) {
this.lineMap = node.lineMap;
Java.super(checker).visitCompilationUnit(node, extra);
},
visitFunctionCall(node, extra) {
var func = node.functionSelect;
if (func instanceof IdentifierTree && func.name == "eval") {
this.printWarning(node, "eval call found");
}
Java.super(checker).visitFunctionCall(node, extra);
},
visitIdentifier(node, extra) {
this.checkProto(node, node.name);
Java.super(checker).visitIdentifier(node, extra);
},
visitMemberSelect(node, extra) {
this.checkProto(node, node.identifier);
Java.super(checker).visitMemberSelect(node, extra);
},
visitProperty(node, extra) {
this.checkProto(node, node.key);
Java.super(checker).visitProperty(node, extra);
},
visitUnary(node, extra) {
if (node.kind == Tree.Kind.DELETE &&