branch: elpa/flymake-collection
commit e9a1e2ab269f0418963665d991423f8afae6bae6
Author: Mohsin Kaleem <mohk...@kisara.moe>
Commit: Mohsin Kaleem <mohk...@kisara.moe>

    Cleanup flymake-rest-define and remove flymake-rest-parse-*
    
    This commit deletes the previous `flymake-rest-parse-rx.el` and
    `flymake-rest-parse-enumerate.el` files and adds the functionality
    for them into `flymake-rest-define.el`. To use parse-rx use
    `flymake-rest-define-rx` and to use parse-enumerate use
    `flymake-rest-define-enumerate`.
    
    This was done to make byte compilation cleaner. Now we don't lexically
    assign any variables (such as flymake-rest-context) when it will remain
    unused for a lot of syntax checkers.
---
 checkers/flymake-rest-awk-gawk.el     |  14 +-
 checkers/flymake-rest-clang.el        |  14 +-
 checkers/flymake-rest-eslint.el       |  48 +--
 checkers/flymake-rest-gcc.el          |  14 +-
 checkers/flymake-rest-html-tidy.el    |  12 +-
 checkers/flymake-rest-jq.el           |  11 +-
 checkers/flymake-rest-jsonlint.el     |  11 +-
 checkers/flymake-rest-less.el         |  10 +-
 checkers/flymake-rest-lua.el          |  16 +-
 checkers/flymake-rest-luacheck.el     |  14 +-
 checkers/flymake-rest-markdownlint.el |  10 +-
 checkers/flymake-rest-mypy.el         |  14 +-
 checkers/flymake-rest-proselint.el    |  41 ++-
 checkers/flymake-rest-pycodestyle.el  |  13 +-
 checkers/flymake-rest-pylint.el       |  44 +--
 checkers/flymake-rest-rubocop.el      |  14 +-
 checkers/flymake-rest-shellcheck.el   |  41 ++-
 checkers/flymake-rest-sql-lint.el     |  10 +-
 checkers/flymake-rest-sqlint.el       |  32 +-
 checkers/flymake-rest-xmllint.el      |  14 +-
 checkers/flymake-rest-yamllint.el     |  13 +-
 flymake-rest-define.el                | 599 ++++++++++++++++++++++++----------
 flymake-rest-parse-enumerate.el       |  56 ----
 flymake-rest-parse-rx.el              | 164 ----------
 flymake-rest.el                       |   4 +-
 25 files changed, 619 insertions(+), 614 deletions(-)

