ArcanistLintSeverity::SEVERITY_ERROR ); } public function getLintNameMap() { return array( self::JSHINT_ERROR => "JSHint Error" ); } public function getJSHintOptions() { $working_copy = $this->getEngine()->getWorkingCopy(); $options = '--reporter '.dirname(realpath(__FILE__)).'/reporter.js'; $config = $working_copy->getConfig('lint.jshint.config'); if ($config !== null) { $config = Filesystem::resolvePath( $config, $working_copy->getProjectRoot()); if (!Filesystem::pathExists($config)) { throw new ArcanistUsageException( "Unable to find custom options file defined by ". "'lint.jshint.config'. Make sure that the path is correct."); } $options .= ' --config '.$config; } return $options; } private function getJSHintPath() { $working_copy = $this->getEngine()->getWorkingCopy(); $prefix = $working_copy->getConfig('lint.jshint.prefix'); $bin = $working_copy->getConfig('lint.jshint.bin'); if ($bin === null) { $bin = "jshint"; } if ($prefix !== null) { $bin = $prefix."/".$bin; if (!Filesystem::pathExists($bin)) { throw new ArcanistUsageException( "Unable to find JSHint binary in a specified directory. Make sure ". "that 'lint.jshint.prefix' and 'lint.jshint.bin' keys are set ". "correctly. If you'd rather use a copy of JSHint installed ". "globally, you can just remove these keys from your .arcconfig"); } return $bin; } // Look for globally installed JSHint $cmd = (phutil_is_windows()) ? 'where %s' : 'which %s'; list($err) = exec_manual($cmd, $bin); if ($err) { throw new ArcanistUsageException( "JSHint does not appear to be installed on this system. Install it ". "(e.g., with 'npm install jshint -g') or configure ". "'lint.jshint.prefix' in your .arcconfig to point to the directory ". "where it resides."); } return $bin; } public function willLintPaths(array $paths) { $jshint_bin = $this->getJSHintPath(); $jshint_options = $this->getJSHintOptions(); $futures = array(); foreach ($paths as $path) { $filepath = $this->getEngine()->getFilePathOnDisk($path); $futures[$path] = new ExecFuture( "%s %s %C", $jshint_bin, $filepath, $jshint_options); } foreach (Futures($futures)->limit(8) as $path => $future) { $this->results[$path] = $future->resolve(); } } public function lintPath($path) { list($rc, $stdout, $stderr) = $this->results[$path]; if ($rc === 0) { return; } $errors = json_decode($stdout); if (!is_array($errors)) { // Something went wrong and we can't decode the output. Exit abnormally. throw new ArcanistUsageException( "JSHint returned unparseable output.\n". "stdout:\n\n{$stdout}". "stderr:\n\n{$stderr}"); } foreach ($errors as $err) { $this->raiseLintAtLine( $err->line, $err->col, self::JSHINT_ERROR, $err->reason); } } }