1package org.chromium.devtools.jsdoc; 2 3import com.google.javascript.rhino.head.CompilerEnvirons; 4import com.google.javascript.rhino.head.IRFactory; 5import com.google.javascript.rhino.head.ast.AstNode; 6import com.google.javascript.rhino.head.ast.AstRoot; 7 8import org.chromium.devtools.jsdoc.checks.ContextTrackingValidationCheck; 9 10import java.io.FileNotFoundException; 11import java.io.IOException; 12import java.io.StringReader; 13import java.nio.ByteBuffer; 14import java.nio.charset.StandardCharsets; 15import java.nio.file.FileSystems; 16import java.nio.file.Files; 17import java.util.ArrayList; 18import java.util.List; 19import java.util.concurrent.Callable; 20 21public class FileCheckerCallable implements Callable<ValidatorContext> { 22 23 private final String fileName; 24 25 public FileCheckerCallable(String fileName) { 26 this.fileName = fileName; 27 } 28 29 @Override 30 public ValidatorContext call() { 31 try { 32 ValidatorContext context = new ValidatorContext(readScriptText(), fileName); 33 AstRoot node = parseScript(context); 34 ValidationCheckDispatcher dispatcher = new ValidationCheckDispatcher(context); 35 dispatcher.registerCheck(new ContextTrackingValidationCheck()); 36 node.visit(dispatcher); 37 dispatcher.flush(); 38 return context; 39 } catch (FileNotFoundException e) { 40 logError("File not found: " + fileName); 41 } catch (IOException e) { 42 logError("Failed to read file " + fileName); 43 } 44 return null; 45 } 46 47 private ScriptText readScriptText() throws IOException { 48 byte[] encoded = Files.readAllBytes(FileSystems.getDefault().getPath(fileName)); 49 String text = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(encoded)).toString(); 50 return new ScriptText(text); 51 } 52 53 private static AstRoot parseScript(ValidatorContext context) throws IOException { 54 CompilerEnvirons env = new CompilerEnvirons(); 55 env.setRecoverFromErrors(true); 56 env.setGenerateDebugInfo(true); 57 env.setRecordingLocalJsDocComments(true); 58 env.setAllowSharpComments(true); 59 env.setRecordingComments(true); 60 IRFactory factory = new IRFactory(env); 61 return factory.parse(new StringReader(context.scriptText.text), context.scriptFileName, 1); 62 } 63 64 private static void logError(String message) { 65 System.err.println("ERROR: " + message); 66 } 67 68 private static class ValidationCheckDispatcher extends DoDidVisitorAdapter { 69 private final List<ValidationCheck> checks = new ArrayList<>(2); 70 private final ValidatorContext context; 71 72 public ValidationCheckDispatcher(ValidatorContext context) { 73 this.context = context; 74 } 75 76 public void registerCheck(ValidationCheck check) { 77 check.setContext(context); 78 checks.add(check); 79 } 80 81 @Override 82 public void doVisit(AstNode node) { 83 for (DoDidNodeVisitor visitor : checks) { 84 visitor.doVisit(node); 85 } 86 } 87 88 @Override 89 public void didVisit(AstNode node) { 90 for (ValidationCheck check : checks) { 91 check.didVisit(node); 92 } 93 } 94 } 95} 96