diff --git a/README.md b/README.md index fb7426f..a4a3d27 100644 --- a/README.md +++ b/README.md @@ -1,102 +1,115 @@ A minimalist command runner for npm packages, with a focus on developer ergonomics. ``` - ______ __ __ ______ __ __ -/\ ___\ /\ `. /\ \ /\ ___\ /\_\_\_\ -\ \ ___\ \ \ `. \ \ \ \ ___\ \/_/\_\/_ - \ \_____\ \ \_\ `.\_\ \ \_____\ /\_\/\_\ - \/_____/ \/_/ \/_/ \/_____/ \/_/\/_/ n(pm) execute + __ __ __ __ +/\ `./\ \ /\_\_\_\ +\ \ .`.` \ \/_/\_\/_ + \ \_\ `._\ /\_\/\_\ + \/_/ \/_/ \/_/\/_/ npm execute ``` -[![shellcheck](https://github.com/evnp/enex/workflows/shellcheck/badge.svg)](https://github.com/evnp/enex/actions) -[![latest release](https://img.shields.io/github/release/evnp/enex.svg)](https://github.com/evnp/enex/releases/latest) -[![npm package](https://img.shields.io/npm/v/enex.svg)](https://www.npmjs.com/package/enex) -[![license](https://img.shields.io/github/license/evnp/enex.svg?color=blue)](https://github.com/evnp/enex/blob/master/LICENSE.md) +[![shellcheck](https://github.com/evnp/nx/workflows/shellcheck/badge.svg)](https://github.com/evnp/nx/actions) +[![latest release](https://img.shields.io/github/release/evnp/nx.svg)](https://github.com/evnp/nx/releases/latest) +[![npm package](https://img.shields.io/npm/v/nx.svg)](https://www.npmjs.com/package/nx) +[![license](https://img.shields.io/github/license/evnp/nx.svg?color=blue)](https://github.com/evnp/nx/blob/master/LICENSE.md) -`enex` lets you interact with any NPM package — that is, anything with a `package.json` — in as few keystrokes as you want (or as possible!). It's eminently configurable, but with a default setup of `source $HOME/enex/enex.sh` in your dotfile of choice, it will add these aliases to any shell: +`nx` lets you interact with any NPM package (anything with a `package.json`) in as few keystrokes as as possible.
+With a default setup of `source $HOME/nx/nx.sh` in your dotfile of choice, it will add these aliases to any shell: ```sh -n -> npm OR npm run # enex intelligently adds `run` - # only when necessary, but you -ns -> npm run start # may use it if you prefer +n -> # show list of currently configured nx aliases +n -> npm OR npm run # nx intelligently adds `run` + # only when necessary, but you +ns -> npm run start # may use it if you prefer nb -> npm run build nf -> npm run format +nl -> npm run lint +nk -> npm run link nt -> npm run test -ntw -> npm run test -- --watch - -ni -> npm install -nu -> npm uninstall -nis -> npm install --save -nus -> npm uninstall --save -nid -> npm install --save-dev -nud -> npm uninstall --save-dev +nt w -> npm run test --watch +# `w` may be added to any nx command to produce `--watch` + +ni -> npm install +nu -> npm uninstall +nis -> npm install --save +nus -> npm uninstall --save +nid -> npm install --save-dev +nud -> npm uninstall --save-dev +nig -> npm install --global +nug -> npm uninstall --glboal ``` -`enex` is only 50 lines of code (with comments!) — if you're interested in knowing exactly what will be running on your system, peruse it [here](https://github.com/evnp/enex/blob/main/enex.sh). Any project that touts minimalism should strive to be understood completely within a few minutes; this is, and will remain, a goal of `enex`. +Of these aliases, only `nl` exists as a pre-existing Bash command (), used for prefixing file lines with line numbers. If you'd like to disable this particular `nx` alias so that the built-in `nl` is not overridden, use this configuration in your shell rc file: + +```bash +export NX_ALIASES=install,uninstall,start,test,build,format,k/link,help; source "$HOME/nx/nx.sh" +``` + +`nx` is only 50 lines of code (with comments!) — if you're interested in knowing exactly what will be running on your system, peruse it [here](https://github.com/evnp/nx/blob/main/nx.sh). Any project that touts minimalism should strive to be understood completely within a few minutes; this is, and will remain, a goal of `nx`. Setup ----- ```sh -npm install -g enex -which enex -> /some/path/to/node_modules/.bin/enex.sh +npm install -g nx +which nx +> /some/path/to/node_modules/.bin/nx.sh # add to your .bashrc / .zshrc / etc. -> -source "/some/path/to/node_modules/.bin/enex.sh" +source "/some/path/to/node_modules/.bin/nx.sh" ``` Or if you prefer, install by checking out the repository manually: ```sh -git clone https://github.com/evnp/enex.git +git clone https://github.com/evnp/nx.git # add to your .bashrc / .zshrc / etc. -> -source "$HOME/enex/enex.sh" +source "$HOME/nx/nx.sh" # or if you didn't check the repository in $HOME directory: -source "/your/path/to/repository/enex/enex.sh" +source "/your/path/to/repository/nx/nx.sh" ``` -Open a new shell instance and `enex` will have initialized these aliases: +Open a new shell instance and `nx` will have initialized these aliases: ```sh -alias n="enex" # -> contextually equivalent to `npm ...` or `npm run ...` - -alias ns="enex start" # -> npm start -alias nt="enex test" # -> npm test; also ntw -> npm run test -- --watch -alias nb="enex build" # -> npm run build -alias nf="enex format" # -> npm run format -alias ni="enex install" # -> npm install -alias nu="enex uninstall" # -> npm uninstall +alias n="nx" # -> contextually equivalent to `npm ...` or `npm run ...` + +alias ns="nx start" # -> npm start +alias nt="nx test" # -> npm test; also ntw -> npm run test -- --watch +alias nb="nx build" # -> npm run build +alias nf="nx format" # -> npm run format +alias ni="nx install" # -> npm install +alias nu="nx uninstall" # -> npm uninstall # also nis, nid, nus, nud for install/uninstall --save/--save-dev combinations, see above ``` -If you'd like to opt out of these default aliases or customize them, use env vars when initializing `enex` to configure: +If you'd like to opt out of these default aliases or customize them, use env vars when initializing `nx` to configure: ```sh -# to opt out of `n` alias and simply use the full command `enex`: -export ENEX_COMMAND=0; source "$HOME/enex/enex.sh" - -# to opt out of enex aliasing altogether: -export ENEX_COMMAND=0; export ENEX_ALIASES=0; source "$HOME/enex/enex.sh" - -# to use the custom command `myencmd` to invoke enex instead of `n`: -export ENEX_COMMAND=myencmd; source "$HOME/enex/enex.sh" -> alias myencmd="enex" - -# to define your own custom set of enex aliases: -export ENEX_ALIASES=build,push,deploy; source "$HOME/enex/enex.sh" -> alias n="enex" -> alias nb="enex build" -> alias np="enex push" -> alias nd="enex deploy" +# to opt out of `n` alias and simply use the full command `nx`: +export NX_COMMAND=0; source "$HOME/nx/nx.sh" + +# to opt out of nx aliasing altogether: +export NX_COMMAND=0; export NX_ALIASES=0; source "$HOME/nx/nx.sh" + +# to use the custom command `myencmd` to invoke nx instead of `n`: +export NX_COMMAND=myencmd; source "$HOME/nx/nx.sh" +> alias myencmd="nx" + +# to define your own custom set of nx aliases: +export NX_ALIASES=build,push,deploy; source "$HOME/nx/nx.sh" +> alias n="nx" +> alias nb="nx build" +> alias np="nx push" +> alias nd="nx deploy" # note: this overrides the set of default aliases entirely, so you # will need to redefine them explicitly if some are desired # to define an alias whose shortcut does not match its first letter: -export ENEX_ALIASES=build,x/specialthing,deploy; source "$HOME/enex/enex.sh" -> alias n="enex" -> alias nb="enex build" -> alias nx="enex specialthing" -> alias nd="enex deploy" +export NX_ALIASES=build,x/specialthing,deploy; source "$HOME/nx/nx.sh" +> alias n="nx" +> alias nb="nx build" +> alias nx="nx specialthing" +> alias nd="nx deploy" ``` -By default, if enex does not detect a `package.json` file within the directory it is being invoked from, it will search for one within directories up to 2 levels below, and an arbitary number of levels above, exiting immediately if it reaches your home directory. This allows you to run enex commands from anywhere within a project with this very common directory structure, or similar project structures: +By default, if nx does not detect a `package.json` file within the directory it is being invoked from, it will search for one within directories up to 2 levels below, and an arbitary number of levels above, exiting immediately if it reaches your home directory. This allows you to run nx commands from anywhere within a project with this very common directory structure, or similar project structures: ```sh $HOME/ └─project/ @@ -106,26 +119,26 @@ $HOME/ ├─src/ └─dir/ ``` -Normally, you'd need to first navigate to the `frontend/` before invoking any `npm` command; enex handles this step invisibly for you in a subshell, so that you remain in the same directory you started in after the operation is complete. +Normally, you'd need to first navigate to the `frontend/` before invoking any `npm` command; nx handles this step invisibly for you in a subshell, so that you remain in the same directory you started in after the operation is complete. -If for any reason you prefer to skip this "auto-find" step, add the following env var to your enex configuration: +If for any reason you prefer to skip this "auto-find" step, add the following env var to your nx configuration: ```sh -export ENEX_FIND=0; source "$HOME/enex/enex.sh" +export NX_FIND=0; source "$HOME/nx/nx.sh" ``` -If you use [nvm](https://github.com/nvm-sh/nvm), enex can be configured to call `nvm use` before each command invocation to ensure NodeJS and NPM versions matching the current directory's `.nvmrc` are used. To enable this behavior, add the following env var to your enex configuration: +If you use [nvm](https://github.com/nvm-sh/nvm), nx can be configured to call `nvm use` before each command invocation to ensure NodeJS and NPM versions matching the current directory's `.nvmrc` are used. To enable this behavior, add the following env var to your nx configuration: ```sh -export ENEX_NVM=1; source "$HOME/enex/enex.sh" +export NX_NVM=1; source "$HOME/nx/nx.sh" ``` -If you'd like enex to await confirmation of current node+npm versions before executing commands, add the following env var to your enex configuration: +If you'd like nx to await confirmation of current node+npm versions before executing commands, add the following env var to your nx configuration: ```sh -export ENEX_CONFIRM=1; source "$HOME/enex/enex.sh" +export NX_CONFIRM=1; source "$HOME/nx/nx.sh" ``` -While sorting out configuration, it may be useful to have enex output the complete set of aliases that are generated when a new shell session begins. To do so, add: +While sorting out configuration, it may be useful to have nx output the complete set of aliases that are generated when a new shell session begins. To do so, add: ```sh -export ENEX_VERBOSE=1; source "$HOME/enex/enex.sh" +export NX_VERBOSE=1; source "$HOME/nx/nx.sh" ``` That's it! diff --git a/enex.sh b/enex.sh deleted file mode 100755 index 1f57292..0000000 --- a/enex.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env bash -# :: enex 0.0.8 :: -# shellcheck disable=SC2139 # shellcheck.net/wiki/SC2139 # allow parameter expansion within alias strings # -function enex() ( local pkg=""; local run=""; - # :: print current aliases and exit when "n" is run with no arguments :: - [[ -z "$1" ]] && alias | grep 'enex' | grep -v "='enex'" | sed 's/^alias //' | sed 's/=/ · /' | sed "s/enex/npm run/" | sed -E "s/run ($( npm -h | awk '/access/,/whoami/' | sed 's/help,//' | xargs | sed 's/, /|/g' ))/\1/" | tr -d "'" && exit 0 - [[ "$( npm -h | awk '/access/,/whoami/' | sed 's/help,//' )," == *" $1,"* ]] || run=" run" - # :: find closest package.json (file path containing fewest "/" characters) :: export ENEX_FIND=0; source "$HOME/enex/enex.sh" (to disable) :: - while [[ ! "${ENEX_FIND}" =~ ^(0|false|FALSE)$ && ! -f "./package.json" ]] ; do - [[ "$( pwd )" == "$HOME" ]] && echo "No package.json found." && exit 1 - pkg="$( find . -name package.json -maxdepth 3 | grep -v node_modules | awk -F/ '{print NF,$0}' | sort -n | cut -d' ' -f2- | head -1 )" - cd "$( [[ -n "${pkg}" ]] && dirname "${pkg}" || echo '..' )" || exit 1 - done - # :: call "nvm use" automatically before running commands :: export ENEX_NVM=1; source "$HOME/enex/enex.sh" (to enable) :: - [[ "${ENEX_NVM}" =~ ^(1|true|TRUE)$ ]] && nvm use &>/dev/null - # :: await confirmation of current node+npm versions before executing command :: export ENEX_CONFIRM=1; source "$HOME/enex/enex.sh" (to enable) :: - if [[ "${ENEX_CONFIRM}" =~ ^(1|true|TRUE)$ ]]; then - echo -e npm"${run}" "$1" "${2:+--}" "${@:2}" "\nPress ENTER to run · CTRL+C to cancel · node $( node -v ) · npm $( npm -v )" - head -n 1 >/dev/null # wait for ENTER keypress, or exit on CTRL+C - fi - npm"${run}" "$1" "${2:+--}" "${@:2}" # :: execute constructed npm command :: -) -# :: default command alias :: n -> enex :: eg. n install -> npm install, n build -> npm run build, etc. -# :: export ENEX_COMMAND=0; source "$HOME/enex/enex.sh" (to disable) :: -if ! [[ "${ENEX_COMMAND}" =~ ^(0|false|FALSE)$ ]]; then - [[ -n "${ENEX_VERBOSE}" ]] && echo "alias ${ENEX_COMMAND:-n}=\"enex\"" - alias "${ENEX_COMMAND:-n}"="enex" -fi -# :: default sub-command aliases :: -# nb -> npm run build nt -> npm test nf -> npm run format nl -> npm run lint nh -> npm run help -# ni -> npm install nu -> npm uninstall nis, nid, nus, nud -> npm [un]install --save[-dev] -# ns -> npm start nk -> npm link ntw, nbw, nfw, nlw -> npm run -- --watch -# :: export ENEX_ALIASES=0; source "$HOME/enex/enex.sh" (to disable) :: -if ! [[ "${ENEX_ALIASES}" =~ ^(0|false|FALSE)$ ]]; then - for word in $( tr -cs '[:alnum:]._-/' ' ' <<< "${ENEX_ALIASES:-install,uninstall,start,test,build,format,lint,k/link,help}" ); do - [[ "${ENEX_COMMAND}" =~ ^(0|false|FALSE)$ ]] && ENEX_COMMAND='enex' - [[ -n "${ENEX_VERBOSE}" ]] && echo "alias ${ENEX_COMMAND:-n}${word:0:1}=\"enex ${word#[a-z]/}\"" - alias "${ENEX_COMMAND:-n}${word:0:1}"="enex ${word#[a-z]/}" - if [[ "${word}" =~ ^(un)?install$ ]]; then - [[ -n "${ENEX_VERBOSE}" ]] && echo "alias ${ENEX_COMMAND:-n}${word:0:1}s=\"enex ${word#[a-z]/} --save\"" - [[ -n "${ENEX_VERBOSE}" ]] && echo "alias ${ENEX_COMMAND:-n}${word:0:1}d=\"enex ${word#[a-z]/} --save-dev\"" - alias "${ENEX_COMMAND:-n}${word:0:1}s"="enex ${word#[a-z]/} --save" - alias "${ENEX_COMMAND:-n}${word:0:1}d"="enex ${word#[a-z]/} --save-dev" - elif [[ "${word}" =~ ^(test|build|format|lint)$ ]]; then - [[ -n "${ENEX_VERBOSE}" ]] && echo "alias ${ENEX_COMMAND:-n}${word:0:1}w=\"enex ${word#[a-z]/} --watch\"" - alias "${ENEX_COMMAND:-n}${word:0:1}w"="enex ${word#[a-z]/} --watch" - fi - done -fi diff --git a/nx.sh b/nx.sh new file mode 100755 index 0000000..896bb5b --- /dev/null +++ b/nx.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# : nx 0.0.8 :: +# shellcheck disable=SC2139 # shellcheck.net/wiki/SC2139 # allow parameter expansion within alias strings # +function nx() ( local pkg="" cmd="" npmcmds="" + npmcmds="$( npm -h | awk '/access/,/whoami/' | sed -E 's/ (help|start|test),//g' | xargs | sed 's/, /|/g' )" + # :: print current aliases and exit when "n" is run with no arguments :: + [[ -z "$1" ]] && alias | grep "='nx " | sed 's/^alias //' | sed 's/=/ · /' | sed "s/nx /npm run /" | sed -E "s/run (${npmcmds})/\1/" | tr -d "'" && exit 0 + [[ "${npmcmds}" == *"|$1|"* || "${npmcmds}" == "$1|"* || "${npmcmds}" == *"|$1" ]] && cmd=('npm' "$1") || cmd=('npm' 'run' "$1" "${2:+--}") + [[ "$2" == 'w' ]] && set -- "$1" "--watch" "${@:3}" # :: rewrite 'w' to '--watch' if provided as second arg "" + # :: find closest package.json (file path containing fewest "/" characters) :: export NX_FIND=0; source "$HOME/nx/nx.sh" (to disable) :: + while [[ ! "${NX_FIND}" =~ ^(0|false|FALSE)$ && ! -f "./package.json" ]] && [[ "$2" != '--global' ]]; do + [[ "$( pwd )" == "$HOME" ]] && echo "No package.json found." && exit 1 + pkg="$( find . -name package.json -maxdepth 3 | grep -v node_modules | awk -F/ '{print NF,$0}' | sort -n | cut -d' ' -f2- | head -1 )" + cd "$( [[ -n "${pkg}" ]] && dirname "${pkg}" || echo '..' )" || exit 1 + done + # :: call "nvm use" automatically before running commands :: export NX_NVM=1; source "$HOME/nx/nx.sh" (to enable) :: + [[ "${NX_NVM}" =~ ^(1|true|TRUE)$ ]] && nvm use &>/dev/null + # :: await confirmation of current node+npm versions before executing command :: export NX_CONFIRM=1; source "$HOME/nx/nx.sh" (to enable) :: + if [[ "${NX_CONFIRM}" =~ ^(1|true|TRUE)$ ]]; then + read -rsn1 -p "${cmd[*]} ${*:2} "$'\n'"Press any key to run · CTRL+C to cancel · node $( node -v ) · npm $( npm -v )"$'\n\n' + fi + "${cmd[@]}" "${@:2}" # :: execute constructed npm command :: +) +# :: default command alias :: n -> nx :: eg. n install -> npm install, n build -> npm run build, etc. +# :: export NX_COMMAND=0; source "$HOME/nx/nx.sh" (to disable) :: +if ! [[ "${NX_COMMAND}" =~ ^(0|false|FALSE)$ ]]; then + alias "${NX_COMMAND:-n}"="nx" +fi +# :: default sub-command aliases :: +# nb -> npm run build nt -> npm test nf -> npm run format nl -> npm run lint nh -> npm run help +# ns -> npm start nk -> npm link ni -> npm install nu -> npm uninstall nis, nid, nus, nud -> npm [un]install --save[-dev] +# :: export NX_ALIASES=0; source "$HOME/nx/nx.sh" (to disable) :: +if ! [[ "${NX_ALIASES}" =~ ^(0|false|FALSE)$ ]]; then + for word in $( tr -cs '[:alnum:]._-/' ' ' <<< "${NX_ALIASES:-install,uninstall,start,test,build,format,lint,k/link,help}" ); do + [[ "${NX_COMMAND}" =~ ^(0|false|FALSE)$ ]] && NX_COMMAND='nx' + alias "${NX_COMMAND:-n}${word:0:1}"="nx ${word#[a-z]/}"; [[ -n "${NX_VERBOSE}" ]] && alias "${NX_COMMAND:-n}${word:0:1}" + if [[ "${word}" =~ ^(un)?install$ ]]; then + alias "${NX_COMMAND:-n}${word:0:1}s"="nx ${word#[a-z]/} --save"; [[ -n "${NX_VERBOSE}" ]] && alias "${NX_COMMAND:-n}${word:0:1}s" + alias "${NX_COMMAND:-n}${word:0:1}d"="nx ${word#[a-z]/} --save-dev"; [[ -n "${NX_VERBOSE}" ]] && alias "${NX_COMMAND:-n}${word:0:1}d" + alias "${NX_COMMAND:-n}${word:0:1}g"="nx ${word#[a-z]/} --global"; [[ -n "${NX_VERBOSE}" ]] && alias "${NX_COMMAND:-n}${word:0:1}g" + fi + done +fi diff --git a/package-lock.json b/package-lock.json index f7a3c32..83b46c6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { - "name": "enex", - "version": "0.0.8", + "name": "nx.sh", + "version": "1.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "enex", - "version": "0.0.8", + "name": "nx.sh", + "version": "1.0.0", "license": "MIT", "bin": { - "enex": "enex" + "nx": "nx" }, "devDependencies": { "shellcheck": "1.1.0" diff --git a/package.json b/package.json index c4f5f26..1adbc86 100644 --- a/package.json +++ b/package.json @@ -1,22 +1,22 @@ { - "name": "enex", - "version": "0.0.8", + "name": "nx.sh", + "version": "1.0.0", "description": "A minimalist command runner for npm packages, with a focus on developer ergonomics.", - "main": "enex", + "main": "nx.sh", "files": [ - "enex.sh" + "nx.sh" ], "bin": { - "enex": "enex" + "nx": "nx" }, "scripts": { - "lint": "shellcheck enex.sh" + "lint": "shellcheck nx.sh" }, "repository": { "type": "git", - "url": "https://github.com/evnp/enex.git" + "url": "https://github.com/evnp/nx.git" }, - "homepage": "https://github.com/evnp/enex", + "homepage": "https://nx.evnp.sh", "author": "Evan Purcer (http://evnp.ca)", "license": "MIT", "devDependencies": {