diff --git a/lefthook.yml b/lefthook.yml
index d62a90d150ecfe9e1341d342767bb59d79f043d3..39496e0d2412a791c33f4a672f8e3862267746d3 100644
--- a/lefthook.yml
+++ b/lefthook.yml
@@ -14,7 +14,7 @@ pre-push:
       tags: style
       files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
       glob: '*.{json}'
-      run: scripts/lint-json.sh {files}
+      run: scripts/lint-json -v {files}
     haml-lint:
       tags: view haml style
       files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
diff --git a/package.json b/package.json
index f477b8407a61079ad7bc9f5f82b6bfaf1675754a..0c029a83e6d892d79d1626da12db6237a5c79ecd 100644
--- a/package.json
+++ b/package.json
@@ -247,7 +247,6 @@
     "jest-jasmine2": "^28.1.3",
     "jest-junit": "^12.3.0",
     "jest-util": "^28.1.3",
-    "jsonlint": "^1.6.3",
     "markdownlint-cli": "0.32.2",
     "miragejs": "^0.1.40",
     "mock-apollo-client": "1.2.0",
diff --git a/scripts/lint-json b/scripts/lint-json
new file mode 100755
index 0000000000000000000000000000000000000000..3fa952b13df827f153a529ae5fe60f114e30dcd5
--- /dev/null
+++ b/scripts/lint-json
@@ -0,0 +1,77 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+require "json"
+require "optparse"
+require "rainbow/refinement"
+using Rainbow
+
+options = {}
+
+OptionParser.new do |opts|
+  opts.banner = 'Checks if JSON files are pretty.'
+
+  opts.on('-f', '--format', 'Format JSON files inline.') do
+    options[:format] = true
+  end
+
+  opts.on('-s', '--stats', 'Print statistics after processing.') do
+    options[:stats] = true
+  end
+
+  opts.on('-v', '--verbose', 'Increase verbosity.') do
+    options[:verbose] = true
+  end
+
+  opts.on('-q', '--quiet', 'Do not print anything. Disables -s and -v') do
+    options[:quiet] = true
+  end
+
+  opts.on('-h', '--help', 'Prints this help') do
+    abort opts.to_s
+  end
+end.parse!
+
+def make_pretty(file, format:, verbose:, quiet:)
+  json = File.read(file)
+  pretty = JSON.pretty_generate(JSON.parse(json)) << "\n"
+
+  return :pretty if json == pretty
+
+  puts "#{file} is not pretty" if verbose && !quiet
+  return :todo unless format
+
+  puts "#{file} was not pretty. Fixed!" unless quiet
+  File.write(file, pretty)
+  :formatted
+rescue JSON::ParserError
+  puts "#{file} is invalid. Skipping!" unless quiet
+  :error
+end
+
+results = ARGV
+  .lazy
+  .flat_map { |pattern| Dir.glob(pattern) }
+  .map { |file| make_pretty(file, format: options[:format], verbose: options[:verbose], quiet: options[:quiet]) }
+  .to_a
+
+if options[:stats] && !options[:quiet]
+  puts format("Scanned total=%<total>d, pretty=%<pretty>d, formatted=%<formatted>d, error=%<error>d",
+    total: results.size,
+    pretty: results.count { |result| result == :pretty },
+    formatted: results.count { |result| result == :formatted },
+    error: results.count { |result| result == :error }
+  )
+end
+
+if results.any?(:todo)
+  unless options[:quiet]
+    puts "\nSome of the JSON files are not pretty-printed, you can run:".yellow
+    puts "\tscripts/lint-json -f $(git diff --name-only master... | grep \\\\.json)".white
+    puts "to fix them".yellow
+  end
+
+  exit(1)
+else
+  exit(0)
+end
diff --git a/scripts/lint-json.sh b/scripts/lint-json.sh
deleted file mode 100755
index 685661c789a12ec069764150adc478aa7ff20a90..0000000000000000000000000000000000000000
--- a/scripts/lint-json.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-for file in "$@"
-do
-  yarn run -s jsonlint -p "$file" | perl -pe 'chomp if eof' | diff "$file" -
-done
diff --git a/yarn.lock b/yarn.lock
index ca31d3a0b27c7a1a630ed318956145c5f0120701..7eb3bc2e9f513e1beaefbba020a5645cb1319380 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2664,11 +2664,6 @@
   resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31"
   integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==
 
