Page MenuHomeSealhub

No OneTemporary

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
index 467d61e1..8e540872 100644
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1,170 +1,172 @@
<?php
/**
* This file is automatically generated. Use 'phutil_mapper.php' to rebuild it.
* @generated
*/
phutil_register_library_map(array(
'class' =>
array(
'ArcanistAmendWorkflow' => 'workflow/amend',
'ArcanistApacheLicenseLinter' => 'lint/linter/apachelicense',
'ArcanistApacheLicenseLinterTestCase' => 'lint/linter/apachelicense/__tests__',
'ArcanistBaseUnitTestEngine' => 'unit/engine/base',
'ArcanistBaseWorkflow' => 'workflow/base',
'ArcanistBranchWorkflow' => 'workflow/branch',
'ArcanistBundle' => 'parser/bundle',
'ArcanistBundleTestCase' => 'parser/bundle/__tests__',
'ArcanistCallConduitWorkflow' => 'workflow/call-conduit',
'ArcanistCapabilityNotSupportedException' => 'workflow/exception/notsupported',
'ArcanistChooseInvalidRevisionException' => 'exception',
'ArcanistChooseNoRevisionsException' => 'exception',
'ArcanistCommitWorkflow' => 'workflow/commit',
'ArcanistConfiguration' => 'configuration',
'ArcanistCoverWorkflow' => 'workflow/cover',
'ArcanistDiffChange' => 'parser/diff/change',
'ArcanistDiffChangeType' => 'parser/diff/changetype',
'ArcanistDiffHunk' => 'parser/diff/hunk',
'ArcanistDiffParser' => 'parser/diff',
'ArcanistDiffParserTestCase' => 'parser/diff/__tests__',
'ArcanistDiffUtils' => 'difference',
'ArcanistDiffUtilsTestCase' => 'difference/__tests__',
'ArcanistDiffWorkflow' => 'workflow/diff',
'ArcanistDifferentialCommitMessage' => 'differential/commitmessage',
'ArcanistDifferentialCommitMessageParserException' => 'differential/commitmessage',
'ArcanistDifferentialRevisionHash' => 'differential/constants/revisionhash',
'ArcanistDifferentialRevisionRef' => 'differential/revision',
'ArcanistDifferentialRevisionStatus' => 'differential/constants/revisionstatus',
'ArcanistDownloadWorkflow' => 'workflow/download',
'ArcanistEventType' => 'events/constant/type',
'ArcanistExportWorkflow' => 'workflow/export',
'ArcanistFilenameLinter' => 'lint/linter/filename',
'ArcanistGeneratedLinter' => 'lint/linter/generated',
'ArcanistGitAPI' => 'repository/api/git',
'ArcanistGitHookPreReceiveWorkflow' => 'workflow/git-hook-pre-receive',
'ArcanistHelpWorkflow' => 'workflow/help',
'ArcanistHookAPI' => 'repository/hookapi/base',
'ArcanistInstallCertificateWorkflow' => 'workflow/install-certificate',
+ 'ArcanistJSHintLinter' => 'lint/linter/jshint',
'ArcanistLiberateLintEngine' => 'lint/engine/liberate',
'ArcanistLiberateWorkflow' => 'workflow/liberate',
'ArcanistLicenseLinter' => 'lint/linter/license',
'ArcanistLintEngine' => 'lint/engine/base',
'ArcanistLintJSONRenderer' => 'lint/renderer',
'ArcanistLintMessage' => 'lint/message',
'ArcanistLintPatcher' => 'lint/patcher',
'ArcanistLintRenderer' => 'lint/renderer',
'ArcanistLintResult' => 'lint/result',
'ArcanistLintSeverity' => 'lint/severity',
'ArcanistLintSummaryRenderer' => 'lint/renderer',
'ArcanistLintWorkflow' => 'workflow/lint',
'ArcanistLinter' => 'lint/linter/base',
'ArcanistLinterTestCase' => 'lint/linter/base/test',
'ArcanistListWorkflow' => 'workflow/list',
'ArcanistMarkCommittedWorkflow' => 'workflow/mark-committed',
'ArcanistMercurialAPI' => 'repository/api/mercurial',
'ArcanistMercurialParser' => 'repository/parser/mercurial',
'ArcanistMercurialParserTestCase' => 'repository/parser/mercurial/__tests__',
'ArcanistMergeWorkflow' => 'workflow/merge',
'ArcanistNoEffectException' => 'exception/usage/noeffect',
'ArcanistNoEngineException' => 'exception/usage/noengine',
'ArcanistNoLintLinter' => 'lint/linter/nolint',
'ArcanistNoLintTestCaseMisnamed' => 'lint/linter/nolint/__tests__',
'ArcanistPEP8Linter' => 'lint/linter/pep8',
'ArcanistPasteWorkflow' => 'workflow/paste',
'ArcanistPatchWorkflow' => 'workflow/patch',
'ArcanistPhutilModuleLinter' => 'lint/linter/phutilmodule',
'ArcanistPhutilTestCase' => 'unit/engine/phutil/testcase',
'ArcanistPhutilTestTerminatedException' => 'unit/engine/phutil/testcase/exception',
'ArcanistPyFlakesLinter' => 'lint/linter/pyflakes',
'ArcanistPyLintLinter' => 'lint/linter/pylint',
'ArcanistRepositoryAPI' => 'repository/api/base',
'ArcanistShellCompleteWorkflow' => 'workflow/shell-complete',
'ArcanistSubversionAPI' => 'repository/api/subversion',
'ArcanistSubversionHookAPI' => 'repository/hookapi/subversion',
'ArcanistSvnHookPreCommitWorkflow' => 'workflow/svn-hook-pre-commit',
'ArcanistTextLinter' => 'lint/linter/text',
'ArcanistTextLinterTestCase' => 'lint/linter/text/__tests__',
'ArcanistUnitTestResult' => 'unit/result',
'ArcanistUnitWorkflow' => 'workflow/unit',
'ArcanistUploadWorkflow' => 'workflow/upload',
'ArcanistUsageException' => 'exception/usage',
'ArcanistUserAbortException' => 'exception/usage/userabort',
'ArcanistWorkingCopyIdentity' => 'workingcopyidentity',
'ArcanistXHPASTLintNamingHook' => 'lint/linter/xhpast/naminghook',
'ArcanistXHPASTLinter' => 'lint/linter/xhpast',
'ArcanistXHPASTLinterTestCase' => 'lint/linter/xhpast/__tests__',
'BranchInfo' => 'branch',
'ExampleLintEngine' => 'lint/engine/example',
'PhutilLintEngine' => 'lint/engine/phutil',
'PhutilModuleRequirements' => 'parser/phutilmodule',
'PhutilUnitTestEngine' => 'unit/engine/phutil',
'PhutilUnitTestEngineTestCase' => 'unit/engine/phutil/__tests__',
'UnitTestableArcanistLintEngine' => 'lint/engine/test',
),
'function' =>
array(
),
'requires_class' =>
array(
'ArcanistAmendWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistApacheLicenseLinter' => 'ArcanistLicenseLinter',
'ArcanistApacheLicenseLinterTestCase' => 'ArcanistLinterTestCase',
'ArcanistBranchWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistBundleTestCase' => 'ArcanistPhutilTestCase',
'ArcanistCallConduitWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistCommitWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistCoverWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistDiffParserTestCase' => 'ArcanistPhutilTestCase',
'ArcanistDiffUtilsTestCase' => 'ArcanistPhutilTestCase',
'ArcanistDiffWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistDownloadWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistEventType' => 'PhutilEventType',
'ArcanistExportWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistFilenameLinter' => 'ArcanistLinter',
'ArcanistGeneratedLinter' => 'ArcanistLinter',
'ArcanistGitAPI' => 'ArcanistRepositoryAPI',
'ArcanistGitHookPreReceiveWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistHelpWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistInstallCertificateWorkflow' => 'ArcanistBaseWorkflow',
+ 'ArcanistJSHintLinter' => 'ArcanistLinter',
'ArcanistLiberateLintEngine' => 'ArcanistLintEngine',
'ArcanistLiberateWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistLicenseLinter' => 'ArcanistLinter',
'ArcanistLintWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistLinterTestCase' => 'ArcanistPhutilTestCase',
'ArcanistListWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistMarkCommittedWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistMercurialAPI' => 'ArcanistRepositoryAPI',
'ArcanistMercurialParserTestCase' => 'ArcanistPhutilTestCase',
'ArcanistMergeWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistNoEffectException' => 'ArcanistUsageException',
'ArcanistNoEngineException' => 'ArcanistUsageException',
'ArcanistNoLintLinter' => 'ArcanistLinter',
'ArcanistNoLintTestCaseMisnamed' => 'ArcanistLinterTestCase',
'ArcanistPEP8Linter' => 'ArcanistLinter',
'ArcanistPasteWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistPatchWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistPhutilModuleLinter' => 'ArcanistLinter',
'ArcanistPyFlakesLinter' => 'ArcanistLinter',
'ArcanistPyLintLinter' => 'ArcanistLinter',
'ArcanistShellCompleteWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistSubversionAPI' => 'ArcanistRepositoryAPI',
'ArcanistSubversionHookAPI' => 'ArcanistHookAPI',
'ArcanistSvnHookPreCommitWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistTextLinter' => 'ArcanistLinter',
'ArcanistTextLinterTestCase' => 'ArcanistLinterTestCase',
'ArcanistUnitWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistUploadWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistUserAbortException' => 'ArcanistUsageException',
'ArcanistXHPASTLinter' => 'ArcanistLinter',
'ArcanistXHPASTLinterTestCase' => 'ArcanistLinterTestCase',
'ExampleLintEngine' => 'ArcanistLintEngine',
'PhutilLintEngine' => 'ArcanistLintEngine',
'PhutilUnitTestEngine' => 'ArcanistBaseUnitTestEngine',
'PhutilUnitTestEngineTestCase' => 'ArcanistPhutilTestCase',
'UnitTestableArcanistLintEngine' => 'ArcanistLintEngine',
),
'requires_interface' =>
array(
),
));
diff --git a/src/lint/linter/jshint/ArcanistJSHintLinter.php b/src/lint/linter/jshint/ArcanistJSHintLinter.php
new file mode 100644
index 00000000..db4c53a2
--- /dev/null
+++ b/src/lint/linter/jshint/ArcanistJSHintLinter.php
@@ -0,0 +1,170 @@
+<?php
+
+/*
+ * Copyright 2011 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Uses "JSHint" to detect errors and potential problems in JavaScript code.
+ * To use this linter, you must install jshint through NPM (Node Package
+ * Manager). You can configure different JSHint options on a per-file basis.
+ *
+ * If you have NodeJS installed you should be able to install jshint with
+ * ##npm install jshint -g## (don't forget the -g flag or NPM will install
+ * the package locally). If your system is unusual, you can manually specify
+ * the location of jshint and its dependencies by configuring these keys in
+ * your .arcconfig:
+ *
+ * lint.jshint.prefix
+ * lint.jshint.bin
+ *
+ * If you want to configure custom options for your project, create a JSON
+ * file with these options and add the path to the file to your .arcconfig
+ * by configuring this key:
+ *
+ * lint.jshint.config
+ *
+ * Example JSON file (config.json):
+ *
+ * {
+ * "predef": [ // Custom globals
+ * "myGlobalVariable",
+ * "anotherGlobalVariable"
+ * ],
+ *
+ * "es5": true, // Allow ES5 syntax
+ * "strict": true // Require strict mode
+ * }
+ *
+ * For more options see http://www.jshint.com/options/.
+ *
+ * @group linter
+ */
+class ArcanistJSHintLinter extends ArcanistLinter {
+
+ const JSHINT_ERROR = 1;
+
+ public function getLinterName() {
+ return 'JSHint';
+ }
+
+ public function getLintSeverityMap() {
+ return array(
+ self::JSHINT_ERROR => 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
+ list($err) = exec_manual('which %s', $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("{$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) = $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 output we can't parse. Check that your JSHint installation.\n".
+ "Output:\n".
+ $stdout);
+ }
+
+ foreach ($errors as $err) {
+ $this->raiseLintAtLine(
+ $err->line,
+ $err->col,
+ self::JSHINT_ERROR,
+ $err->reason);
+ }
+ }
+}
diff --git a/src/lint/linter/jshint/__init__.php b/src/lint/linter/jshint/__init__.php
new file mode 100644
index 00000000..80349853
--- /dev/null
+++ b/src/lint/linter/jshint/__init__.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('arcanist', 'lint/linter/base');
+phutil_require_module('arcanist', 'lint/message');
+phutil_require_module('arcanist', 'lint/severity');
+
+phutil_require_module('phutil', 'future/exec');
+
+
+phutil_require_source('ArcanistJSHintLinter.php');
diff --git a/src/lint/linter/jshint/reporter.js b/src/lint/linter/jshint/reporter.js
new file mode 100644
index 00000000..b34bd736
--- /dev/null
+++ b/src/lint/linter/jshint/reporter.js
@@ -0,0 +1,18 @@
+module.exports = {
+ reporter: function (results) {
+ var report = [];
+
+ results.forEach(function (result) {
+ var error = result.error;
+
+ report.push({
+ 'file': result.file,
+ 'line': error.line,
+ 'col': error.character,
+ 'reason': error.reason
+ });
+ });
+
+ process.stdout.write(JSON.stringify(report));
+ }
+};

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 8, 06:25 (1 d, 13 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1034104
Default Alt Text
(15 KB)

Event Timeline