mirror of
https://github.com/vale981/apheleia
synced 2025-03-04 09:01:42 -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`.
|
||||
* More tree-sitter based major modes have been added to
|
||||
`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]).
|
||||
* Use `lisp-indent` as default formatter for `emacs-lisp-mode` ([#223])
|
||||
* Use `hclfmt` for formatting hashicorp HCL files ([#231])
|
||||
|
@ -34,6 +38,9 @@ The format is based on [Keep a Changelog].
|
|||
### Internal Changes
|
||||
* Refactored the organisation of the apheleia package for ease of
|
||||
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
|
||||
* `ktlint` would emit log messages into its stdout when formatting,
|
||||
|
|
|
@ -81,42 +81,45 @@
|
|||
(perltidy . ("perltidy" "--quiet" "--standard-error-output"))
|
||||
(phpcs . ("apheleia-phpcs"))
|
||||
(prettier
|
||||
. (npx "prettier" "--stdin-filepath" filepath
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
. ("apheleia-npx" "prettier" "--stdin-filepath" filepath
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
(prettier-css
|
||||
. (npx "prettier" "--stdin-filepath" filepath "--parser=css"
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
. ("apheleia-npx" "prettier" "--parser=css"
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
(prettier-html
|
||||
. (npx "prettier" "--stdin-filepath" filepath "--parser=html"
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
. ("apheleia-npx" "prettier" "--parser=html"
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
(prettier-graphql
|
||||
. (npx "prettier" "--stdin-filepath" filepath "--parser=graphql"
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
. ("apheleia-npx" "prettier" "--parser=graphql"
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
(prettier-javascript
|
||||
. (npx "prettier" "--stdin-filepath" filepath "--parser=babel-flow"
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
. ("apheleia-npx" "prettier" "--parser=babel-flow"
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
(prettier-json
|
||||
. (npx "prettier" "--stdin-filepath" filepath "--parser=json"
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
. ("apheleia-npx" "prettier" "--parser=json"
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
(prettier-markdown
|
||||
. (npx "prettier" "--stdin-filepath" filepath "--parser=markdown"
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
. ("apheleia-npx" "prettier" "--parser=markdown"
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
(prettier-ruby
|
||||
. (npx "prettier" "--stdin-filepath" filepath "--parser=ruby"
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
. ("apheleia-npx" "prettier" "--stdin-filepath" "dummy.rb"
|
||||
"--plugin=@prettier/plugin-ruby"
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
(prettier-scss
|
||||
. (npx "prettier" "--stdin-filepath" filepath "--parser=scss"
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
. ("apheleia-npx" "prettier" "--stdin-filepath" filepath
|
||||
"--parser=scss"
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
(prettier-svelte
|
||||
. (npx "prettier" "--stdin-filepath" filepath "--parser=svelte"
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
. ("apheleia-npx" "prettier" "--stdin-filepath" filepath
|
||||
"--plugin=prettier-plugin-svelte"
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
(prettier-typescript
|
||||
. (npx "prettier" "--stdin-filepath" filepath "--parser=typescript"
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
. ("apheleia-npx" "prettier" "--parser=typescript"
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
(prettier-yaml
|
||||
. (npx "prettier" "--stdin-filepath" filepath "--parser=yaml"
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
(purs-tidy . (npx "purs-tidy" "format"))
|
||||
. ("apheleia-npx" "prettier" "--parser=yaml"
|
||||
(apheleia-formatters-js-indent "--use-tabs" "--tab-width")))
|
||||
(purs-tidy . ("apheleia-npx" "purs-tidy" "format"))
|
||||
(rubocop . ("rubocop" "--stdin" filepath "--auto-correct"
|
||||
"--stderr" "--format" "quiet" "--fail-level" "fatal"))
|
||||
(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
|
||||
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
|
||||
symbols mentioned above will be evaluated when the formatter is
|
||||
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
|
||||
(error "Formatter uses `file' but process will run on different \
|
||||
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
|
||||
;; file, so `buffer-modified-p' should be ignored (it always
|
||||
;; returns non-nil).
|
||||
|
|
|
@ -7,6 +7,7 @@ find=(
|
|||
find .
|
||||
-name .git -prune -o
|
||||
-name .log -prune -o
|
||||
-path ./scripts/pnp-bin.js -prune -o
|
||||
-path ./test/formatters -prune -o
|
||||
-name "*.elc" -o
|
||||
-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
|
||||
"^scripts/formatters/\\([^/]+\\)$" changed-file)
|
||||
(let ((script (match-string 1 changed-file)))
|
||||
(map-keys
|
||||
(map-filter
|
||||
(lambda (fmt def)
|
||||
(member script def))
|
||||
apheleia-formatters)))))))
|
||||
(mapcar #'symbol-name
|
||||
(map-keys
|
||||
(map-filter
|
||||
(lambda (fmt def)
|
||||
(and (listp def) (member script def)))
|
||||
apheleia-formatters))))))))
|
||||
|
||||
(defun apheleia-ft--get-formatters-for-pull-request ()
|
||||
"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."
|
||||
(princ (concat
|
||||
(string-join
|
||||
(apheleia-ft--get-formatters-for-pull-request) ",")
|
||||
(cl-remove-duplicates
|
||||
(apheleia-ft--get-formatters-for-pull-request)
|
||||
:test 'string=)
|
||||
",")
|
||||
"\n")))
|
||||
|
||||
(defun apheleia-ft--read-file (filename)
|
||||
|
|
|
@ -6,14 +6,10 @@ export DEBIAN_FRONTEND=noninteractive
|
|||
apt-get update
|
||||
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 -
|
||||
|
||||
ubuntu_name="$(lsb_release -cs)"
|
||||
node_repo="$(curl -fsSL https://deb.nodesource.com/setup_current.x | grep NODEREPO= | grep -Eo 'node_[0-9]+\.x' | head -n1)"
|
||||
|
||||
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
|
||||
mkdir -p /etc/apt/keyrings
|
||||
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
|
||||
NODE_MAJOR=20
|
||||
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
|
||||
|
||||
add-apt-repository -n ppa:longsleep/golang-backports
|
||||
|
||||
|
@ -30,9 +26,6 @@ nodejs
|
|||
sudo
|
||||
unzip
|
||||
wget
|
||||
sudo
|
||||
unzip
|
||||
wget
|
||||
|
||||
"
|
||||
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
# Need ruby for gem, need gcc and ruby headers for native gem deps
|
||||
apt-get install -y ruby ruby-dev gcc
|
||||
|
||||
# Install the plugin
|
||||
npm install -g prettier @prettier/plugin-ruby
|
||||
|
||||
# Have to install from source because release not tagged yet
|
||||
# https://github.com/ruby-syntax-tree/syntax_tree-rbs/pull/34
|
||||
# https://stackoverflow.com/a/11767563
|
||||
gem install specific_install
|
||||
gem specific_install -l https://github.com/ruby-syntax-tree/syntax_tree-rbs.git
|
||||
# Apparently rubygems does not know how to do dependency resolution.
|
||||
# So we have to manually install an old version of this dependency to
|
||||
# avoid the latest version getting installed and then failing to build
|
||||
# because it does not support ruby 2.7 which is what we have.
|
||||
gem install rbs -v 3.1.3
|
||||
|
||||
# These are required dependencies documented at
|
||||
# https://www.npmjs.com/package/@prettier/plugin-ruby
|
||||
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