mirror of
https://github.com/vale981/apheleia
synced 2025-03-04 17:11:40 -05:00
Add support for formatters locally installed via yarn 2+ pnp mode (#200)
This adds support for formatters installed locally in project directories via yarn 2's "zero install" [pnp mode](https://yarnpkg.com/features/pnp). It's quite similar to the support for formatters installed locally in a project's `node_modules` via npm, and leverages the `npx` symbol, so existing formatter definitions should work without modification. This checks for a `.pnp.cjs` file (expected in the project root for yarn pnp projects), then looks for a yarn executable, and checks the version of yarn to make sure it supports pnp. If that works, we just push `"yarn"` onto the front of `command`. I've only tested this with a locally installed `prettier.js`. It's very much a works-for-me draft, I'm putting in a PR to make sure this is a workable approach before going any further with it. --------- Co-authored-by: Radon Rosborough <radon@intuitiveexplanations.com>
This commit is contained in:
parent
47547ea694
commit
54a192c345
9 changed files with 140 additions and 52 deletions
|
@ -27,6 +27,10 @@ The format is based on [Keep a Changelog].
|
||||||
* Prettier is now enabled in `svelte-mode`.
|
* Prettier is now enabled in `svelte-mode`.
|
||||||
* More tree-sitter based major modes have been added to
|
* More tree-sitter based major modes have been added to
|
||||||
`apheleia-mode-alist` ([#191]).
|
`apheleia-mode-alist` ([#191]).
|
||||||
|
* Built-in formatters now use a new `"apheleia-npx"` built-in script
|
||||||
|
instead of the legacy `npx` keyword. The effect of the new script is
|
||||||
|
the same, except that it also works with Yarn PNP projects as well
|
||||||
|
as `node_modules` style projects ([#200]).
|
||||||
* Autoload the apheleia-goto-error command ([#215]).
|
* Autoload the apheleia-goto-error command ([#215]).
|
||||||
* Use `lisp-indent` as default formatter for `emacs-lisp-mode` ([#223])
|
* Use `lisp-indent` as default formatter for `emacs-lisp-mode` ([#223])
|
||||||
* Use `hclfmt` for formatting hashicorp HCL files ([#231])
|
* Use `hclfmt` for formatting hashicorp HCL files ([#231])
|
||||||
|
@ -34,6 +38,9 @@ The format is based on [Keep a Changelog].
|
||||||
### Internal Changes
|
### Internal Changes
|
||||||
* Refactored the organisation of the apheleia package for ease of
|
* Refactored the organisation of the apheleia package for ease of
|
||||||
understanding and usability ([#215]).
|
understanding and usability ([#215]).
|
||||||
|
* The new `scripts/pnp-bin.js` script is standalone minified nodejs built
|
||||||
|
from the [`pnp-bin`](https://github.com/PuddleByteComputing/pnp-bin) repo,
|
||||||
|
extracted from apheleia PR [#200].
|
||||||
|
|
||||||
### Bugs fixed
|
### Bugs fixed
|
||||||
* `ktlint` would emit log messages into its stdout when formatting,
|
* `ktlint` would emit log messages into its stdout when formatting,
|
||||||
|
|
|
@ -81,42 +81,45 @@
|
||||||
(perltidy . ("perltidy" "--quiet" "--standard-error-output"))
|
(perltidy . ("perltidy" "--quiet" "--standard-error-output"))
|
||||||
(phpcs . ("apheleia-phpcs"))
|
(phpcs . ("apheleia-phpcs"))
|
||||||
(prettier
|
(prettier
|
||||||
. (npx "prettier" "--stdin-filepath" filepath
|
. ("apheleia-npx" "prettier" "--stdin-filepath" filepath
|
||||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||||
(prettier-css
|
(prettier-css
|
||||||
. (npx "prettier" "--stdin-filepath" filepath "--parser=css"
|
. ("apheleia-npx" "prettier" "--parser=css"
|
||||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||||
(prettier-html
|
(prettier-html
|
||||||
. (npx "prettier" "--stdin-filepath" filepath "--parser=html"
|
. ("apheleia-npx" "prettier" "--parser=html"
|
||||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||||
(prettier-graphql
|
(prettier-graphql
|
||||||
. (npx "prettier" "--stdin-filepath" filepath "--parser=graphql"
|
. ("apheleia-npx" "prettier" "--parser=graphql"
|
||||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||||
(prettier-javascript
|
(prettier-javascript
|
||||||
. (npx "prettier" "--stdin-filepath" filepath "--parser=babel-flow"
|
. ("apheleia-npx" "prettier" "--parser=babel-flow"
|
||||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||||
(prettier-json
|
(prettier-json
|
||||||
. (npx "prettier" "--stdin-filepath" filepath "--parser=json"
|
. ("apheleia-npx" "prettier" "--parser=json"
|
||||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||||
(prettier-markdown
|
(prettier-markdown
|
||||||
. (npx "prettier" "--stdin-filepath" filepath "--parser=markdown"
|
. ("apheleia-npx" "prettier" "--parser=markdown"
|
||||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||||
(prettier-ruby
|
(prettier-ruby
|
||||||
. (npx "prettier" "--stdin-filepath" filepath "--parser=ruby"
|
. ("apheleia-npx" "prettier" "--stdin-filepath" "dummy.rb"
|
||||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
"--plugin=@prettier/plugin-ruby"
|
||||||
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||||
(prettier-scss
|
(prettier-scss
|
||||||
. (npx "prettier" "--stdin-filepath" filepath "--parser=scss"
|
. ("apheleia-npx" "prettier" "--stdin-filepath" filepath
|
||||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
"--parser=scss"
|
||||||
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||||
(prettier-svelte
|
(prettier-svelte
|
||||||
. (npx "prettier" "--stdin-filepath" filepath "--parser=svelte"
|
. ("apheleia-npx" "prettier" "--stdin-filepath" filepath
|
||||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
"--plugin=prettier-plugin-svelte"
|
||||||
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||||
(prettier-typescript
|
(prettier-typescript
|
||||||
. (npx "prettier" "--stdin-filepath" filepath "--parser=typescript"
|
. ("apheleia-npx" "prettier" "--parser=typescript"
|
||||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||||
(prettier-yaml
|
(prettier-yaml
|
||||||
. (npx "prettier" "--stdin-filepath" filepath "--parser=yaml"
|
. ("apheleia-npx" "prettier" "--parser=yaml"
|
||||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||||
(purs-tidy . (npx "purs-tidy" "format"))
|
(purs-tidy . ("apheleia-npx" "purs-tidy" "format"))
|
||||||
(rubocop . ("rubocop" "--stdin" filepath "--auto-correct"
|
(rubocop . ("rubocop" "--stdin" filepath "--auto-correct"
|
||||||
"--stderr" "--format" "quiet" "--fail-level" "fatal"))
|
"--stderr" "--format" "quiet" "--fail-level" "fatal"))
|
||||||
(ruby-standard . ("standardrb" "--stdin" filepath "--fix" "--stderr"
|
(ruby-standard . ("standardrb" "--stdin" filepath "--fix" "--stderr"
|
||||||
|
@ -185,6 +188,11 @@ then the first string element of the command list is resolved
|
||||||
inside node_modules/.bin if such a directory exists anywhere
|
inside node_modules/.bin if such a directory exists anywhere
|
||||||
above the current `default-directory'.
|
above the current `default-directory'.
|
||||||
|
|
||||||
|
\(However, instead of using `npx', consider using
|
||||||
|
\"apheleia-npx\", which is a built-in script that will replicate
|
||||||
|
the effect, but will also work with Yarn PNP projects and other
|
||||||
|
npm project types that may exist in the future.)
|
||||||
|
|
||||||
Any list elements that are not strings and not any of the special
|
Any list elements that are not strings and not any of the special
|
||||||
symbols mentioned above will be evaluated when the formatter is
|
symbols mentioned above will be evaluated when the formatter is
|
||||||
invoked, and spliced into the list. A form can evaluate either to
|
invoked, and spliced into the list. A form can evaluate either to
|
||||||
|
@ -834,7 +842,7 @@ it's first in the sequence"))
|
||||||
(unless remote-match
|
(unless remote-match
|
||||||
(error "Formatter uses `file' but process will run on different \
|
(error "Formatter uses `file' but process will run on different \
|
||||||
machine from the machine file is available on"))
|
machine from the machine file is available on"))
|
||||||
(setq stdin nil)
|
(setq stdin nil)
|
||||||
;; If `buffer-file-name' is nil then there is no backing
|
;; If `buffer-file-name' is nil then there is no backing
|
||||||
;; file, so `buffer-modified-p' should be ignored (it always
|
;; file, so `buffer-modified-p' should be ignored (it always
|
||||||
;; returns non-nil).
|
;; returns non-nil).
|
||||||
|
|
|
@ -7,6 +7,7 @@ find=(
|
||||||
find .
|
find .
|
||||||
-name .git -prune -o
|
-name .git -prune -o
|
||||||
-name .log -prune -o
|
-name .log -prune -o
|
||||||
|
-path ./scripts/pnp-bin.js -prune -o
|
||||||
-path ./test/formatters -prune -o
|
-path ./test/formatters -prune -o
|
||||||
-name "*.elc" -o
|
-name "*.elc" -o
|
||||||
-type f -print
|
-type f -print
|
||||||
|
|
71
scripts/formatters/apheleia-npx
Executable file
71
scripts/formatters/apheleia-npx
Executable file
|
@ -0,0 +1,71 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# This script is like npx but also works for yarn pnp projects, and
|
||||||
|
# never tries to install anything. It is very fast.
|
||||||
|
#
|
||||||
|
# The script takes as arguments a command to execute and the arguments
|
||||||
|
# to pass to it. If the command is installed as a binary by an npm
|
||||||
|
# module in the current project, then that binary is used. Otherwise,
|
||||||
|
# the script is execed as normal from $PATH. In either case, the
|
||||||
|
# working directory is preserved.
|
||||||
|
|
||||||
|
if (( "$#" == 0 )); then
|
||||||
|
echo >&2 "usage: apheleia-npx CMD [ARG...]"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# location of this script
|
||||||
|
apheleia_dir="$(cd $(dirname ${BASH_SOURCE[0]})/../.. &>/dev/null && pwd)"
|
||||||
|
pnp_bin="${apheleia_dir}/scripts/pnp-bin.js"
|
||||||
|
|
||||||
|
# This function prints the name of the current directory if it
|
||||||
|
# contains a file or directory named after the first argument, or the
|
||||||
|
# parent directory if it contains such a file, or the parent's parent,
|
||||||
|
# and so on. If no such file is found it returns nonzero.
|
||||||
|
# https://unix.stackexchange.com/a/22215
|
||||||
|
find_upwards() {
|
||||||
|
fname="$1"
|
||||||
|
|
||||||
|
path="${PWD}"
|
||||||
|
while [[ -n "${path}" && ! -e "${path}/${fname}" ]]; do
|
||||||
|
path="${path%/*}"
|
||||||
|
done
|
||||||
|
[[ -n "${path}" ]] && echo "${path}"
|
||||||
|
}
|
||||||
|
|
||||||
|
dir="$(find_upwards package.json)"
|
||||||
|
|
||||||
|
if [[ -d $dir ]]; then
|
||||||
|
cd $dir
|
||||||
|
|
||||||
|
pnp_root=$(find_upwards '.pnp.cjs')
|
||||||
|
npm_root=$(find_upwards 'node_modules')
|
||||||
|
|
||||||
|
if [[ -n ${pnp_root} && ${#pnp_root} -gt ${#npm_root} ]]; then
|
||||||
|
# trying pnp
|
||||||
|
pnp_path="${pnp_root}/.pnp.cjs"
|
||||||
|
bin="$(${pnp_bin} ${pnp_path} $1)"
|
||||||
|
# note: $bin might not be on the real filesystem,
|
||||||
|
# might be in a zip archive
|
||||||
|
if [[ -n $bin ]]; then
|
||||||
|
if [[ -f "${pnp_path}/.pnp.loader.mjs" ]]; then
|
||||||
|
loader_opt="--loader ${pnp_path}/.pnp.loader.mjs"
|
||||||
|
fi
|
||||||
|
node=$(which node)
|
||||||
|
command="${node} --require ${pnp_path} ${loader_opt} ${bin} ${@:2}"
|
||||||
|
exec ${command}
|
||||||
|
fi
|
||||||
|
elif [[ -n ${npm_root} ]]; then
|
||||||
|
# trying npm
|
||||||
|
node_modules_paths=(\
|
||||||
|
$(node -e 'console.log(require.resolve.paths("").join("\n"))'))
|
||||||
|
for path in ${node_modules_paths[@]}; do
|
||||||
|
if [[ -x "${path}/.bin/$1" ]]; then
|
||||||
|
exec "${path}/.bin/$1" "${@:2}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Fall back to executing the command if it's installed and on the user's $PATH
|
||||||
|
exec "$@"
|
2
scripts/pnp-bin.js
Executable file
2
scripts/pnp-bin.js
Executable file
File diff suppressed because one or more lines are too long
|
@ -101,11 +101,12 @@ relative to repo root, as returned by git diff --name-only."
|
||||||
((string-match
|
((string-match
|
||||||
"^scripts/formatters/\\([^/]+\\)$" changed-file)
|
"^scripts/formatters/\\([^/]+\\)$" changed-file)
|
||||||
(let ((script (match-string 1 changed-file)))
|
(let ((script (match-string 1 changed-file)))
|
||||||
(map-keys
|
(mapcar #'symbol-name
|
||||||
(map-filter
|
(map-keys
|
||||||
(lambda (fmt def)
|
(map-filter
|
||||||
(member script def))
|
(lambda (fmt def)
|
||||||
apheleia-formatters)))))))
|
(and (listp def) (member script def)))
|
||||||
|
apheleia-formatters))))))))
|
||||||
|
|
||||||
(defun apheleia-ft--get-formatters-for-pull-request ()
|
(defun apheleia-ft--get-formatters-for-pull-request ()
|
||||||
"Return list of formatter string names that were touched in this PR.
|
"Return list of formatter string names that were touched in this PR.
|
||||||
|
@ -133,7 +134,10 @@ main."
|
||||||
"Print to stdout a comma-delimited list of formatters changed in this PR."
|
"Print to stdout a comma-delimited list of formatters changed in this PR."
|
||||||
(princ (concat
|
(princ (concat
|
||||||
(string-join
|
(string-join
|
||||||
(apheleia-ft--get-formatters-for-pull-request) ",")
|
(cl-remove-duplicates
|
||||||
|
(apheleia-ft--get-formatters-for-pull-request)
|
||||||
|
:test 'string=)
|
||||||
|
",")
|
||||||
"\n")))
|
"\n")))
|
||||||
|
|
||||||
(defun apheleia-ft--read-file (filename)
|
(defun apheleia-ft--read-file (filename)
|
||||||
|
|
|
@ -6,14 +6,10 @@ export DEBIAN_FRONTEND=noninteractive
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y ca-certificates curl gnupg lsb-release software-properties-common
|
apt-get install -y ca-certificates curl gnupg lsb-release software-properties-common
|
||||||
|
|
||||||
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add -
|
mkdir -p /etc/apt/keyrings
|
||||||
|
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
|
||||||
ubuntu_name="$(lsb_release -cs)"
|
NODE_MAJOR=20
|
||||||
node_repo="$(curl -fsSL https://deb.nodesource.com/setup_current.x | grep NODEREPO= | grep -Eo 'node_[0-9]+\.x' | head -n1)"
|
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
|
||||||
|
|
||||||
tee -a /etc/apt/sources.list.d/nodejs.list >/dev/null <<EOF
|
|
||||||
deb [arch=amd64] https://deb.nodesource.com/${node_repo} ${ubuntu_name} main
|
|
||||||
EOF
|
|
||||||
|
|
||||||
add-apt-repository -n ppa:longsleep/golang-backports
|
add-apt-repository -n ppa:longsleep/golang-backports
|
||||||
|
|
||||||
|
@ -30,9 +26,6 @@ nodejs
|
||||||
sudo
|
sudo
|
||||||
unzip
|
unzip
|
||||||
wget
|
wget
|
||||||
sudo
|
|
||||||
unzip
|
|
||||||
wget
|
|
||||||
|
|
||||||
"
|
"
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
# Need ruby for gem, need gcc and ruby headers for native gem deps
|
# Need ruby for gem, need gcc and ruby headers for native gem deps
|
||||||
apt-get install -y ruby ruby-dev gcc
|
apt-get install -y ruby ruby-dev gcc
|
||||||
|
|
||||||
# Install the plugin
|
# Apparently rubygems does not know how to do dependency resolution.
|
||||||
npm install -g prettier @prettier/plugin-ruby
|
# So we have to manually install an old version of this dependency to
|
||||||
|
# avoid the latest version getting installed and then failing to build
|
||||||
# Have to install from source because release not tagged yet
|
# because it does not support ruby 2.7 which is what we have.
|
||||||
# https://github.com/ruby-syntax-tree/syntax_tree-rbs/pull/34
|
gem install rbs -v 3.1.3
|
||||||
# https://stackoverflow.com/a/11767563
|
|
||||||
gem install specific_install
|
|
||||||
gem specific_install -l https://github.com/ruby-syntax-tree/syntax_tree-rbs.git
|
|
||||||
|
|
||||||
# These are required dependencies documented at
|
# These are required dependencies documented at
|
||||||
# https://www.npmjs.com/package/@prettier/plugin-ruby
|
# https://www.npmjs.com/package/@prettier/plugin-ruby
|
||||||
gem install prettier_print syntax_tree syntax_tree-haml syntax_tree-rbs
|
gem install prettier_print syntax_tree syntax_tree-haml syntax_tree-rbs
|
||||||
|
|
||||||
|
# Install the plugin
|
||||||
|
cd /tmp
|
||||||
|
npm install --save-dev prettier @prettier/plugin-ruby
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
npm install -g prettier-plugin-svelte prettier
|
cd /tmp
|
||||||
|
npm install --save-dev prettier-plugin-svelte prettier
|
||||||
|
|
Loading…
Add table
Reference in a new issue