Wrote some simple code to prevent saving .json if it doesn't parse

I was working with NPM package.json files a lot lately and I often found myself saving them in an unparseable state. json-ts-mode highlights syntax errors in yellow but it wasn’t enough.

I didn’t want to use flymake-eslint becuase it requires having the jsonlint binary in the PATH and I just wanted a simple Lisp solution.

The code tries to parse the current buffer on save using Emacs’ built-in json-parse-string and moves the cursor to the location of the parsing error if it fails.

The below code naively assumes that the saved buffer is always the current buffer, which may very well not be the case (e.g. (save-some-buffers)).

It also probably won’t save JSON5 files which have // comments inside because json-parse-string won’t handle that.


<span style="color:#323232;">(setq write-file-functions
</span><span style="color:#323232;">      (lambda ()
</span><span style="color:#323232;">	(if (eq major-mode 'json-ts-mode)
</span><span style="color:#323232;">            (condition-case err
</span><span style="color:#323232;">		(json-parse-string
</span><span style="color:#323232;">		 (buffer-substring-no-properties
</span><span style="color:#323232;">		  (point-min)
</span><span style="color:#323232;">		  (point-max)))
</span><span style="color:#323232;">              (json-parse-error
</span><span style="color:#323232;">               (goto-char (nth 5 err)) (error err))))))
</span>
StrangeAstronomer, (edited )

I find the various linters and checkers a bit too intrusive while I’m trying to code - I prefer to just have a check when I stop fiddling with the code and save it. So I have these checks run in after-save-hook - if there are errors, I get a popup otherwise nothing and all is good:


<span style="color:#323232;">;; ** syntax checking on file save:
</span><span style="color:#323232;">(defun bh/check-syntax ()
</span><span style="color:#323232;">  "Check syntax for various languages."
</span><span style="color:#323232;">  (when (eq major-mode 'emacs-lisp-mode)
</span><span style="color:#323232;">    (ignore-errors (kill-buffer byte-compile-log-buffer))
</span><span style="color:#323232;">    (let ((byte-compile-warnings '(not free-vars obsolete unresolved)))
</span><span style="color:#323232;">      (unless (byte-compile-file buffer-file-name)
</span><span style="color:#323232;">        (pop-to-buffer byte-compile-log-buffer))))
</span><span style="color:#323232;">  (when (eq major-mode 'sh-mode)
</span><span style="color:#323232;">    (compile (format "bash -n %s && shellcheck -f gcc %s" buffer-file-name buffer-file-name) t))
</span><span style="color:#323232;">  (when (eq major-mode 'ruby-mode)
</span><span style="color:#323232;">    (compile (format "ruby -c %s" buffer-file-name) t))
</span><span style="color:#323232;">  (when (eq major-mode 'python-mode)
</span><span style="color:#323232;">    (compile (format "python -B -m py_compile %s" buffer-file-name) t))
</span><span style="color:#323232;">  (when (eq major-mode 'awk-mode)
</span><span style="color:#323232;">    (compile (format "AWKPATH=$PATH gawk --lint --source 'BEGIN { exit(0) } END { exit(0) }' --file %s" buffer-file-name) t)))
</span>

(add-hook 'after-save-hook #'bh/check-syntax)

I don’t work much with json files but I daresay the idea could be extended to them. Sorry about the crappy elisp.

  • All
  • Subscribed
  • Moderated
  • Favorites
  • emacs@lemmy.ml
  • DreamBathrooms
  • magazineikmin
  • InstantRegret
  • GTA5RPClips
  • ethstaker
  • Youngstown
  • everett
  • slotface
  • osvaldo12
  • rosin
  • mdbf
  • kavyap
  • thenastyranch
  • ngwrru68w68
  • megavids
  • Durango
  • modclub
  • cubers
  • khanakhh
  • Leos
  • tacticalgear
  • cisconetworking
  • vwfavf
  • tester
  • anitta
  • normalnudes
  • provamag3
  • JUstTest
  • All magazines