-JSV@^4.0.x:
-  version "4.0.2"
-  resolved "https://registry.yarnpkg.com/JSV/-/JSV-4.0.2.tgz#d077f6825571f82132f9dffaed587b4029feff57"
-  integrity sha512-ZJ6wx9xaKJ3yFUhq5/sk82PJMuUyLk277I8mQeyDgCTjGdjWJIvPfaU5LIXaMuaN2UO1X3kZH4+lgphublZUHw==
-
 abab@^2.0.5, abab@^2.0.6:
   version "2.0.6"
   resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291"
@@ -2837,11 +2832,6 @@ ansi-styles@^5.0.0:
   resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b"
   integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==
 
-ansi-styles@~1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178"
-  integrity sha512-3iF4FIKdxaVYT3JqQuY3Wat/T2t7TRbbQ94Fu50ZUCbLy4TFbTzr90NOHQodQkNqmeEGCw8WbeP78WNi6SKYUA==
-
 anymatch@^3.0.3, anymatch@~3.1.2:
   version "3.1.2"
   resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
@@ -3555,15 +3545,6 @@ chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2:
     ansi-styles "^4.1.0"
     supports-color "^7.1.0"
 
-chalk@~0.4.0:
-  version "0.4.0"
-  resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f"
-  integrity sha512-sQfYDlfv2DGVtjdoQqxS0cEZDroyG8h6TamA6rvxwlrU5BaSLDx9xhatBYl2pxZ7gmpNaPFVwBtdGdu5rQ+tYQ==
-  dependencies:
-    ansi-styles "~1.0.0"
-    has-color "~0.1.0"
-    strip-ansi "~0.1.0"
-
 char-regex@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
@@ -6539,11 +6520,6 @@ has-bigints@^1.0.1, has-bigints@^1.0.2:
   resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa"
   integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==
 
-has-color@~0.1.0:
-  version "0.1.7"
-  resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f"
-  integrity sha512-kaNz5OTAYYmt646Hkqw50/qyxP2vFnTVu5AQ1Zmk22Kk5+4Qx6BpO8+u7IKsML5fOsFk0ZT0AcCJNYwcvaLBvw==
-
 has-flag@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
@@ -7986,14 +7962,6 @@ jsonfile@^4.0.0:
   optionalDependencies:
     graceful-fs "^4.1.6"
 
-jsonlint@^1.6.3:
-  version "1.6.3"
-  resolved "https://registry.yarnpkg.com/jsonlint/-/jsonlint-1.6.3.tgz#cb5e31efc0b78291d0d862fbef05900adf212988"
-  integrity sha512-jMVTMzP+7gU/IyC6hvKyWpUU8tmTkK5b3BPNuMI9U8Sit+YAWLlZwB6Y6YrdCxfg2kNz05p3XY3Bmm4m26Nv3A==
-  dependencies:
-    JSV "^4.0.x"
-    nomnom "^1.5.x"
-
 jszip@^3.1.3:
   version "3.10.1"
   resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2"
@@ -9427,14 +9395,6 @@ nodemon@^2.0.19:
     touch "^3.1.0"
     undefsafe "^2.0.5"
 
-nomnom@^1.5.x:
-  version "1.8.1"
-  resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7"
-  integrity sha512-5s0JxqhDx9/rksG2BTMVN1enjWSvPidpoSgViZU4ZXULyTe+7jxcCRLB6f42Z0l1xYJpleCBtSyY6Lwg3uu5CQ==
-  dependencies:
-    chalk "~0.4.0"
-    underscore "~1.6.0"
-
 nopt@^4.0.3:
   version "4.0.3"
   resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48"
@@ -11443,11 +11403,6 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1:
   dependencies:
     ansi-regex "^5.0.1"
 
-strip-ansi@~0.1.0:
-  version "0.1.1"
-  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991"
-  integrity sha512-behete+3uqxecWlDAm5lmskaSaISA+ThQ4oNNBDTBJt0x2ppR6IPqfZNuj6BLaLJ/Sji4TPZlcRyOis8wXQTLg==
-
 strip-bom@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
@@ -12058,11 +12013,6 @@ undefsafe@^2.0.5:
   resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c"
   integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==
 
-underscore@~1.6.0:
-  version "1.6.0"
-  resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8"
-  integrity sha512-z4o1fvKUojIWh9XuaVLUDdf86RQiq13AC1dmHbTpoyuu+bquHms76v16CjycCbec87J7z0k//SiQVk0sMdFmpQ==
-
 undici@^5.0.0:
   version "5.8.0"
   resolved "https://registry.yarnpkg.com/undici/-/undici-5.8.0.tgz#dec9a8ccd90e5a1d81d43c0eab6503146d649a4f"