Page MenuHomePhabricator

D8988.id21344.diff
No OneTemporary

D8988.id21344.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -84,6 +84,8 @@
'ArcanistInstallCertificateWorkflow' => 'workflow/ArcanistInstallCertificateWorkflow.php',
'ArcanistJSHintLinter' => 'lint/linter/ArcanistJSHintLinter.php',
'ArcanistJSHintLinterTestCase' => 'lint/linter/__tests__/ArcanistJSHintLinterTestCase.php',
+ 'ArcanistJSONLintLinter' => 'lint/linter/ArcanistJSONLintLinter.php',
+ 'ArcanistJSONLintLinterTestCase' => 'lint/linter/__tests__/ArcanistJSONLintLinterTestCase.php',
'ArcanistLandWorkflow' => 'workflow/ArcanistLandWorkflow.php',
'ArcanistLiberateWorkflow' => 'workflow/ArcanistLiberateWorkflow.php',
'ArcanistLintConsoleRenderer' => 'lint/renderer/ArcanistLintConsoleRenderer.php',
@@ -245,6 +247,8 @@
'ArcanistInstallCertificateWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistJSHintLinter' => 'ArcanistExternalLinter',
'ArcanistJSHintLinterTestCase' => 'ArcanistArcanistLinterTestCase',
+ 'ArcanistJSONLintLinter' => 'ArcanistExternalLinter',
+ 'ArcanistJSONLintLinterTestCase' => 'ArcanistArcanistLinterTestCase',
'ArcanistLandWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistLiberateWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistLintConsoleRenderer' => 'ArcanistLintRenderer',
diff --git a/src/lint/linter/ArcanistJSONLintLinter.php b/src/lint/linter/ArcanistJSONLintLinter.php
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/ArcanistJSONLintLinter.php
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * A linter for JSON files.
+ */
+final class ArcanistJSONLintLinter extends ArcanistExternalLinter {
+ public function getLinterName() {
+ return 'JSON';
+ }
+
+ public function getLinterConfigurationName() {
+ return 'jsonlint';
+ }
+
+ public function getDefaultBinary() {
+ return 'jsonlint';
+ }
+
+ public function getVersion() {
+ // NOTE: `jsonlint --version` returns a non-zero exit status.
+ list($err, $stdout) = exec_manual(
+ '%C --version',
+ $this->getExecutableCommand());
+
+ $matches = array();
+ if (preg_match('/^(?P<version>\d+\.\d+\.\d+)$/', $stdout, $matches)) {
+ $version = $matches['version'];
+ } else {
+ return false;
+ }
+ }
+
+ public function getInstallInstructions() {
+ return pht('Install jsonlint using `npm install -g jsonlint`.');
+ }
+
+ public function shouldExpectCommandErrors() {
+ return true;
+ }
+
+ public function supportsReadDataFromStdin() {
+ return true;
+ }
+
+ protected function getMandatoryFlags() {
+ return array(
+ '--compact',
+ );
+ }
+
+ protected function parseLinterOutput($path, $err, $stdout, $stderr) {
+ $lines = phutil_split_lines($stderr, false);
+
+ $messages = array();
+ foreach ($lines as $line) {
+ $matches = null;
+ $match = preg_match(
+ '/^(?:(?<path>.+): )?' .
+ 'line (?<line>\d+), col (?<column>\d+), ' .
+ '(?<description>.*)$/',
+ $line,
+ $matches);
+
+ if ($match) {
+ $message = new ArcanistLintMessage();
+ $message->setPath($path);
+ $message->setLine($matches['line']);
+ $message->setChar($matches['column']);
+ $message->setCode($this->getLinterName());
+ $message->setDescription(ucfirst($matches['description']));
+ $message->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR);
+
+ $messages[] = $message;
+ }
+ }
+
+ if ($err && !$messages) {
+ return false;
+ }
+
+ return $messages;
+ }
+}
diff --git a/src/lint/linter/__tests__/ArcanistJSONLintLinterTestCase.php b/src/lint/linter/__tests__/ArcanistJSONLintLinterTestCase.php
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/ArcanistJSONLintLinterTestCase.php
@@ -0,0 +1,12 @@
+<?php
+
+final class ArcanistJSONLintLinterTestCase
+ extends ArcanistArcanistLinterTestCase {
+
+ public function testJSONLintLinter() {
+ $this->executeTestsInDirectory(
+ dirname(__FILE__).'/jsonlint/',
+ new ArcanistJSONLintLinter());
+ }
+
+}
diff --git a/src/lint/linter/__tests__/jsonlint/1.lint-test b/src/lint/linter/__tests__/jsonlint/1.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/1.lint-test
@@ -0,0 +1,59 @@
+[
+ "JSON Test Pattern pass1",
+ {"object with 1 member":["array with 1 element"]},
+ {},
+ [],
+ -42,
+ true,
+ false,
+ null,
+ {
+ "integer": 1234567890,
+ "real": -9876.543210,
+ "e": 0.123456789e-12,
+ "E": 1.234567890E+34,
+ "": 23456789012E66,
+ "zero": 0,
+ "one": 1,
+ "space": " ",
+ "quote": "\"",
+ "backslash": "\\",
+ "controls": "\b\f\n\r\t",
+ "slash": "/ & \/",
+ "alpha": "abcdefghijklmnopqrstuvwyz",
+ "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
+ "digit": "0123456789",
+ "0123456789": "digit",
+ "special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
+ "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
+ "true": true,
+ "false": false,
+ "null": null,
+ "array":[ ],
+ "object":{ },
+ "address": "50 St. James Street",
+ "url": "http://www.JSON.org/",
+ "comment": "// /* <!-- --",
+ "# -- --> */": " ",
+ " s p a c e d " :[1,2 , 3
+
+,
+
+4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7],
+ "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
+ "quotes": "&#34; \u0022 %22 0x22 034 &#x22;",
+ "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
+: "A key can be any string"
+ },
+ 0.5 ,98.6
+,
+99.44
+,
+
+1066,
+1e1,
+0.1e1,
+1e-1,
+1e00,2e+00,2e-00
+,"rosebud"]
+~~~~~~~~~~
diff --git a/src/lint/linter/__tests__/jsonlint/10.lint-test b/src/lint/linter/__tests__/jsonlint/10.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/10.lint-test
@@ -0,0 +1,3 @@
+{"Extra value after close": true} "misplaced quoted value"
+~~~~~~~~~~
+error:1:33
diff --git a/src/lint/linter/__tests__/jsonlint/11.lint-test b/src/lint/linter/__tests__/jsonlint/11.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/11.lint-test
@@ -0,0 +1,3 @@
+{"Illegal expression": 1 + 2}
+~~~~~~~~~~
+error:1:24
diff --git a/src/lint/linter/__tests__/jsonlint/12.lint-test b/src/lint/linter/__tests__/jsonlint/12.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/12.lint-test
@@ -0,0 +1,3 @@
+{"Illegal invocation": alert()}
+~~~~~~~~~~
+error:1:22
diff --git a/src/lint/linter/__tests__/jsonlint/13.lint-test b/src/lint/linter/__tests__/jsonlint/13.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/13.lint-test
@@ -0,0 +1,3 @@
+{"Numbers cannot have leading zeroes": 013}
+~~~~~~~~~~
+error:1:38
diff --git a/src/lint/linter/__tests__/jsonlint/14.lint-test b/src/lint/linter/__tests__/jsonlint/14.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/14.lint-test
@@ -0,0 +1,3 @@
+{"Numbers cannot be hex": 0x14}
+~~~~~~~~~~
+error:1:25
diff --git a/src/lint/linter/__tests__/jsonlint/15.lint-test b/src/lint/linter/__tests__/jsonlint/15.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/15.lint-test
@@ -0,0 +1,3 @@
+["Illegal backslash escape: \x15"]
+~~~~~~~~~~
+error:1:1
diff --git a/src/lint/linter/__tests__/jsonlint/16.lint-test b/src/lint/linter/__tests__/jsonlint/16.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/16.lint-test
@@ -0,0 +1,3 @@
+[\naked]
+~~~~~~~~~~
+error:1:1
diff --git a/src/lint/linter/__tests__/jsonlint/17.lint-test b/src/lint/linter/__tests__/jsonlint/17.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/17.lint-test
@@ -0,0 +1,3 @@
+["Illegal backslash escape: \017"]
+~~~~~~~~~~
+error:1:1
diff --git a/src/lint/linter/__tests__/jsonlint/19.lint-test b/src/lint/linter/__tests__/jsonlint/19.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/19.lint-test
@@ -0,0 +1,3 @@
+{"Missing colon" null}
+~~~~~~~~~~
+error:1:16
diff --git a/src/lint/linter/__tests__/jsonlint/2.lint-test b/src/lint/linter/__tests__/jsonlint/2.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/2.lint-test
@@ -0,0 +1,2 @@
+[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
+~~~~~~~~~~
diff --git a/src/lint/linter/__tests__/jsonlint/20.lint-test b/src/lint/linter/__tests__/jsonlint/20.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/20.lint-test
@@ -0,0 +1,3 @@
+{"Double colon":: null}
+~~~~~~~~~~
+error:1:16
diff --git a/src/lint/linter/__tests__/jsonlint/21.lint-test b/src/lint/linter/__tests__/jsonlint/21.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/21.lint-test
@@ -0,0 +1,3 @@
+{"Comma instead of colon", null}
+~~~~~~~~~~
+error:1:25
diff --git a/src/lint/linter/__tests__/jsonlint/22.lint-test b/src/lint/linter/__tests__/jsonlint/22.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/22.lint-test
@@ -0,0 +1,3 @@
+["Colon instead of comma": false]
+~~~~~~~~~~
+error:1:25
diff --git a/src/lint/linter/__tests__/jsonlint/23.lint-test b/src/lint/linter/__tests__/jsonlint/23.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/23.lint-test
@@ -0,0 +1,3 @@
+["Bad value", truth]
+~~~~~~~~~~
+error:1:13
diff --git a/src/lint/linter/__tests__/jsonlint/24.lint-test b/src/lint/linter/__tests__/jsonlint/24.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/24.lint-test
@@ -0,0 +1,3 @@
+['single quote']
+~~~~~~~~~~
+error:1:1
diff --git a/src/lint/linter/__tests__/jsonlint/25.lint-test b/src/lint/linter/__tests__/jsonlint/25.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/25.lint-test
@@ -0,0 +1,3 @@
+[" tab character in string "]
+~~~~~~~~~~
+error:1:1
diff --git a/src/lint/linter/__tests__/jsonlint/26.lint-test b/src/lint/linter/__tests__/jsonlint/26.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/26.lint-test
@@ -0,0 +1,3 @@
+["tab\ character\ in\ string\ "]
+~~~~~~~~~~
+error:1:1
diff --git a/src/lint/linter/__tests__/jsonlint/27.lint-test b/src/lint/linter/__tests__/jsonlint/27.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/27.lint-test
@@ -0,0 +1,4 @@
+["line
+break"]
+~~~~~~~~~~
+error:1:1
diff --git a/src/lint/linter/__tests__/jsonlint/28.lint-test b/src/lint/linter/__tests__/jsonlint/28.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/28.lint-test
@@ -0,0 +1,4 @@
+["line\
+break"]
+~~~~~~~~~~
+error:1:1
diff --git a/src/lint/linter/__tests__/jsonlint/29.lint-test b/src/lint/linter/__tests__/jsonlint/29.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/29.lint-test
@@ -0,0 +1,3 @@
+[0e]
+~~~~~~~~~~
+error:1:1
diff --git a/src/lint/linter/__tests__/jsonlint/3.lint-test b/src/lint/linter/__tests__/jsonlint/3.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/3.lint-test
@@ -0,0 +1,7 @@
+{
+ "JSON Test Pattern pass3": {
+ "The outermost value": "must be an object or array.",
+ "In this test": "It is an object."
+ }
+}
+~~~~~~~~~~
diff --git a/src/lint/linter/__tests__/jsonlint/30.lint-test b/src/lint/linter/__tests__/jsonlint/30.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/30.lint-test
@@ -0,0 +1,3 @@
+[0e+]
+~~~~~~~~~~
+error:1:1
diff --git a/src/lint/linter/__tests__/jsonlint/31.lint-test b/src/lint/linter/__tests__/jsonlint/31.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/31.lint-test
@@ -0,0 +1,3 @@
+[0e+-1]
+~~~~~~~~~~
+error:1:1
diff --git a/src/lint/linter/__tests__/jsonlint/32.lint-test b/src/lint/linter/__tests__/jsonlint/32.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/32.lint-test
@@ -0,0 +1,3 @@
+{"Comma instead if closing brace": true,
+~~~~~~~~~~
+error:1:40
diff --git a/src/lint/linter/__tests__/jsonlint/33.lint-test b/src/lint/linter/__tests__/jsonlint/33.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/33.lint-test
@@ -0,0 +1,3 @@
+["mismatch"}
+~~~~~~~~~~
+error:1:11
diff --git a/src/lint/linter/__tests__/jsonlint/34.lint-test b/src/lint/linter/__tests__/jsonlint/34.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/34.lint-test
@@ -0,0 +1,3 @@
+{"extra brace": 1}}
+~~~~~~~~~~
+error:1:18
diff --git a/src/lint/linter/__tests__/jsonlint/4.lint-test b/src/lint/linter/__tests__/jsonlint/4.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/4.lint-test
@@ -0,0 +1,3 @@
+["extra comma",]
+~~~~~~~~~~
+error:1:15
diff --git a/src/lint/linter/__tests__/jsonlint/5.lint-test b/src/lint/linter/__tests__/jsonlint/5.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/5.lint-test
@@ -0,0 +1,3 @@
+["double extra comma",,]
+~~~~~~~~~~
+error:1:22
diff --git a/src/lint/linter/__tests__/jsonlint/6.lint-test b/src/lint/linter/__tests__/jsonlint/6.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/6.lint-test
@@ -0,0 +1,3 @@
+[, "<-- missing value"]
+~~~~~~~~~~
+error:1:1
diff --git a/src/lint/linter/__tests__/jsonlint/7.lint-test b/src/lint/linter/__tests__/jsonlint/7.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/7.lint-test
@@ -0,0 +1,3 @@
+["Comma after the close"],
+~~~~~~~~~~
+error:1:25
diff --git a/src/lint/linter/__tests__/jsonlint/8.lint-test b/src/lint/linter/__tests__/jsonlint/8.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/8.lint-test
@@ -0,0 +1,3 @@
+["Extra close"]]
+~~~~~~~~~~
+error:1:15
diff --git a/src/lint/linter/__tests__/jsonlint/9.lint-test b/src/lint/linter/__tests__/jsonlint/9.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/jsonlint/9.lint-test
@@ -0,0 +1,3 @@
+{"Extra comma": true,}
+~~~~~~~~~~
+error:1:21

File Metadata

Mime Type
text/plain
Expires
Fri, Oct 18, 2:53 PM (3 w, 4 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6712342
Default Alt Text
D8988.id21344.diff (14 KB)

Event Timeline