diff --git a/checkers/flymake-rest-awk-gawk.el 
b/checkers/flymake-rest-awk-gawk.el
index d1b6a694ab..0f4e3dd77f 100644
--- a/checkers/flymake-rest-awk-gawk.el
+++ b/checkers/flymake-rest-awk-gawk.el
@@ -26,11 +26,10 @@
 (require 'flymake-rest)
 
 (eval-when-compile
-  (require 'flymake-rest-define)
-  (require 'flymake-rest-parse-rx))
+  (require 'flymake-rest-define))
 
 ;;;###autoload (autoload 'flymake-rest-awk-gawk "flymake-rest-awk-gawk")
-(flymake-rest-define flymake-rest-awk-gawk
+(flymake-rest-define-rx flymake-rest-awk-gawk
   "GNU awk's built-in --lint checker."
   :title "gawk-awk"
   :pre-let ((gawk-exec (executable-find "gawk")))
@@ -39,14 +38,13 @@
   :write-type 'pipe
   :command (list gawk-exec
                  ;; Avoid code execution.  See 
https://github.com/w0rp/ale/pull/1411
-                 "--source" "'BEGIN{exit} END{exit 1}'"
+                 "--source" "BEGIN{exit} END{exit 0}"
                  "-f" "-"
                  "--lint"
                  null-device)
-  :error-parser
-  (flymake-rest-parse-rx
-   ((error   bol (? "g") "awk: -:" line ": " (or "fatal" "error") ": " 
(message) eol)
-    (warning bol (? "g") "awk: -:" line ": " "warning"            ": " 
(message) eol))))
+  :regexps
+  ((error   bol (? "g") "awk: -:" line ": " (or "fatal" "error") ": " 
(message) eol)
+   (warning bol (? "g") "awk: -:" line ": " "warning"            ": " 
(message) eol)))
 
 (provide 'flymake-rest-awk-gawk)
 
diff --git a/checkers/flymake-rest-clang.el b/checkers/flymake-rest-clang.el
index b80880c8df..41c9b34918 100644
--- a/checkers/flymake-rest-clang.el
+++ b/checkers/flymake-rest-clang.el
@@ -26,8 +26,7 @@
 (require 'flymake-rest)
 
 (eval-when-compile
-  (require 'flymake-rest-define)
-  (require 'flymake-rest-parse-rx))
+  (require 'flymake-rest-define))
 
 (defvar flymake-rest-clang-args
   '("-pedantic" "-pedantic-errors")
@@ -37,7 +36,7 @@
   "Default include path for gcc in `flymake-rest-clang'.")
 
 ;;;###autoload (autoload 'flymake-rest-clang "flymake-rest-clang")
-(flymake-rest-define flymake-rest-clang
+(flymake-rest-define-rx flymake-rest-clang
   "A C/C++ syntax checker using Clang.
 
 See URL `http://clang.llvm.org/'."
@@ -63,11 +62,10 @@ See URL `http://clang.llvm.org/'."
                      ('c-mode "c")
                      ((or 'c++-mode _) "c++"))
              "-")
-  :error-parser
-  (flymake-rest-parse-rx
-   ((error   bol "<stdin>:" line ":" column ": " (or "fatal" "error") ": " 
(message) eol)
-    (warning bol "<stdin>:" line ":" column ": " "warning"            ": " 
(message) eol)
-    (note    bol "<stdin>:" line ":" column ": " "note"               ": " 
(message) eol))))
+  :regexps
+  ((error   bol "<stdin>:" line ":" column ": " (? "fatal ") "error" ": " 
(message) eol)
+   (warning bol "<stdin>:" line ":" column ": " "warning"            ": " 
(message) eol)
+   (note    bol "<stdin>:" line ":" column ": " "note"               ": " 
(message) eol)))
 
 (provide 'flymake-rest-gcc)
 
diff --git a/checkers/flymake-rest-eslint.el b/checkers/flymake-rest-eslint.el
index f284690523..7ca7288a65 100644
--- a/checkers/flymake-rest-eslint.el
+++ b/checkers/flymake-rest-eslint.el
@@ -26,11 +26,10 @@
 (require 'flymake-rest)
 
 (eval-when-compile
-  (require 'flymake-rest-define)
-  (require 'flymake-rest-parse-enumerate))
+  (require 'flymake-rest-define))
 
 ;;;###autoload (autoload 'flymake-rest-eslint "flymake-rest-eslint")
-(flymake-rest-define flymake-rest-eslint
+(flymake-rest-define-enumerate flymake-rest-eslint
   "A Javascript syntax and style checker using eslint.
 
 See URL `https://eslint.org/'."
@@ -45,25 +44,30 @@ See URL `https://eslint.org/'."
     "--stdin"
     ,@(when-let ((file (buffer-file-name flymake-rest-source)))
         (list "--stdin-filename" file)))
-  :error-parser
-  (flymake-rest-parse-enumerate
-      (alist-get
-       'messages
-       (caar
-        (flymake-rest-parse-json
-         (buffer-substring-no-properties
-          (point-min) (point-max)))))
-    (let-alist it
-      (let ((loc (cons (car (flymake-diag-region flymake-rest-source .line 
.column))
-                       (cdr (flymake-diag-region flymake-rest-source .endLine 
.endColumn)))))
-        (list flymake-rest-source
-              (car loc)
-              (cdr loc)
-              (pcase .severity
-                (2 :error)
-                (1 :warning)
-                (_ :note))
-              (concat "[" .ruleId "] " .message))))))
+  :generator
+  (alist-get
+   'messages
+   (caar
+    (flymake-rest-parse-json
+     (buffer-substring-no-properties
+      (point-min) (point-max)))))
+  :enumerate-parser
+  (let-alist it
+    (let* ((start-loc (flymake-diag-region flymake-rest-source .line .column))
+           (loc (cons (car start-loc)
+                      (cdr
+                       (if (and .endLine .endColumn)
+                           (flymake-diag-region flymake-rest-source
+                                                .endLine (1- .endColumn))
+                         start-loc)))))
+      (list flymake-rest-source
+            (car loc)
+            (cdr loc)
+            (pcase .severity
+              (2 :error)
+              (1 :warning)
+              (_ :note))
+            (concat "[" .ruleId "] " .message)))))
 
 (provide 'flymake-rest-eslint)
 
diff --git a/checkers/flymake-rest-gcc.el b/checkers/flymake-rest-gcc.el
index bf728f3a4e..16502840f4 100644
--- a/checkers/flymake-rest-gcc.el
+++ b/checkers/flymake-rest-gcc.el
@@ -23,10 +23,9 @@
 ;;; Code:
 
 (require 'flymake)
-(require 'flymake-rest-define)
 
 (eval-when-compile
-  (require 'flymake-rest-parse-rx))
+  (require 'flymake-rest-define))
 
 (defcustom flymake-rest-gcc-args
   '("-pedantic" "-pedantic-errors")
@@ -40,7 +39,7 @@
   :group 'flymake-rest)
 
 ;;;###autoload (autoload 'flymake-rest-gcc "flymake-rest-gcc")
-(flymake-rest-define flymake-rest-gcc
+(flymake-rest-define-rx flymake-rest-gcc
   "A C/C++ syntax checker using GCC.
 
 Requires GCC 4.4 or newer.  See URL `https://gcc.gnu.org/'."
@@ -67,11 +66,10 @@ Requires GCC 4.4 or newer.  See URL `https://gcc.gnu.org/'."
              ;; code.
              "-S" "-o" ,null-device
              "-")
-  :error-parser
-  (flymake-rest-parse-rx
-   ((error   bol "<stdin>:" line ":" column ": " (or "fatal" "error") ": " 
(message) eol)
-    (warning bol "<stdin>:" line ":" column ": " "warning"            ": " 
(message) eol)
-    (note    bol "<stdin>:" line ":" column ": " "note"               ": " 
(message) eol))))
+  :regexps
+  ((error   bol "<stdin>:" line ":" column ": " (? "fatal ") "error" ": " 
(message) eol)
+   (warning bol "<stdin>:" line ":" column ": " "warning"            ": " 
(message) eol)
+   (note    bol "<stdin>:" line ":" column ": " "note"               ": " 
(message) eol)))
 
 (provide 'flymake-rest-gcc)
 
diff --git a/checkers/flymake-rest-html-tidy.el 
b/checkers/flymake-rest-html-tidy.el
index 6481998a42..41ba2c7000 100644
--- a/checkers/flymake-rest-html-tidy.el
+++ b/checkers/flymake-rest-html-tidy.el
@@ -26,11 +26,10 @@
 (require 'flymake-rest)
 
 (eval-when-compile
-  (require 'flymake-rest-define)
-  (require 'flymake-rest-parse-rx))
+  (require 'flymake-rest-define))
 
 ;;;###autoload (autoload 'flymake-rest-html-tidy "flymake-rest-html-tidy")
-(flymake-rest-define flymake-rest-html-tidy
+(flymake-rest-define-rx flymake-rest-html-tidy
   "A HTML syntax and style checker using Tidy.
 
 See URL `https://github.com/htacg/tidy-html5'."
@@ -40,10 +39,9 @@ See URL `https://github.com/htacg/tidy-html5'."
                (error "Cannot find tidy executable"))
   :write-type 'pipe
   :command `(,tidy-exec "-lang" "en" "-e" "-q")
-  :error-parser
-  (flymake-rest-parse-rx
-   ((error   bol "line " line " column " column " - Error: "   (message) eol)
-    (warning bol "line " line " column " column " - Warning: " (message) 
eol))))
+  :regexps
+  ((error   bol "line " line " column " column " - Error: "   (message) eol)
+   (warning bol "line " line " column " column " - Warning: " (message) eol)))
 
 (provide 'flymake-rest-html-tidy)
 
diff --git a/checkers/flymake-rest-jq.el b/checkers/flymake-rest-jq.el
index 3e33cc4e6b..8f0495bd25 100644
--- a/checkers/flymake-rest-jq.el
+++ b/checkers/flymake-rest-jq.el
@@ -26,11 +26,10 @@
 (require 'flymake-rest)
 
 (eval-when-compile
-  (require 'flymake-rest-define)
-  (require 'flymake-rest-parse-rx))
+  (require 'flymake-rest-define))
 
 ;;;###autoload (autoload 'flymake-rest-jq "flymake-rest-jq")
-(flymake-rest-define flymake-rest-jq
+(flymake-rest-define-rx flymake-rest-jq
   "JSON checker using the jq tool.
 
 This checker accepts multiple consecutive JSON values in a
@@ -43,11 +42,9 @@ See URL `https://stedolan.github.io/jq/'."
                (error "Cannot find jq executable"))
   :write-type 'pipe
   :command (list jq-exec "." "-" null-device)
-  :error-parser
-  (flymake-rest-parse-rx
-   ((error bol "parse error: " (message) " at line " line ", column " column 
eol))))
+  :regexps
+  ((error bol "parse error: " (message) " at line " line ", column " column 
eol)))
 
 (provide 'flymake-rest-jq)
 
-
 ;;; flymake-rest-jq.el ends here
diff --git a/checkers/flymake-rest-jsonlint.el 
b/checkers/flymake-rest-jsonlint.el
index 113450b669..a13a8e86dc 100644
--- a/checkers/flymake-rest-jsonlint.el
+++ b/checkers/flymake-rest-jsonlint.el
@@ -26,11 +26,10 @@
 (require 'flymake-rest)
 
 (eval-when-compile
-  (require 'flymake-rest-define)
-  (require 'flymake-rest-parse-rx))
+  (require 'flymake-rest-define))
 
 ;;;###autoload (autoload 'flymake-rest-jsonlint "flymake-rest-jsonlint")
-(flymake-rest-define flymake-rest-jsonlint
+(flymake-rest-define-rx flymake-rest-jsonlint
   "A JSON syntax and style checker using jsonlint.
 
 See URL `https://github.com/zaach/jsonlint'."
@@ -40,11 +39,9 @@ See URL `https://github.com/zaach/jsonlint'."
                (error "Cannot find jsonlint executable"))
   :write-type 'file
   :command (list jsonlint-exec "-c" "-q" flymake-rest-temp-file)
-  :error-parser
-  (flymake-rest-parse-rx
-   ((error bol (file-name) ": line " line ", col " column ", " (message) 
eol))))
+  :regexps
+  ((error bol (file-name) ": line " line ", col " column ", " (message) eol)))
 
 (provide 'flymake-rest-jsonlint)
 
-
 ;;; flymake-rest-jsonlint.el ends here
diff --git a/checkers/flymake-rest-less.el b/checkers/flymake-rest-less.el
index 7ad0fa2377..0b3a2edc29 100644
--- a/checkers/flymake-rest-less.el
+++ b/checkers/flymake-rest-less.el
@@ -26,11 +26,10 @@
 (require 'flymake-rest)
 
 (eval-when-compile
-  (require 'flymake-rest-define)
-  (require 'flymake-rest-parse-rx))
+  (require 'flymake-rest-define))
 
 ;;;###autoload (autoload 'flymake-rest-less "flymake-rest-less")
-(flymake-rest-define flymake-rest-less
+(flymake-rest-define-rx flymake-rest-less
   "A LESS syntax checker using lessc.
 
 Requires lessc 1.4 or newer.
@@ -42,9 +41,8 @@ See URL `http://lesscss.org'."
                (error "Cannot find lessc executable"))
   :write-type 'pipe
   :command (list lessc-exec  "--lint" "--no-color" "-")
-  :error-parser
-  (flymake-rest-parse-rx
-   ((error bol (+ not-newline) ": " (message) " in - on line " line ", column 
" column ":" eol))))
+  :regexps
+  ((error bol (+ not-newline) ": " (message) " in - on line " line ", column " 
column ":" eol)))
 
 (provide 'flymake-rest-less)
 
diff --git a/checkers/flymake-rest-lua.el b/checkers/flymake-rest-lua.el
index 13630184b4..712c60bf54 100644
--- a/checkers/flymake-rest-lua.el
+++ b/checkers/flymake-rest-lua.el
@@ -26,11 +26,10 @@
 (require 'flymake-rest)
 
 (eval-when-compile
-  (require 'flymake-rest-define)
-  (require 'flymake-rest-parse-rx))
+  (require 'flymake-rest-define))
 
 ;;;###autoload (autoload 'flymake-rest-lua "flymake-rest-lua")
-(flymake-rest-define flymake-rest-lua
+(flymake-rest-define-rx flymake-rest-lua
   "A Lua syntax checker using the Lua compiler.
 
 See URL `http://www.lua.org/'."
@@ -39,12 +38,11 @@ See URL `http://www.lua.org/'."
                (user-error "Cannot find lua compiler executable"))
   :write-type 'pipe
   :command `(,lua-exec "-p" "-")
-  :error-parser
-  (flymake-rest-parse-rx
-   ((error bol
-           ;; Skip the name of the luac executable.
-           (minimal-match (zero-or-more not-newline))
-           ": stdin:" line ": " (message) eol))))
+  :regexps
+  ((error bol
+          ;; Skip the name of the luac executable.
+          (minimal-match (zero-or-more not-newline))
+          ": stdin:" line ": " (message) eol)))
 
 (provide 'flymake-rest-lua)
 
diff --git a/checkers/flymake-rest-luacheck.el 
b/checkers/flymake-rest-luacheck.el
index 24062b6c49..d34516885f 100644
--- a/checkers/flymake-rest-luacheck.el
+++ b/checkers/flymake-rest-luacheck.el
@@ -26,8 +26,7 @@
 (require 'flymake-rest)
 
 (eval-when-compile
-  (require 'flymake-rest-define)
-  (require 'flymake-rest-parse-rx))
+  (require 'flymake-rest-define))
 
 (defcustom flymake-rest-luacheck-standards nil
   "The standards to use in luacheck.
@@ -47,7 +46,7 @@ non-nil, pass the standards via one or more `--std' options."
   :group 'flymake-rest)
 
 ;;;###autoload (autoload 'flymake-rest-luacheck "flymake-rest-luacheck")
-(flymake-rest-define flymake-rest-luacheck
+(flymake-rest-define-rx flymake-rest-luacheck
   "A Lua syntax checker using luacheck.
 
 See URL `https://github.com/mpeterv/luacheck'."
@@ -68,11 +67,10 @@ See URL `https://github.com/mpeterv/luacheck'."
              ,@(when-let ((file (buffer-file-name flymake-rest-source)))
                  (list "--filename" file))
              "-")
-  :error-parser
-  (flymake-rest-parse-rx
-   ;; NOTE: `luacheck' before 0.11.0 did not output codes for errors, hence 
the ID is optional in the error pattern.
-   ((warning bol (optional (file-name)) ":" line ":" column ":"           " (" 
(id "W" (one-or-more digit)) ") "  (message) eol)
-    (error   bol (optional (file-name)) ":" line ":" column ":" (optional " (" 
(id "E" (one-or-more digit)) ") ") (message) eol))))
+  :regexps
+  ;; NOTE: `luacheck' before 0.11.0 did not output codes for errors, hence the 
ID is optional in the error pattern.
+  ((warning bol (optional (file-name)) ":" line ":" column ":"           " (" 
(id "W" (one-or-more digit)) ") "  (message) eol)
+   (error   bol (optional (file-name)) ":" line ":" column ":" (optional " (" 
(id "E" (one-or-more digit)) ") ") (message) eol)))
 
 (provide 'flymake-rest-luacheck)
 
diff --git a/checkers/flymake-rest-markdownlint.el 
b/checkers/flymake-rest-markdownlint.el
index 16ca58f893..f8d14d3280 100644
--- a/checkers/flymake-rest-markdownlint.el
+++ b/checkers/flymake-rest-markdownlint.el
@@ -26,8 +26,7 @@
 (require 'flymake-rest)
 
 (eval-when-compile
-  (require 'flymake-rest-define)
-  (require 'flymake-rest-parse-rx))
+  (require 'flymake-rest-define))
 
 (defcustom flymake-rest-markdownlint-style nil
   "Path to the style config for markdownlint."
@@ -35,7 +34,7 @@
   :group 'flymake-rest)
 
 ;;;###autoload (autoload 'flymake-rest-markdownlint 
"flymake-rest-markdownlint")
-(flymake-rest-define flymake-rest-markdownlint
+(flymake-rest-define-rx flymake-rest-markdownlint
   "Markdown checker using mdl.
 
 See URL `https://github.com/markdownlint/markdownlint'."
@@ -47,9 +46,8 @@ See URL `https://github.com/markdownlint/markdownlint'."
   :command `(,mdl-exec
              ,@(and flymake-rest-markdownlint-style
                     `("--style" ,flymake-rest-markdownlint-style)))
-  :error-parser
-  (flymake-rest-parse-rx
-   ((error bol "(stdin):" line ": " (id "MD" (+ digit)) " " (message) eol))))
+  :regexps
+  ((error bol "(stdin):" line ": " (id "MD" (+ digit)) " " (message) eol)))
 
 (provide 'flymake-rest-markdownlint)
 
diff --git a/checkers/flymake-rest-mypy.el b/checkers/flymake-rest-mypy.el
index 212be607f1..0f3b451e54 100644
--- a/checkers/flymake-rest-mypy.el
+++ b/checkers/flymake-rest-mypy.el
@@ -26,11 +26,10 @@
 (require 'flymake-rest)
 
 (eval-when-compile
-  (require 'flymake-rest-define)
-  (require 'flymake-rest-parse-rx))
+  (require 'flymake-rest-define))
 
 ;;;###autoload (autoload 'flymake-rest-mypy "flymake-rest-mypy")
-(flymake-rest-define flymake-rest-mypy
+(flymake-rest-define-rx flymake-rest-mypy
   "Mypy syntax and type checker.  Requires mypy>=0.580.
 
 See URL `http://mypy-lang.org/'."
@@ -47,11 +46,10 @@ See URL `http://mypy-lang.org/'."
                  "--show-absolute-path"
                  "--show-error-codes"
                  flymake-rest-temp-file)
-  :error-parser
-  (flymake-rest-parse-rx
-   ((error   bol (file-name) ":" line ":" column ": error: "   (message) eol)
-    (warning bol (file-name) ":" line ":" column ": warning: " (message) eol)
-    (note    bol (file-name) ":" line ":" column ": note: "    (message) 
eol))))
+  :regexps
+  ((error   bol (file-name) ":" line ":" column ": error: "   (message) eol)
+   (warning bol (file-name) ":" line ":" column ": warning: " (message) eol)
+   (note    bol (file-name) ":" line ":" column ": note: "    (message) eol)))
 
 (provide 'flymake-rest-mypy)
 
diff --git a/checkers/flymake-rest-proselint.el 
b/checkers/flymake-rest-proselint.el
index dacfc7f886..6443315ff6 100644
--- a/checkers/flymake-rest-proselint.el
+++ b/checkers/flymake-rest-proselint.el
@@ -26,11 +26,10 @@
 (require 'flymake-rest)
 
 (eval-when-compile
-  (require 'flymake-rest-define)
-  (require 'flymake-rest-parse-enumerate))
+  (require 'flymake-rest-define))
 
 ;;;###autoload (autoload 'flymake-rest-proselint "flymake-rest-proselint")
-(flymake-rest-define flymake-rest-proselint
+(flymake-rest-define-enumerate flymake-rest-proselint
   "Flymake checker using Proselint.
 
 See URL `http://proselint.com/'."
@@ -40,25 +39,23 @@ See URL `http://proselint.com/'."
                (error "Cannot find proselint executable"))
   :write-type 'pipe
   :command `(,proselint-exec "--json" "-")
-  :error-parser
-  (flymake-rest-parse-enumerate
-      (alist-get 'errors
-       (alist-get 'data
-        (car
-         (flymake-rest-parse-json
-          (buffer-substring-no-properties
-           (point-min) (point-max))))))
-    (let-alist it
-      ;; (cons (car (flymake-diag-region flymake-rest-source .line .column))
-      ;;       (cdr (flymake-diag-region flymake-rest-source .endLine 
.endColumn)))
-      (list flymake-rest-source
-            .start
-            .end
-            (pcase .severity
-              ("suggestion" :note)
-              ("warning" :warning)
-              ((or "error" _) :error))
-            (concat (propertize .check 'face 'flymake-rest-diag-id) " " 
.message)))))
+  :generator
+  (alist-get 'errors
+   (alist-get 'data
+    (car
+     (flymake-rest-parse-json
+      (buffer-substring-no-properties
+       (point-min) (point-max))))))
+  :enumerate-parser
+  (let-alist it
+    (list flymake-rest-source
+          .start
+          .end
+          (pcase .severity
+            ("suggestion" :note)
+            ("warning" :warning)
+            ((or "error" _) :error))
+          (concat (propertize .check 'face 'flymake-rest-diag-id) " " 
.message))))
 
 (provide 'flymake-rest-proselint)
 
diff --git a/checkers/flymake-rest-pycodestyle.el 
b/checkers/flymake-rest-pycodestyle.el
index 34854ae80c..5531efc900 100644
--- a/checkers/flymake-rest-pycodestyle.el
+++ b/checkers/flymake-rest-pycodestyle.el
@@ -26,11 +26,13 @@
 (require 'flymake-rest)
 
 (eval-when-compile
-  (require 'flymake-rest-define)
-  (require 'flymake-rest-parse-rx))
+  (require 'flymake-rest-define))
 
 ;;;###autoload (autoload 'flymake-rest-pycodestyle "flymake-rest-pycodestyle")
-(flymake-rest-define flymake-rest-pycodestyle
+(flymake-rest-define-rx flymake-rest-pycodestyle
+  "Python style guide checker.
+
+See URL `https://github.com/PyCQA/pycodestyle'."
   :title "pycodestyle"
   :pre-let ((pycodestyle-exec (executable-find "pycodestyle")))
   :pre-check
@@ -39,9 +41,8 @@
   :write-type 'file
   :source-inplace t
   :command (list pycodestyle-exec flymake-rest-temp-file)
-  :error-parser
-  (flymake-rest-parse-rx
-   ((error bol (file-name) ":" line ":" column ": " (id (or "E" "W") 
(one-or-more digit)) " " (message) eol))))
+  :regexps
+  ((error bol (file-name) ":" line ":" column ": " (id (or "E" "W") 
(one-or-more digit)) " " (message) eol)))
 
 (provide 'flymake-rest-pycodestyle)
 
diff --git a/checkers/flymake-rest-pylint.el b/checkers/flymake-rest-pylint.el
index 05315cbccd..d967591b30 100644
--- a/checkers/flymake-rest-pylint.el
+++ b/checkers/flymake-rest-pylint.el
@@ -26,11 +26,15 @@
 (require 'flymake-rest)
 
 (eval-when-compile
-  (require 'flymake-rest-define)
-  (require 'flymake-rest-parse-enumerate))
+  (require 'flymake-rest-define))
 
 ;;;###autoload (autoload 'flymake-rest-pylint "flymake-rest-pylint")
-(flymake-rest-define flymake-rest-pylint
+(flymake-rest-define-enumerate flymake-rest-pylint
+  "A Python syntax and style checker using Pylint.
+
+This syntax checker requires Pylint 1.0 or newer.
+
+See URL `https://www.pylint.org/'."
   :title "pylint"
   :pre-let ((python-exec (executable-find "python3"))
             (pylint-exec (executable-find "pylint"))
@@ -49,23 +53,23 @@
                  "--output-format=json"
                  "--from-stdin"
                  file-name)
-  :error-parser
-  (flymake-rest-parse-enumerate
-      (car
-       (flymake-rest-parse-json
-        (buffer-substring-no-properties
-         (point-min) (point-max))))
-    (let-alist it
-      (let ((loc (flymake-diag-region flymake-rest-source .line .column)))
-        (list flymake-rest-source
-              (car loc)
-              (cdr loc)
-              (pcase .type
-                ;; See "pylint/utils.py"
-                ((or "fatal" "error") :error)
-                ((or "warning" "refactor" "convention") :warning)
-                ((or "info" _) :note))
-              (concat (propertize .message-id 'face 'flymake-rest-diag-id) " " 
.message))))))
+  :generator
+  (car
+   (flymake-rest-parse-json
+    (buffer-substring-no-properties
+     (point-min) (point-max))))
+  :enumerate-parser
+  (let-alist it
+    (let ((loc (flymake-diag-region flymake-rest-source .line .column)))
+      (list flymake-rest-source
+            (car loc)
+            (cdr loc)
+            (pcase .type
+              ;; See "pylint/utils.py"
+              ((or "fatal" "error") :error)
+              ((or "warning" "refactor" "convention") :warning)
+              ((or "info" _) :note))
+            (concat (propertize .message-id 'face 'flymake-rest-diag-id) " " 
.message)))))
 
 (provide 'flymake-rest-pylint)
 
diff --git a/checkers/flymake-rest-rubocop.el b/checkers/flymake-rest-rubocop.el
index 0cf09a3c82..be91eafd50 100644
--- a/checkers/flymake-rest-rubocop.el
+++ b/checkers/flymake-rest-rubocop.el
@@ -26,8 +26,7 @@
 (require 'flymake-rest)
 
 (eval-when-compile
-  (require 'flymake-rest-define)
-  (require 'flymake-rest-parse-rx))
+  (require 'flymake-rest-define))
 
 (defcustom flymake-rest-rubocop-use-bundler t
   "When true use bundle exec for rubocop checks."
@@ -35,7 +34,7 @@
   :group 'flymake-rest)
 
 ;;;###autoload (autoload 'flymake-rest-rubocop "flymake-rest-rubocop")
-(flymake-rest-define flymake-rest-rubocop
+(flymake-rest-define-rx flymake-rest-rubocop
   "A Ruby syntax checker using rubocop.
 
 See URL `https://github.com/rubocop/rubocop'."
@@ -68,11 +67,10 @@ See URL `https://github.com/rubocop/rubocop'."
              ;; Rubocop takes the original file name as argument when reading
              ;; from standard input
              "--stdin" ,file-name)
-  :error-parser
-  (flymake-rest-parse-rx
-   ((error   bol (file-name) ":" line ":" column ": " (or "E" "F") ": " (? 
"[Correctable] ") (message) eol)
-    (warning bol (file-name) ":" line ":" column ": " "C"          ": " (? 
"[Correctable] ") (message) eol)
-    (note    bol (file-name) ":" line ":" column ": " "W"          ": " (? 
"[Correctable] ") (message) eol))))
+  :regexps
+  ((error   bol (file-name) ":" line ":" column ": " (or "E" "F") ": " (? 
"[Correctable] ") (message) eol)
+   (warning bol (file-name) ":" line ":" column ": " "C"          ": " (? 
"[Correctable] ") (message) eol)
+   (note    bol (file-name) ":" line ":" column ": " "W"          ": " (? 
"[Correctable] ") (message) eol)))
 
 (provide 'flymake-rest-rubocop)
 
diff --git a/checkers/flymake-rest-shellcheck.el 
b/checkers/flymake-rest-shellcheck.el
index 9cf9cbc51d..f71ad410a1 100644
--- a/checkers/flymake-rest-shellcheck.el
+++ b/checkers/flymake-rest-shellcheck.el
@@ -26,18 +26,17 @@
 (require 'flymake-rest)
 
 (eval-when-compile
-  (require 'flymake-rest-define)
-  (require 'flymake-rest-parse-enumerate))
+  (require 'flymake-rest-define))
 
 (defcustom flymake-rest-shellcheck-follow-sources t
-  "Whether to follow"
+  "Whether to follow sources in `flymake-rest-shellcheck'."
   :type '(choice (const :tag "Follow source files" t)
                  (const :tag "Follow source files and lint them" lint)
                  (const :tag "Do not follow source files" nil))
   :group 'flymake-rest)
 
 ;;;###autoload (autoload 'flymake-rest-shellcheck "flymake-rest-shellcheck")
-(flymake-rest-define flymake-rest-shellcheck
+(flymake-rest-define-enumerate flymake-rest-shellcheck
   "A shell script syntax and style checker using Shellcheck.
 
 See URL `https://github.com/koalaman/shellcheck/'."
@@ -55,23 +54,23 @@ See URL `https://github.com/koalaman/shellcheck/'."
                    ,@(when (eq flymake-rest-shellcheck-follow-sources 'lint)
                        '("--check-sourced"))))
              "-")
-  :error-parser
-  (flymake-rest-parse-enumerate
-      (car
-       (flymake-rest-parse-json
-        (buffer-substring-no-properties
-         (point-min) (point-max))))
-    (let-alist it
-      (let ((loc (cons (car (flymake-diag-region flymake-rest-source .line 
.column))
-                       (cdr (flymake-diag-region flymake-rest-source .endLine 
.endColumn)))))
-        (list flymake-rest-source
-              (car loc)
-              (cdr loc)
-              (pcase .level
-                ("error" :error)
-                ("warning" :warning)
-                ((or "info" "style" _) :note))
-              (concat (propertize (format "SC%s" .code) 'face 
'flymake-rest-diag-id) " " .message))))))
+  :generator
+  (car
+   (flymake-rest-parse-json
+    (buffer-substring-no-properties
+     (point-min) (point-max))))
+  :enumerate-parser
+  (let-alist it
+    (let ((loc (cons (car (flymake-diag-region flymake-rest-source .line 
.column))
+                     (cdr (flymake-diag-region flymake-rest-source .endLine 
.endColumn)))))
+      (list flymake-rest-source
+            (car loc)
+            (cdr loc)
+            (pcase .level
+              ("error" :error)
+              ("warning" :warning)
+              ((or "info" "style" _) :note))
+            (concat (propertize (format "SC%s" .code) 'face 
'flymake-rest-diag-id) " " .message)))))
 
 (provide 'flymake-rest-shellcheck)
 
diff --git a/checkers/flymake-rest-sql-lint.el 
b/checkers/flymake-rest-sql-lint.el
index 17b12dc142..fa47fc85c7 100644
--- a/checkers/flymake-rest-sql-lint.el
+++ b/checkers/flymake-rest-sql-lint.el
@@ -26,8 +26,7 @@
 (require 'flymake-rest)
 
 (eval-when-compile
-  (require 'flymake-rest-define)
-  (require 'flymake-rest-parse-rx))
+  (require 'flymake-rest-define))
 
 (defcustom flymake-rest-sql-lint-driver nil
   "The SQL driver to pass to sql-lint."
@@ -38,7 +37,7 @@
   :group 'flymake-rest)
 
 ;;;###autoload (autoload 'flymake-rest-sql-lint "flymake-rest-sql-lint")
-(flymake-rest-define flymake-rest-sql-lint
+(flymake-rest-define-rx flymake-rest-sql-lint
   "A SQL syntax checker using the sql-lint tool.
 
 See URL `https://github.com/joereynolds/sql-lint'."
@@ -50,9 +49,8 @@ See URL `https://github.com/joereynolds/sql-lint'."
   :command `(,lint-exec
              ,@(when flymake-rest-sql-lint-driver
                  `("--driver" ,flymake-rest-sql-lint-driver)))
-  :error-parser
-  (flymake-rest-parse-rx
-    ((warning bol "stdin:" line " [sql-lint: " (id (one-or-more (any alnum 
"-"))) "] " (message) eol))))
+  :regexps
+  ((warning bol "stdin:" line " [sql-lint: " (id (one-or-more (any alnum 
"-"))) "] " (message) eol)))
 
 (provide 'flymake-rest-sql-lint)
 
diff --git a/checkers/flymake-rest-sqlint.el b/checkers/flymake-rest-sqlint.el
index ffd933d903..8be965d594 100644
--- a/checkers/flymake-rest-sqlint.el
+++ b/checkers/flymake-rest-sqlint.el
@@ -26,11 +26,10 @@
 (require 'flymake-rest)
 
 (eval-when-compile
-  (require 'flymake-rest-define)
-  (require 'flymake-rest-parse-rx))
+  (require 'flymake-rest-define))
 
 ;;;###autoload (autoload 'flymake-rest-sqlint "flymake-rest-sqlint")
-(flymake-rest-define flymake-rest-sqlint
+(flymake-rest-define-rx flymake-rest-sqlint
   "A SQL syntax checker using the sqlint tool.
 
 See URL `https://github.com/purcell/sqlint'."
@@ -40,20 +39,19 @@ See URL `https://github.com/purcell/sqlint'."
                (error "Cannot find sqlint executable"))
   :write-type 'pipe
   :command (list lint-exec)
-  :error-parser
-  (flymake-rest-parse-rx
-    ((warning bol "stdin:" line ":" column ":WARNING "
-       (message (one-or-more not-newline)
-         (zero-or-more "\n"
-           (one-or-more "  ")
-           (one-or-more not-newline)))
-       eol)
-      (error bol "stdin:" line ":" column ":ERROR "
-        (message (one-or-more not-newline)
-          (zero-or-more "\n"
-            (one-or-more "  ")
-            (one-or-more not-newline)))
-        eol))))
+  :regexps
+  ((warning bol "stdin:" line ":" column ":WARNING "
+     (message (one-or-more not-newline)
+       (zero-or-more "\n"
+         (one-or-more "  ")
+         (one-or-more not-newline)))
+     eol)
+    (error bol "stdin:" line ":" column ":ERROR "
+      (message (one-or-more not-newline)
+        (zero-or-more "\n"
+          (one-or-more "  ")
+          (one-or-more not-newline)))
+      eol)))
 
 (provide 'flymake-rest-sqlint)
 
diff --git a/checkers/flymake-rest-xmllint.el b/checkers/flymake-rest-xmllint.el
index 5d54fb8503..6d7ca9e7c7 100644
--- a/checkers/flymake-rest-xmllint.el
+++ b/checkers/flymake-rest-xmllint.el
@@ -26,15 +26,13 @@
 (require 'flymake-rest)
 
 (eval-when-compile
-  (require 'flymake-rest-define)
-  (require 'flymake-rest-parse-rx))
+  (require 'flymake-rest-define))
 
 ;;;###autoload (autoload 'flymake-rest-xmllint "flymake-rest-xmllint")
-(flymake-rest-define flymake-rest-xmllint
+(flymake-rest-define-rx flymake-rest-xmllint
   "A XML syntax checker and validator using the xmllint utility.
 
-The xmllint is part of libxml2, see URL
-`http://www.xmlsoft.org/'."
+The xmllint is part of libxml2, see URL `http://www.xmlsoft.org/'."
   :title "xmllint"
   :pre-let ((xmllint-exec (executable-find "xmllint")))
   :pre-check
@@ -42,11 +40,9 @@ The xmllint is part of libxml2, see URL
     (error "Cannot find xmllint executable"))
   :write-type 'pipe
   :command `(,xmllint-exec "--noout" "-")
-  :error-parser
-  (flymake-rest-parse-rx
-   ((error   bol "-:" line ": " (message) eol))))
+  :regexps
+  ((error bol "-:" line ": " (message) eol)))
 
 (provide 'flymake-rest-xmllint)
-;;; flymake-rest-xml.el ends here
 
 ;;; flymake-rest-xmllint.el ends here
diff --git a/checkers/flymake-rest-yamllint.el 
b/checkers/flymake-rest-yamllint.el
index 4e091f026c..01e545472c 100644
--- a/checkers/flymake-rest-yamllint.el
+++ b/checkers/flymake-rest-yamllint.el
@@ -23,14 +23,14 @@
 ;;; Code:
 
 (require 'flymake)
-(require 'flymake-rest-define)
 
 (eval-when-compile
-  (require 'flymake-rest-parse-rx))
+  (require 'flymake-rest-define))
 
 ;;;###autoload (autoload 'flymake-rest-yamllint "flymake-rest-yamllint")
-(flymake-rest-define flymake-rest-yamllint
+(flymake-rest-define-rx flymake-rest-yamllint
   "A YAML syntax checker using YAMLLint.
+
 See URL `https://github.com/adrienverge/yamllint'."
   :title "yamllint"
   :pre-let ((yamllint-exec (executable-find "yamllint")))
@@ -38,10 +38,9 @@ See URL `https://github.com/adrienverge/yamllint'."
                (error "Cannot find yamllint executable"))
   :write-type 'pipe
   :command (list yamllint-exec "-f" "parsable" "-")
-  :error-parser
-  (flymake-rest-parse-rx
-   ((error   bol "stdin:" line ":" column ": " "[error] "   (message) eol)
-    (warning bol "stdin:" line ":" column ": " "[warning] " (message) eol))))
+  :regexps
+  ((error   bol "stdin:" line ":" column ": " "[error] "   (message) eol)
+   (warning bol "stdin:" line ":" column ": " "[warning] " (message) eol)))
 
 (provide 'flymake-rest-yamllint)
 
diff --git a/flymake-rest-define.el b/flymake-rest-define.el
index e3bd813aae..35749edc04 100644
--- a/flymake-rest-define.el
+++ b/flymake-rest-define.el
@@ -22,14 +22,29 @@
 
 ;;; Commentary:
 
-;; This file provides a macro, adapted heavily from 
[[https://github.com/karlotness/flymake-quickdef/blob/150c5839768a3d32f988f9dc08052978a68f2ad7/flymake-quickdef.el][flymake-quickdef]],
 to allow
-;; streamlined syntax-checker definitions. The intended purpose is to abstract
-;; the process creation, management and cleanup for a checker as much as 
possible,
-;; leaving the developer to only have to specify what command to run and how
-;; to parse its output.
+;; This file provides a macro `flymake-rest-define', adapted heavily from
+;; 
[[https://github.com/karlotness/flymake-quickdef/blob/150c5839768a3d32f988f9dc08052978a68f2ad7/flymake-quickdef.el][flymake-quickdef]],
 to allow streamlined syntax-checker definitions. The
+;; intended purpose is to abstract the process creation, management and cleanup
+;; for a checker as much as possible, leaving the developer to only have to
+;; specify what command to run and how to parse its output.
+
+;; Also in this file you'll find helper macros to parse diagnostics using
+;; regexps and simplify JSON processing.
+;;
+;; `flymake-rest-define-rx' works by defining some regular expressions (one for
+;; each severity level of the checker) and then matching each line of the 
output
+;; to a regular expression. Special capture groups have been setup by the 
parser
+;; that should be used by any calling checkers to ensure the correct fields 
from
+;; the output can be parsed. The approach for this was heavily inspired by
+;; flychecks :error-parsers feature.
+;;
+;; `flymake-rest-define' can be used to parse JSON output from the checker into
+;; flymake diagnostics. This works by parsing the entire JSON input into a list
+;; of diagnostic related data, and then iteratively parsing it into 
diagnostics.
 
 ;;; Code:
 
+(require 'cl-lib)
 (require 'flymake)
 
 ;;;###autoload
@@ -40,205 +55,445 @@ finished its removed and killed. In the very often 
circumstance where a
 new check is begun while an old check is still pending, the old check is
 killed and replaced with the new check.")
 
-(defmacro flymake-rest-define (name &optional docstring &rest defs)
-  "Quickly define a backend for use with Flymake.
-This macro creates a new function NAME which is suitable for use with the
-variable `flymake-diagnostic-functions'. DOCSTRING if given will become the
-docstring of the checker function.
+
+;;; `flymake-rest-define'
+
+(defun flymake-rest-define--temp-file (temp-dir temp-file source-inplace)
+  "Let forms for defining a temporary directory and file.
+TEMP-DIR and TEMP-FILE are the symbols used for the corresponding variables.
+SOURCE-INPLACE specifies whether the TEMP-DIR should be in the same working
+directory as the current buffer."
+  `((,temp-dir
+     ,@(let ((forms
+              (append
+               (when source-inplace
+                 '((when-let ((dir (or (when-let ((file (buffer-file-name)))
+                                         (file-name-directory file))
+                                       default-directory)))
+                     (unless (file-exists-p dir)
+                       (error "Checker needs to be run in the cwd, but the cwd 
\
+doesn't exist: %s" dir))
+                     dir)))
+               '((make-temp-file "flymake-" t)))))
+         (if (> (length forms) 1)
+             `((or ,@forms))
+           forms)))
+    (,temp-file
+     (let ((temporary-file-directory ,temp-dir)
+           (basename (file-name-nondirectory (or (buffer-file-name)
+                                                 (buffer-name)))))
+       (make-temp-file ".flymake_" nil (concat "_" basename))))))
 
-DEFS is a plist of values used to setup the backend. The only required fields
-in DEFS is :command and :error-parser.
+(defmacro flymake-rest-define--parse-diags
+    (title proc-symb diags-symb current-diag-symb source-symb error-parser)
+  "Helper macro to parse diagnostics into DIAGS-SYMB.
+TITLE is the title of the current syntax checker. PROC-SYMB, DIAGS-SYMB,
+CURRENT-DIAGS-SYMB, SOURCE-SYMB, ERROR-PARSER are all described in
+`flymake-rest-define'."
+  `(with-current-buffer ,source-symb
+     (save-restriction
+       (widen)
+       (with-current-buffer (process-buffer ,proc-symb)
+         (goto-char (point-min))
+         (save-match-data
+           (while (setq ,current-diag-symb (progn ,error-parser))
+             (let* ((diag-beg (nth 1 ,current-diag-symb))
+                    (diag-end (nth 2 ,current-diag-symb))
+                    (diag-type (nth 3 ,current-diag-symb)))
+               (if (and (integer-or-marker-p diag-beg)
+                        (integer-or-marker-p diag-end))
+                   ;; Skip any diagnostics with a type of nil. This makes it
+                   ;; easier to filter some out.
+                   (when diag-type
+                     ;; Include the checker title in the message.
+                     ,@(when title
+                         `((setf (nth 4 ,current-diag-symb)
+                                 (concat
+                                  (nth 4 ,current-diag-symb)
+                                  ,(concat
+                                    " ("
+                                    (propertize title 'face 
'flymake-rest-checker)
+                                    ")")))))
+                     (push (apply #'flymake-make-diagnostic
+                                  ,current-diag-symb)
+                           ,diags-symb))
+                 (with-current-buffer ,source-symb
+                   (flymake-log
+                    :error
+                    "Got invalid buffer position %s or %s in %s"
+                    diag-beg diag-end ,proc-symb))))))))
+     (setq ,diags-symb (nreverse ,diags-symb))))
+
+;; WARN: I can't seem to make docstring optional and use keys, because
+;; the key for the first keyword argument will become the docstring if
+;; there's no docstring.
+(cl-defmacro flymake-rest-define
+    (name docstring
+          &optional &key title command error-parser write-type
+          source-inplace pre-let pre-check)
+  "Quickly define a backend function for use with Flymake.
+Define a function NAME which is suitable for use with the variable
+`flymake-diagnostic-functions'. DOCSTRING if given will become the
+docstring of the checker function.
 
 Available Variables
+-------------------
+Within the body of NAME several macro specific variables will be
+made available for use with ERROR-PARSER or COMMAND, and other
+optional arguments such as PRE-LET. This includes:
+* flymake-rest-source
+  The the buffer where the syntax check originally began.
+* flymake-rest-temp-file
+  A temporary file where the contents of the current buffer were
+  written (only if WRITE-TYPE is 'file)
+* flymake-rest-temp-dir
+  The dirname of flymake-rest-temp-file.
+
+Body Execution
+--------------
+The overall execution of the generated function NAME first makes use
+of (1) WRITE-TYPE, (2) SOURCE-INPLACE, (3) PRE-LET, and (4) PRE-CHECK.
+Then a process is created using (4) COMMAND. Once the process finishes
+ERROR-PARSER is called (until it returns nil) to get the next
+diagnostic which is then provided to `flymake'. TITLE if provided is
+used to suffix the message for each diagnostic.
+
+WRITE-TYPE specifies how the process for a syntax check should recieve
+the input. It should one of 'pipe or 'file (defaulting to 'pipe).
+When set to 'file a temporary file will ve created, copying the contents
+of the `current-buffer'. The variable flymake-rest-temp-file and
+flymake-rest-temp-dir will be bound in the body of NAME and provide
+access to this temp-file.
+When set to 'pipe, all of the `current-buffer' will be passed to the
+process on its standard-input stream after it has begun.
+
+SOURCE-INPLACE determines whether to also create a temporary directory
+for a temporary file (when using a WRITE-TYPE of 'file) or whether to
+place the temporary file in the same directory as the file being checked.
+This can be useful if the syntax checker also resolves imports or packages
+and thus needs to be in the same directory. This is disabled by default
+meaning the file is placed in folder in the systems temporary directory.
+
+PRE-LET is a `let*' form that is assigned after any checker agnostic
+variables. Place anything you want exposed to everything else in the
+checker here.
 
-flymake-rest-source, flymake-rest-temp-file, fmdq-temp-dir, 
flymake-rest-context.
-Within the body of :error-parser and :command, several macro specific variables
-are made available. This includes (1) `flymake-rest-source',
-(2) `flymake-rest-temp-file', (3) `flymake-rest-temp-dir', (4) 
`flymake-rest-context'.
-
-Body Definitions
-
-The overall execution of the produced function first makes use of (1)
-:write-type, (2) :source-inplace, (3) :pre-let, and (3) :pre-check. Next
-a process is created using (4) :command. Once the process is finished
-:error-parser is called (until it returns nil) to get the next diagnostic
-which is then provided to flymake. (5) :title if provided is used to
-suffix the messages for each diagnostic.
-
-:write-type specifies how the process for flymake should recieve the input.
-It should be one of 'pipe or 'file (defaulting to 'pipe). When set to file
-a temporary file will be created copying the contents of the `current-buffer'.
-The variable flymake-rest-temp-file and flymake-rest-temp-dir will be bound in 
the body
-of the rest of the keywords that provide access to the temp-file. When set
-to pipe after the process has been started all of the current buffers input
-will be passed to the process through standard-input.
-
-:source-inplace is a boolean that sets flymake-rest-temp-dir to the current 
working
-directory. By default this is nil and the temp-file used for :write-type 'file
-will be set to a folder in the systems temporary directory.
-
-:pre-let is a `let*' form that is assigned after any backend-agnostic let
-forms have been setup.
-
-:pre-check is a Lisp form that will be executed immeadiately before any pending
-checker processes are killed and a new process is begun. It can check 
conditions
-to ensure launching the checker program is possible. If something is wrong it
-should signal an error.
-
-:command is a lip form which evaluates to a list of strings that will be used 
to
-start the checker process. It should be suitable for use as the :command 
argument
-to the `make-process' function.
-
-:error-parser is a lisp-form that should, each time it is evaluated, return the
-next diagnostic from the checker output. The result should be a value that can
-be passed to the `flymake-make-diagnostic' function. Once there're no more
-diagnostics to parse this form should evaluate to nil."
+PRE-CHECK is a Lisp form that will be executed immeadiately before any
+pending checker processes are killed and a new process is begun. It can
+check conditions to ensure launching the checker program is possible. If
+something is wrong it should signal an error.
+
+COMMAND is a Lisp form which evaluates to a list of strings that will be
+used to start the checker process. It should be suitable for use as the
+:command argument to the `make-process' function.
+
+ERROR-PARSER is a lisp-form that should, each time it is evaluated,
+return the next diagnostic from the checker output. The result should be
+a value that can be passed to the `flymake-make-diagnostic' function. Once
+there're no more diagnostics to parse this form should evaluate to nil."
   (declare (indent defun) (doc-string 2))
   (unless lexical-binding
     (error "Need lexical-binding for flymake-rest-define (%s)" name))
-  (or (stringp docstring)
-      (setq defs (cons docstring defs)
-            docstring nil))
-  (dolist (elem '(:command :error-parser))
-    (unless (plist-get defs elem)
-      (error "Missing flymake backend definition `%s'" elem)))
-  (let* ((write-type (or (eval (plist-get defs :write-type)) 'pipe))
-         (source-inplace (plist-get defs :source-inplace))
-         (temp-dir-symb (intern "flymake-rest-temp-dir"))
-         (temp-file-symb (intern "flymake-rest-temp-file"))
-         (err-symb (intern "flymake-rest-err"))
-         (diags-symb (intern "diags"))
-         (proc-symb (intern "proc"))
-         (source-symb (intern "flymake-rest-source"))
-         (current-diags-symb (intern "diag"))
+  (dolist (elem (list (cons 'command command)
+                      (cons 'error-parser error-parser)))
+    (unless (cdr elem)
+      (error "Missing flymake backend definition `%s'" (car elem))))
+
+  (setq write-type (or (eval write-type) 'pipe))
+  (setq source-inplace (eval source-inplace))
+
+  (unless (memq write-type '(file pipe))
+    (error "Invalid `:write-type' value `%s'" write-type))
+
+  (let* ((temp-dir-symb 'flymake-rest-temp-dir)
+         (temp-file-symb 'flymake-rest-temp-file)
+         (proc-symb 'proc)
+         (err-symb 'flymake-rest-err)
+         (source-symb 'flymake-rest-source)
+         (diags-symb 'diags)
+         (current-diag-symb 'diag)
          (cleanup-form (when (eq write-type 'file)
                          (if source-inplace
                              `((delete-file ,temp-file-symb))
                            `((delete-directory ,temp-dir-symb t)))))
-         (not-obsolete-form `((eq ,proc-symb (plist-get (buffer-local-value 
'flymake-rest-define--procs ,source-symb) ',name)))))
-    ;; Sanitise parsed inputs from `defs'.
-    (unless (memq write-type '(file pipe nil))
-      (error "Invalid `:write-type' value `%s'" write-type))
-
+         (not-obsolete-form
+          `((eq ,proc-symb
+                (plist-get (buffer-local-value 'flymake-rest-define--procs
+                                               ,source-symb)
+                           ',name)))))
     `(defun ,name (report-fn &rest _args)
        ,docstring
        (let* ((,source-symb (current-buffer))
-              (flymake-rest-context nil)
               ,@(when (eq write-type 'file)
-                  `((,temp-dir-symb
-                     ,@(let ((forms (append (when source-inplace
-                                              `((when-let ((dir (or (when-let 
((file (buffer-file-name)))
-                                                                      
(file-name-directory file))
-                                                                    
default-directory)))
-                                                  (unless (file-exists-p dir)
-                                                    (error "Checker needs to 
be run in the cwd, but the cwd doesn't exist: %s" dir))
-                                                  dir)))
-                                            '((make-temp-file "flymake-" t)))))
-                         (if (> (length forms) 1)
-                             `((or ,@forms))
-                           forms)))
-                    (,temp-file-symb
-                     (let ((temporary-file-directory ,temp-dir-symb)
-                           (basename (file-name-nondirectory (or 
(buffer-file-name)
-                                                                 
(buffer-name)))))
-                       (make-temp-file ".flymake_"
-                                       nil
-                                       (concat "_" basename))))))
-              ,@(plist-get defs :pre-let))
-         ;; With vars defined, do :pre-check.
-         ,@(when-let ((pre-check (plist-get defs :pre-check)))
+                  (flymake-rest-define--temp-file
+                   temp-dir-symb temp-file-symb source-inplace))
+              ,@pre-let)
+         ;; With vars defined, do pre-check.
+         ,@(when pre-check
              `((condition-case ,err-symb
-                   (progn ,pre-check)
+                   ,pre-check
                  (error ,@cleanup-form
                         (signal (car ,err-symb) (cdr ,err-symb))))))
-         ;; Kill any running (obsolete) processes for current checker and 
buffer.
+         ;; Kill any running (obsolete) checkers for current checker and 
buffer.
          (let ((,proc-symb (plist-get flymake-rest-define--procs ',name)))
            (when (process-live-p ,proc-symb)
-             (kill-process ,proc-symb)
-             (flymake-log :debug "Killing earlier checker process %s" 
,proc-symb)))
-
+             (flymake-log :debug "Killing earlier checker process %s" 
,proc-symb)
+             (kill-process ,proc-symb)))
          ;; Kick-start checker process.
          (save-restriction
            (widen)
-           ;; Write the current file out before starting checker.
            ,@(when (eq write-type 'file)
                `((write-region nil nil ,temp-file-symb nil 'silent)))
-           (let (proc)
-             (setq proc
-                   (make-process
-                    :name ,(concat (symbol-name name) "-flymake")
-                    :noquery t
-                    :connection-type 'pipe
-                    :buffer (generate-new-buffer ,(concat " *" (symbol-name 
name) "-flymake*"))
-                    :command
-                    (let ((cmd ,(plist-get defs :command)))
-                      (prog1 cmd
-                        (flymake-log :debug "Checker command is %s" cmd)))
-                    :sentinel
-                    (lambda (,proc-symb _event)
-                      (unless (process-live-p ,proc-symb)
-                        (unwind-protect
-                            (if ,@not-obsolete-form
-                                (with-current-buffer ,source-symb
-                                  ;; First read diagnostics from process 
buffer referencing the source buffer.
-                                  (let ((,diags-symb nil) ,current-diags-symb)
-                                    ;; Widen the source buffer to ensure 
`flymake-diag-region' is correct.
-                                    (save-restriction
-                                      (widen)
-                                      (with-current-buffer (process-buffer 
,proc-symb)
-                                        (goto-char (point-min))
-                                        (save-match-data
-                                          (while (setq ,current-diags-symb 
,(plist-get defs :error-parser))
-                                            (let* ((diag-beg (nth 1 
,current-diags-symb))
-                                                   (diag-end (nth 2 
,current-diags-symb))
-                                                   (diag-type (nth 3 
,current-diags-symb)))
-                                              (if (and (integer-or-marker-p 
diag-beg)
-                                                       (integer-or-marker-p 
diag-end))
-                                                  ;; Skip any diagnostics with 
a type of nil
-                                                  ;; This makes it easier to 
filter some out.
-                                                  (when diag-type
-                                                    ;; Include the checker 
name/title in the message.
-                                                    ,@(when (plist-get defs 
:title)
-                                                        `((setf (nth 4 
,current-diags-symb)
-                                                                (concat (nth 4 
,current-diags-symb)
-                                                                        
,(concat
-                                                                          " ("
-                                                                          
(propertize (plist-get defs :title)
-                                                                               
       'face 'flymake-rest-checker)
-                                                                          
")")))))
-
-                                                    (push (apply 
#'flymake-make-diagnostic ,current-diags-symb)
-                                                          ,diags-symb))
-                                                (with-current-buffer 
,source-symb
-                                                  (flymake-log :error "Got 
invalid buffer position %s or %s in %s"
-                                                               diag-beg 
diag-end ,proc-symb))))))))
-                                    ;; Pass reports back to the 
callback-function when still not-obsolete.
-                                    (if ,@not-obsolete-form
-                                        (progn
-                                          (let ((status (process-exit-status 
,proc-symb)))
-                                            (when (and (eq (length 
,diags-symb) 0)
-                                                       (not (eq status 0)))
-                                              (flymake-log :warning
-                                                           "Checker gave no 
diagnostics but had a non-zero exit status %d\nStderr:" status
-                                                           
(with-current-buffer (process-buffer ,proc-symb)
-                                                             (format "%s" 
(buffer-substring-no-properties
-                                                                           
(point-min) (point-max)))))))
-                                          (funcall report-fn (nreverse 
,diags-symb)))
-                                      ;; In case the check was cancelled after 
processing began but before it finished.
-                                      (flymake-log :warning "Canceling 
obsolete check %s" ,proc-symb)))
-                                  (flymake-log :warning "Canceling obsolete 
check %s" ,proc-symb)))
-                          ;; Finished linting, cleanup any temp-files and then 
kill proc buffer.
-                          ,@cleanup-form
-                          (kill-buffer (process-buffer ,proc-symb)))))))
+           (let (,proc-symb)
+             (setq
+              ,proc-symb
+              (make-process
+               :name ,(concat (symbol-name name) "-flymake")
+               :noquery t
+               :connection-type 'pipe
+               :buffer (generate-new-buffer
+                        ,(concat " *" (symbol-name name) "-flymake*"))
+               :command
+               (prog1 ,command
+                 (flymake-log :debug "Checker command is %s" ,command))
+               :sentinel
+               (lambda (,proc-symb _event)
+                 (unless (process-live-p ,proc-symb)
+                   (unwind-protect
+                       (if ,@not-obsolete-form
+                           (let ((,diags-symb nil) ,current-diag-symb)
+                             (flymake-rest-define--parse-diags
+                              ,title
+                              ,proc-symb
+                              ,diags-symb
+                              ,current-diag-symb
+                              ,source-symb
+                              ,error-parser)
+                             ;; Report diagnostics when still not-obsolete.
+                             (if ,@not-obsolete-form
+                                 (progn
+                                   (let ((status (process-exit-status 
,proc-symb)))
+                                     (when (and (eq (length ,diags-symb) 0)
+                                                (not (eq status 0)))
+                                       (flymake-log
+                                        :warning
+                                        "Checker gave no diagnostics but had a 
non-zero \
+exit status %d\nStderr: %s"
+                                        status
+                                        (with-current-buffer (process-buffer 
,proc-symb)
+                                          (format "%s" 
(buffer-substring-no-properties
+                                                        (point-min) 
(point-max)))))))
+                                   (funcall report-fn ,diags-symb))
+                               ;; In case the check was cancelled after 
processing began
+                               ;; but before it finished.
+                               (flymake-log :warning "Canceling obsolete check 
%s" ,proc-symb)))
+                         (flymake-log :warning "Canceling obsolete check %s" 
,proc-symb))
+                     ;; Finished linting, cleanup any temp-files and then kill
+                     ;; the process buffer.
+                     ,@cleanup-form
+                     (kill-buffer (process-buffer ,proc-symb)))))))
              ;; Push the new-process to the process to the process alist.
              (setq flymake-rest-define--procs
                    (plist-put flymake-rest-define--procs ',name ,proc-symb))
              ;; If piping, send data to the process.
              ,@(when (eq write-type 'pipe)
-                 `((process-send-region proc (point-min) (point-max))
-                   (process-send-eof proc)))
+                 `((process-send-region ,proc-symb (point-min) (point-max))
+                   (process-send-eof ,proc-symb)))
+             ;; Return value of syntax-checker is checker function.
              ,proc-symb))))))
 
+
+;;; `flymake-rest-define-rx'
+
+(eval-when-compile
+  (require 'rx))
+
+(defconst flymake-rest-parse-rx-constituents
+  `((file-name ,(lambda (body)
+                  (rx-to-string
+                   `(group-n 1 ,@(or (cdr body)
+                                     '((minimal-match
+                                        (one-or-more not-newline)))))
+                   t))
+               0 nil) ;; group 1
+    (line . ,(rx (group-n 2 (one-or-more digit))))
+    (column . ,(rx (group-n 3 (one-or-more digit))))
+    (message ,(lambda (body)
+                (rx-to-string
+                 `(group-n 4 ,@(or (cdr body)
+                                   '((minimal-match
+                                      (one-or-more not-newline)))))
+                 t))
+             0 nil)
+    (id ,(lambda (body)
+           (rx-to-string `(group-n 5 ,@(cdr body)) t))
+        0 nil)
+    (end-line . ,(rx (group-n 6 (one-or-more digit))))
+    (end-column . ,(rx (group-n 7 (one-or-more digit))))))
+
+(defmacro flymake-rest-define--parse-rx (regexps)
+  "`flymake-rest-define' parser using regular expressions.
+
+This macro generates a parser that for each line of output from the
+checker process, matches one or more regular expressions and then
+converts the result to a valid flymake diagnostic that can be
+passed back to `flymake-make-diagnostic'.
+
+REGEXPS should be an alist with the car of each entry being the
+severity of the diagnostic it matches (as a symbol that will be
+turned into a keyword by this macro) and the cdr should be a
+sequence of entries that can be interpreted by the `rx' macro.
+To simplify matching specific fields in the parsed output several
+helper extensions to `rx' have been defined such as file-name or
+line. For a list of these see `flymake-rest-parse-rx-constituents'.
+The only required fields that MUST be parsed are the line number
+and message. If these are ommited the matched diagnostic will be
+skipped.
+
+WARN: You should not try to capture any extra fields outside of
+the special ones described above. This is because any extra capture
+groups are used to associate the severity of the diagnostic to the
+regexp that matched it (as a performance improvement).
+
+For an example of this macro in action, see `flymake-rest-pycodestyle'."
+  (unless (> (length regexps) 0)
+    (error "Must supply at least one regexp for error, warning or note"))
+
+  (let* ((group-count (length flymake-rest-parse-rx-constituents))
+         (regexps
+          ;; To avoid having to rematch each diagnostic more than once we 
append
+          ;; a special extra capture group (greater than all the ones above) 
that
+          ;; simply matches the empty string. Then we can index the groups 
after
+          ;; the ones above and use that to determine the severity of the 
symbol.
+          (cl-loop for (severity . regex) in regexps
+                   with count = group-count
+                   do (setq count (1+ count))
+                   collect (cons `(seq ,@regex (group-n ,count ""))
+                                 (intern (concat ":" (symbol-name 
severity))))))
+         (combined-regex
+          (let ((rx-constituents (append flymake-rest-parse-rx-constituents
+                                         (bound-and-true-p rx-constituents) 
nil)))
+            (rx-to-string `(or ,@(mapcar #'car regexps))
+                          'no-group)))
+         (severity-seq (mapcar #'cdr regexps)))
+    ;; Because if this evaluates to nil `flymake-rest-define' thinks there
+    ;; are no-more diagnostics to be parsed, we wrap it in a loop that exits
+    ;; the moment we find a match, but otherwise keeps moving through 
diagnostics
+    ;; until there actually aren't any more to match.
+    `(let (res ; file-name
+           line column message id end-line end-column severity-ix)
+       (while (and (not res)
+                   (search-forward-regexp ,combined-regex nil t))
+         (setq
+          res
+          (save-match-data
+            (save-excursion
+              (setq ; file-name (match-string 1)
+                    line (match-string 2)
+                    column (match-string 3)
+                    message (match-string 4)
+                    id (match-string 5)
+                    end-line (match-string 6)
+                    end-column (match-string 7)
+                    severity-ix (- (seq-find #'match-string
+                                             (number-sequence ,(1+ group-count)
+                                                              ,(+ group-count 
(length regexps))))
+                                   ,(1+ group-count)))
+              (cond
+               ;; Log an error when any of the required fields are missing.
+               ,@(cl-loop for it in '(severity-ix line message)
+                          collect
+                          `((not ,it)
+                            (flymake-log :error
+                                         ,(format
+                                           "Matched diagnostic didn't capture 
a %s group"
+                                           (symbol-name it)))
+                            nil))
+               (t
+                (let ((loc (flymake-diag-region flymake-rest-source
+                                                (string-to-number line)
+                                                (when column
+                                                  (string-to-number column))))
+                      (loc-end (when end-line
+                                 (flymake-diag-region flymake-rest-source
+                                                      (string-to-number 
end-line)
+                                                      (when end-column
+                                                        (string-to-number 
end-column))))))
+                  (when loc-end
+                    (setcdr loc (cdr loc-end)))
+                  (list flymake-rest-source
+                        (car loc)
+                        (cdr loc)
+                        (nth severity-ix (quote ,severity-seq))
+                        (concat
+                         (when id
+                           (concat (propertize id 'face 'flymake-rest-diag-id) 
" "))
+                         message)))))))))
+       res)))
+
+(cl-defmacro flymake-rest-define-rx
+    (name docstring
+          &optional &key title command write-type source-inplace pre-let 
pre-check regexps)
+  "`flymake-rest-define' helper using `rx' syntax to parse diagnostics.
+This helper macro adapts `flymake-rest-define' to use an error-parser built
+from a collections of REGEXPS (see `flymake-rest-define--parse-rx').
+
+See `flymake-rest-define' for a description of NAME, DOCSTRING, TITLE, COMMAND,
+WRITE-TYPE, SOURCE-INPLACE, PRE-LET, and PRE-CHECK."
+  (declare (indent defun) (doc-string 2))
+  `(flymake-rest-define ,name
+     ,docstring
+     :title ,title
+     :command ,command
+     :write-type ,write-type
+     :source-inplace ,source-inplace
+     :pre-let ,pre-let
+     :pre-check ,pre-check
+     :error-parser
+     (flymake-rest-define--parse-rx ,regexps)))
+
+
+;;; `flymake-rest-define-enumerate'
+
+(cl-defmacro flymake-rest-define-enumerate
+  (name docstring
+        &optional &key title command write-type source-inplace
+        pre-let pre-check generator enumerate-parser)
+  "`flymake-rest-define' helper for dealing with serialised diagnostics.
+This helper parses a collection of diagnostics using GENERATOR and then
+enumerates through it, entry by entry using ENUMERATE-PARSER. This is useful
+for linters that produce output such as JSON, to avoid having to reparse the
+output again and again.
+
+The value of the current entry from GENERATOR in ENUMERATE-PARSER will be set 
to
+the variable `it'. ENUMERATE-PARSER should evaluate to a form that can be 
passed
+to `flymake-make-diagnostic'."
+  (declare (indent defun) (doc-string 2))
+  (let ((entries-var 'flymake-rest-entries)
+        (parsed-var 'flymake-rest-parsed))
+    `(flymake-rest-define ,name
+       ,docstring
+       :title ,title
+       :command ,command
+       :write-type ,write-type
+       :source-inplace ,source-inplace
+       :pre-let ,(append `((,entries-var)
+                           (,parsed-var))
+                         pre-let)
+       :pre-check ,pre-check
+       :error-parser
+       (progn
+         (unless ,parsed-var
+           (setq ,entries-var ,generator
+                 ,parsed-var t))
+         (let (it res)
+           ;; While we haven't found a new diagnostic to return, BUT there're
+           ;; still diagnostics that can be found in the parsed checker output.
+           (while (and (not res)
+                       (setq it (pop ,entries-var)))
+             (setq res ,enumerate-parser))
+           res)))))
+
 (provide 'flymake-rest-define)
 
 ;;; flymake-rest-define.el ends here
diff --git a/flymake-rest-parse-enumerate.el b/flymake-rest-parse-enumerate.el
deleted file mode 100644
index 6f7f0657df..0000000000
--- a/flymake-rest-parse-enumerate.el
+++ /dev/null
@@ -1,56 +0,0 @@
-;;; flymakflymake-backend-parse-enumerate!to simplify checker creation -*- 
lexical-binding: t -*-
-
-;; Copyright (c) 2021 Mohsin Kaleem
-
-;; Permission is hereby granted, free of charge, to any person obtaining a copy
-;; of this software and associated documentation files (the "Software"), to 
deal
-;; in the Software without restriction, including without limitation the rights
-;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-;; copies of the Software, and to permit persons to whom the Software is
-;; furnished to do so, subject to the following conditions:
-
-;; The above copyright notice and this permission notice shall be included in 
all
-;; copies or substantial portions of the Software.
-
-;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
-;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
THE
-;; SOFTWARE.
-
-;;; Commentary:
-;; This file defines an error-parser for `flymake-rest-define' which can be 
used
-;; to parse JSON output from the checker into flymake diagnostics. This works 
by
-;; parsing the entire JSON input into a list of diagnostic related data, and 
then
-;; iteratively parsing it into diagnostics.
-
-;;; Code:
-
-;;;###autoload
-(defmacro flymake-rest-parse-enumerate (gen &rest body)
-  "Error parser for `flymake-backend-define' which parses all of
-the diagnostics at once using GEN and then prepares them one-at-a-time
-with BODY.
-
-The value of the current entry from GEN in BODY will be set to the variable
-`it'. BODY should evaluate to a form that can be passed to
-`flymake-make-diagnostic'."
-  (declare (indent 1))
-  (let ((context-var (intern "flymake-rest-context")))
-    `(progn
-       (unless (alist-get 'enumerated ,context-var)
-         (push (cons 'entries ,gen) ,context-var)
-         (push '(enumerated t) ,context-var))
-       (let (it res)
-         ;; While we haven't found a new diagnostic to return, BUT there're
-         ;; still diagnostics that can be found in the parsed checker output.
-         (while (and (not res)
-                     (setq it (pop (alist-get 'entries ,context-var))))
-           (setq res ,@body))
-         res))))
-
-(provide 'flymake-rest-parse-enumerate)
-
-;;; flymake-rest-parse-enumerate.el ends here
diff --git a/flymake-rest-parse-rx.el b/flymake-rest-parse-rx.el
deleted file mode 100644
index f2a710ae34..0000000000
--- a/flymake-rest-parse-rx.el
+++ /dev/null
@@ -1,164 +0,0 @@
-;;; flymake-rest-rest.el --- A macro to simplify checker creation -*- 
lexical-binding: t -*-
-
-;; Copyright (c) 2021 Mohsin Kaleem
-
-;; Permission is hereby granted, free of charge, to any person obtaining a copy
-;; of this software and associated documentation files (the "Software"), to 
deal
-;; in the Software without restriction, including without limitation the rights
-;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-;; copies of the Software, and to permit persons to whom the Software is
-;; furnished to do so, subject to the following conditions:
-
-;; The above copyright notice and this permission notice shall be included in 
all
-;; copies or substantial portions of the Software.
-
-;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
-;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
THE
-;; SOFTWARE.
-
-;;; Commentary:
-;; This file defines an error-parser for `flymake-rest-define' which can be 
used
-;; to parse plaintext output from the checker into flymake diagnostics. This 
works
-;; by defining some regular expressions (one for each severity level of the 
checker)
-;; and then matching each line of the output to a regular expression. Special
-;; capture groups have been setup by the parser that should be used by any 
calling
-;; checkers to ensure the correct fields from the output can be parsed.
-;;
-;; The approach implemented here was heavily inspired by flychecks 
:error-parsers
-;; feature.
-
-;;; Code:
-
-(require 'rx)
-
-(defconst flymake-rest-parse-rx-constituents
-  `((file-name ,(lambda (body)
-                  (rx-to-string
-                   `(group-n 1 ,@(or (cdr body)
-                                     '((minimal-match
-                                        (one-or-more not-newline)))))
-                   t))
-               0 nil) ;; group 1
-    (line . ,(rx (group-n 2 (one-or-more digit))))
-    (column . ,(rx (group-n 3 (one-or-more digit))))
-    (message ,(lambda (body)
-                (rx-to-string
-                 `(group-n 4 ,@(or (cdr body)
-                                   '((minimal-match
-                                      (one-or-more not-newline)))))
-                 t))
-             0 nil)
-    (id ,(lambda (body)
-           (rx-to-string `(group-n 5 ,@(cdr body)) t))
-        0 nil)
-    (end-line . ,(rx (group-n 6 (one-or-more digit))))
-    (end-column . ,(rx (group-n 7 (one-or-more digit))))))
-
-;;;###autoload
-(defmacro flymake-rest-parse-rx (regexps)
-  "`flymake-rest-define' parser using regular expressions.
-
-This macro generates a parser that for each line of output from the
-checker process, matches one or more regular expressions and then
-converts the result to a valid flymake diagnostic that can be
-passed back to `flymake-make-diagnostic'.
-
-REGEXPS should be an alist with the car of each entry being the
-severity of the diagnostic it matches (as a symbol that will be
-turned into a keyword by this macro) and the cdr should be a
-sequence of entries that can be interpreted by the `rx' macro.
-To simplify matching specific fields in the parsed output several
-helper extensions to `rx' have been defined such as file-name or
-line. For a list of these see `flymake-rest-parse-rx-constituents'.
-The only required fields that MUST be parsed are the line number
-and message. If these are ommited the matched diagnostic will be
-skipped.
-
-WARN: You should not try to capture any extra fields outside of
-the special ones described above. This is because any extra capture
-groups are used to associate the severity of the diagnostic to the
-regexp that matched it (as a performance improvement).
-
-For an example of this macro in action, see `flymake-rest-pycodestyle'."
-  (unless (> (length regexps) 0)
-    (error "Must supply at least one regexp for error, warning or note"))
-
-  (let* ((group-count (length flymake-rest-parse-rx-constituents))
-         (regexps
-          ;; To avoid having to rematch each diagnostic more than once we 
append
-          ;; a special extra capture group (greater than all the ones above) 
that
-          ;; simply matches the empty string. Then we can index the groups 
after
-          ;; the ones above and use that to determine the severity of the 
symbol.
-          (cl-loop for (severity . regex) in regexps
-                   with count = group-count
-                   do (setq count (1+ count))
-                   collect (cons `(seq ,@regex (group-n ,count ""))
-                                 (intern (concat ":" (symbol-name 
severity))))))
-         (combined-regex
-          (let ((rx-constituents (append flymake-rest-parse-rx-constituents
-                                         rx-constituents nil)))
-            (rx-to-string `(or ,@(mapcar #'car regexps))
-                          'no-group)))
-         (severity-seq (mapcar #'cdr regexps)))
-    ;; Because if this evaluates to nil `flymake-rest-define' thinks there
-    ;; are no-more diagnostics to be parsed, we wrap it in a loop that exits
-    ;; the moment we find a match, but otherwise keeps moving through 
diagnostics
-    ;; until there actually aren't any more to match.
-    `(let (res ; file-name
-           line column message id end-line end-column severity-ix)
-       (while (and (not res)
-                   (search-forward-regexp ,combined-regex nil t))
-         (setq
-          res
-          (save-match-data
-            (save-excursion
-              (setq ; file-name (match-string 1)
-                    line (match-string 2)
-                    column (match-string 3)
-                    message (match-string 4)
-                    id (match-string 5)
-                    end-line (match-string 6)
-                    end-column (match-string 7)
-                    severity-ix (- (seq-find #'match-string
-                                             (number-sequence ,(1+ group-count)
-                                                              ,(+ group-count 
(length regexps))))
-                                   ,(1+ group-count)))
-              (cond
-               ;; Log an error when any of the required fields are missing.
-               ,@(cl-loop for it in '(severity-ix line message)
-                          collect
-                          `((not ,it)
-                            (flymake-log :error
-                                         ,(format
-                                           "Matched diagnostic didn't capture 
a %s group"
-                                           (symbol-name it)))
-                            nil))
-               (t
-                (let ((loc (flymake-diag-region flymake-rest-source
-                                                (string-to-number line)
-                                                (when column
-                                                  (string-to-number column))))
-                      (loc-end (when end-line
-                                 (flymake-diag-region flymake-rest-source
-                                                      (string-to-number 
end-line)
-                                                      (when end-column
-                                                        (string-to-number 
end-column))))))
-                  (when loc-end
-                    (setcdr loc (cdr loc-end)))
-                  (list flymake-rest-source
-                        (car loc)
-                        (cdr loc)
-                        (nth severity-ix (quote ,severity-seq))
-                        (concat
-                         (when id
-                           (concat (propertize id 'face 'flymake-rest-diag-id) 
" "))
-                         message)))))))))
-       res)))
-
-(provide 'flymake-rest-parse-rx)
-
-;;; flymake-rest-parse-rx.el ends here
diff --git a/flymake-rest.el b/flymake-rest.el
index 7dc1128dc3..f72fe3e0df 100644
--- a/flymake-rest.el
+++ b/flymake-rest.el
@@ -6,7 +6,7 @@
 ;; Created: 15 June 2021
 ;; Homepage: https://github.com/mohkale/flymake-rest
 ;; Keywords: language tools
-;; Package-Requires: ((emacs "27.1"))
+;; Package-Requires: ((emacs "27.1") (let-alist "1.0"))
 ;; SPDX-License-Identifier: MIT
 ;; Version: 1.0.0
 
@@ -61,7 +61,7 @@
   "Id of a diagnostic.")
 
 (defun flymake-rest-parse-json (output)
-  "Helper for `flymake-rest-define' to parse JSON output OUTPUT.
+  "Helper for `flymake-rest-define' to parse JSON OUTPUT.
 
 Adapted from `flycheck-parse-json'. This reads a bunch of JSON-Lines
 like output from OUTPUT into a list and then returns it."

Reply via email to