From 64e0779e11053dbed5b65c13702179e655a766f0 Mon Sep 17 00:00:00 2001 From: aecepoglu Date: Sat, 16 Dec 2023 12:28:01 +0000 Subject: [PATCH] use flymake-eslint-executable to access eslint indirectly (#26) --- README.md | 24 +++++++++++------- flymake-eslint.el | 63 ++++++++++++++++++++--------------------------- 2 files changed, 42 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 94e7010..107e68c 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,8 @@ Flymake backend for Javascript using eslint ## Installation -0. Make sure `eslint` is installed and present on your emacs `exec-path`. For Linux systems `exec-path` usually equals your `$PATH` environment variable; for other systems, you're on your own. +0. Make sure `eslint` is present on your `exec-path`. If you want to use an `eslint` local to your project (through `npx`) you must configure (see _Customization_ below) `flymake-eslint-executable` variable to `'("npx" "eslint")`. + For Linux systems `exec-path` usually equals your `$PATH` environment variable; for other systems, you're on your own. 1. Install: - from MELPA: `M-x package-install [RET] flymake-eslint [RET]` - manually: download and place inside `~/.emacs.d/lisp` then edit `~/.emacs` or equivalent: @@ -24,13 +25,16 @@ Flymake backend for Javascript using eslint useful variables are members of the `flymake-eslint` group and can be viewed and modified with the command `M-x customize-group [RET] flymake-eslint [RET]`. ```lisp -(defcustom flymake-eslint-executable-name "eslint" - "Name of executable to run when checker is called. Must be present in variable `exec-path'." - :type 'string - :group 'flymake-eslint) - -(defcustom flymake-eslint-executable-args nil - "Extra arguments to pass to eslint." +(defcustom flymake-eslint-executable '("eslint") + "Name and arguments to call eslint with. + Examples: + '(\"eslint\") ; if eslint exists and available in exec-path + '(\"npx" "eslint\") ; if eslint is called through npx. Allows access to project-local eslint + '(\"npm\" \"exec\" \"--\" \"eslint\") ; equivalent to \"npx\" + + You can also send additional arguments to eslint. For example to set eslint's --max-warnings to 13: + '(\"eslint\" \"--max-warnings\" \"13\") + '(\"npx\" \"eslint\" \"--max-warnings\" \"13\")" :type 'string :group 'flymake-eslint) @@ -65,7 +69,9 @@ yes ## See Also -[flymake-stylelint](https://github.com/orzechowskid/flymake-stylelint) +* [flymake-stylelint](https://github.com/orzechowskid/flymake-stylelint) +* [npx](https://docs.npmjs.com/cli/v7/commands/npx) +* [eslint CLI](https://eslint.org/docs/latest/use/command-line-interface) ## License diff --git a/flymake-eslint.el b/flymake-eslint.el index f0fc5cc..2019850 100644 --- a/flymake-eslint.el +++ b/flymake-eslint.el @@ -38,15 +38,17 @@ :group 'programming :prefix "flymake-eslint-") -(defcustom flymake-eslint-executable-name "eslint" - "Name of executable to run when checker is called. -Must be present in variable `exec-path'." - :type 'string - :group 'flymake-eslint) - -(defcustom flymake-eslint-executable-args nil - "Extra arguments to pass to eslint." - :type '(choice string (repeat string)) +(defcustom flymake-eslint-executable '("eslint") + "Arguments to execute `eslint' + Example values: + '(\"eslint\") ; to use an eslint available in exec-ptah + '(\"npx\" \"eslint\") ; to use eslint through npx. Allows access to project-local eslint + '(\"npm\" \"exec\" \"--\" \"eslint\") ; equivalent to \"npx\" + + You can also send additional arguments to eslint. For example to set eslint's --max-warnings to 13: + '(\"eslint\" \"--max-warnings\" \"13\") + '(\"npx\" \"eslint\" \"--max-warnings\" \"13\")" + :type '(repeat string) :group 'flymake-eslint) (defcustom flymake-eslint-show-rule-name t @@ -100,31 +102,28 @@ installation with JSON support." "Enable Flymake and flymake-eslint. Add this function to some js major mode hook." (interactive) + (make-local-variable 'flymake-eslint-project-root) + (setq default-directory + (or flymake-eslint-project-root + (when (and (featurep 'project) + (project-current)) + (project-root (project-current))) + default-directory)) (unless flymake-eslint-defer-binary-check (flymake-eslint--ensure-binary-exists)) - (make-local-variable 'flymake-eslint-project-root) (flymake-mode t) (add-hook 'flymake-diagnostic-functions 'flymake-eslint--checker nil t)) ;;;;; Private -(defun flymake-eslint--executable-args () - "Get additional arguments for `flymake-eslint-executable-name'. -Return `flymake-eslint-executable-args' value and ensure that -this is a list." - (if (listp flymake-eslint-executable-args) - flymake-eslint-executable-args - (list flymake-eslint-executable-args))) - (defun flymake-eslint--ensure-binary-exists () - "Ensure that `flymake-eslint-executable-name' exists. + "Ensure that `flymake-eslint-executable' exists and can be invoked with `--version' Otherwise, throw an error and tell Flymake to disable this -backend if `flymake-eslint-executable-name' can't be found in -variable `exec-path'" - (unless (executable-find flymake-eslint-executable-name) - (let ((option 'flymake-eslint-executable-name)) - (error "Can't find \"%s\" in exec-path - try to configure `%s'" - (symbol-value option) option)))) +backend." + (with-temp-buffer + (let ((x flymake-eslint-executable)) + (unless (= 0 (apply 'call-process `(,(car x) nil t (current-buffer) ,@(cdr x) "--version"))) + (error "`eslint' invocation failed. It errored with message: %s" (buffer-string)))))) (defun flymake-eslint--get-position (line column buffer) "Get the position at LINE and COLUMN for BUFFER." @@ -226,14 +225,7 @@ CALLBACK accepts a buffer containing stdout from linter as its argument." (when (process-live-p flymake-eslint--process) (kill-process flymake-eslint--process)) - (let ((default-directory - (or - flymake-eslint-project-root - (when (and (featurep 'project) - (project-current)) - (project-root (project-current))) - default-directory)) - (format-args + (let ((format-args (if (flymake-eslint--use-json-p) '("--format" "json") ""))) @@ -243,14 +235,13 @@ argument." :connection-type 'pipe :noquery t :buffer (generate-new-buffer " *flymake-eslint*") - :command `(,flymake-eslint-executable-name + :command `(,@flymake-eslint-executable "--no-color" "--no-ignore" ,@format-args "--stdin" "--stdin-filename" - ,(buffer-file-name source-buffer) - ,@(flymake-eslint--executable-args)) + ,(buffer-file-name source-buffer)) :sentinel (lambda (proc &rest ignored) (let ((status (process-status proc))