Skip to content

Latest commit

 

History

History
167 lines (135 loc) · 6.13 KB

README.md

File metadata and controls

167 lines (135 loc) · 6.13 KB

The package is in early stage, some changes (in API) may be made until version 1.0.0.!

NodeJS Script – Easy cross-platform scripting

This package serves as an alternative to google/zx for example. The key difference is to provide Unix shell commands in a cross-platform compatible way and usable inside JavaScript. This is primarily achieved by using shelljs/shelljs library.

You can compare the final script code to zx example:

#!/usr/bin/env nodejsscript

echo(s.grep("name", "package.json"));

s.run("git branch --show-current")
.xargs(s.run, "dep deploy --branch={}");

s.run("sleep 1; echo 1");
s.run("sleep 2; echo 2");
s.run("sleep 3; echo 3");

const name= "foo bar";
s.mkdir($.xdg.temp(name));

…also see examples. You can also use nodejsscript -e/nodejsscript -p in shell:

curl https://api.spacexdata.com/v4/launches/latest | nodejsscript -p 'Object.entries($.nojq).filter(([_,v])=> Array.isArray(v))'

…see examples again.

Quick links/info

Installation

  1. tested/used on NodeJS: node@v16.13.0 and node@v17.9.1 ⇒ for installation follow nvm-sh/nvm: Node Version Manager1
  2. npm install nodejsscript --location=global … alternatively install locally: npm install nodejsscript2

Goods

s #shelljs · $ ($.api() #sade, $.read(), $.xdg, …) · echo() #css-in-console · fetch() #node-fetch · pipe() · cyclicLoop()

Documentation

Write your scripts in a file with an .mjs extension in order to use await at the top level. If you prefer the .js extension, wrap your scripts in something like (async function () {...})().

Add the following shebang to the beginning of your nodejsscript scripts:

#!/usr/bin/env nodejsscript

Now you will be able to run your script like so:

chmod +x ./script.mjs
./script.mjs

Or via the nodejsscript executable:

nodejsscript ./script.mjs
Alternatively when installed locally
#!/usr/bin/env -S npx nodejsscript
npx nodejsscript ./script.mjs

All function (shelljs, fetch, …) are registered as global namespaces/functions: … The entry point for documentation of all Public items is in the docs/.

Note that there are also built-in 'node:*' modules:

import { setTimeout } from "node:timers/promises";
import { join, resolve } from "node:path";

//.current file url
import.meta.url;
//.url to path
import { fileURLToPath } from "node:url";
const file_path= fileURLToPath(import.meta.url);
// url is supported! (see relative reading)
s.cat(new URL('relative_file', import.meta.url));

//.crypto utils
import { randomUUID } from "node:crypto";

// …

…and more, see Node.js v17.9.1 Documentation.

Security guidelines

run()/runA() command injection: this advice applies to child_process.exec() just as much as it applies to s.run(). It is potentially risky to run commands passed for example by user input:

function curlUnsafe(urlToDownload){ return s.run('curl ' + urlToDownload); }
curlUnsafe('https://some/url ; rm -rf $HOME'); //=> curl https://some/url ; rm -rf $HOME

Therefore, nodejsscripts s.run() provide way to escapes untrusted parameters:

function curl(url){ return s.run("curl ::url::", { url }); }
curl('https://some/url ; rm -rf $HOME'); //=> curl 'https://some/url ; rm -rf $HOME'

…you can also use as template function (but without command specific options):

function curl(url){ return s.run`curl ${url}`; }
curl('https://some/url ; rm -rf $HOME'); //=> curl 'https://some/url ; rm -rf $HOME'

Note: The 'xargs()' by default also escapes piped strings.

…Note 2: s.run(…cmd, …vars) is also helpul for escaping parameters passed as variables (e.g. arrays).

…Note 3: ShellJS also provides s.exec, but s.run should be prefered way to execute commands.

Glob injection (all commands): Most ShellJS commands support glob expansion, expanding wildcards such as * to match files. While this is very powerful, dependent modules should exercise caution. Unsanitized user input may contain wildcard characters. Consider for example that the *.txt is valid file name, however the s.rm("*.txt") by default (using the globbing) delete all txt files. Keep in mind that you can always turn off this for next command by using:

s.$("-g").rm("*.txt");

Helper(s) for developing

You can create jsconfig.json to help your editor provide proper suggestions. As editor you can use VSCode or Vim with for example neoclide/coc.nvim. NodeJSScript provides nodejsscript --global-jsconfig add script_file to help generate jsconfig.json.

Migration from zx

The runA is almost identical to $:

await $`cat package.json | grep name`;
await s.runA`cat package.json | grep name`;

…but for cp/mv/… you need to rewrite code to s.*:

echo(s.cat("package.json").grep("name"));
// or
echo(s.grep("name", "package.json"));

API changes 0.80.9

  1. cli renamed to $
  2. style (ansi-colors) removed in favour of using “CSS” in echo
  3. exit removed in favour of $.exit

Contribute

Footnotes

  1. Alternatively curl -sL install-node.vercel.app/16.13.0 | bash

  2. Or: npm install https://github.com/jaandrle/nodejsscript --global