1 package org.chromium.devtools.jsdoc;
3 import com.google.javascript.jscomp.Compiler;
4 import com.google.javascript.jscomp.NodeTraversal;
5 import com.google.javascript.jscomp.parsing.Config;
6 import com.google.javascript.jscomp.parsing.Config.LanguageMode;
7 import com.google.javascript.jscomp.parsing.ParserRunner;
8 import com.google.javascript.rhino.ErrorReporter;
9 import com.google.javascript.rhino.Node;
11 import org.chromium.devtools.jsdoc.checks.ContextTrackingValidationCheck;
13 import java.io.FileNotFoundException;
14 import java.io.IOException;
15 import java.nio.ByteBuffer;
16 import java.nio.charset.StandardCharsets;
17 import java.nio.file.FileSystems;
18 import java.nio.file.Files;
19 import java.util.ArrayList;
20 import java.util.List;
21 import java.util.concurrent.Callable;
23 public class FileCheckerCallable implements Callable<ValidatorContext> {
25 private final String fileName;
27 public FileCheckerCallable(String fileName) {
28 this.fileName = fileName;
32 public ValidatorContext call() {
34 ValidatorContext context = new ValidatorContext(readScriptText(), fileName);
35 ValidationCheckDispatcher dispatcher = new ValidationCheckDispatcher(context);
36 dispatcher.registerCheck(new ContextTrackingValidationCheck());
37 NodeTraversal.traverse(new Compiler(), parseScript(context), dispatcher);
39 } catch (FileNotFoundException e) {
40 logError("File not found: " + fileName);
41 } catch (IOException e) {
42 logError("Failed to read file " + fileName);
47 private String readScriptText() throws IOException {
48 byte[] encoded = Files.readAllBytes(FileSystems.getDefault().getPath(fileName));
49 String text = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(encoded)).toString();
53 private static Node parseScript(final ValidatorContext context) {
54 Config config = ParserRunner.createConfig(true, LanguageMode.ECMASCRIPT5_STRICT, true);
55 ErrorReporter errorReporter = new ErrorReporter() {
57 public void warning(String message, String sourceName, int line, int lineOffset) {
62 public void error(String message, String sourceName, int line, int lineOffset) {
63 logError("at " + sourceName + ":" + line + ":" + lineOffset);
67 return ParserRunner.parse(
68 context.sourceFile, context.sourceFile.getCode(), config, errorReporter).ast;
69 } catch (IOException e) {
70 // Does not happen with preloaded files.
75 private static void logError(String message) {
76 System.err.println("ERROR: " + message);
79 private static class ValidationCheckDispatcher extends DoDidVisitorAdapter {
80 private final List<ValidationCheck> checks = new ArrayList<>(2);
81 private final ValidatorContext context;
83 public ValidationCheckDispatcher(ValidatorContext context) {
84 this.context = context;
87 public void registerCheck(ValidationCheck check) {
88 check.setContext(context);
93 public void doVisit(Node node) {
94 for (DoDidNodeVisitor visitor : checks) {
95 visitor.doVisit(node);
100 public void didVisit(Node node) {
101 for (ValidationCheck check : checks) {
102 check.didVisit(node);