If your Nova extension relies on an NPM package's executable, it's a good idea to provide a fallback or default installation.
Users of your extension might already have the package installed globally or as a dependency of a given project. If so, your extension can prefer those locations automatically. However, if the user doesn't have the package installed, providing a fallback instance is a helpful way of letting them get started without having to install tools on the command line.
nova-npm-executable provides a helper class to make offering this functionality easier:
- Install the fallback package inside the Nova extension bundle
- Instantiate a
Process
instance constructed with options that are ideal for running the executable in the user's environment
npm install --save nova-npm-executable
See Using NPM Packages in Nova Extensions for information on structuring your project and using a module bundler to include the nova-npm-executable API in your extension.
In addition to your project's top-level package.json
, your extension bundle should also include its own package.json
file. Use this to define the package or packages whose CLI executables you wish to install as a fallback.
For example, if you are building a JSONLint extension that relies on the jsonlint
executable:
cd nova-jsonlint/JSONLint.novaextension
npm install --save jsonlint
⚠️ NPMExecutable.install
will only install packages defined independencies
, not fromdevDependencies
.
const {NPMExecutable} = require( "nova-npm-executable" );
Check whether the fallback dependency has been installed inside the extension bundle, and install it if not:
class JSONLint
{
constructor()
{
this.jsonlint = new NPMDependency( "jsonlint" );
if( !this.jsonlint.isInstalled )
{
this.jsonlint.install()
.catch( error =>
{
console.error( error );
});
}
{string} binName
- The name of the executable found innode_modules/.bin
Example:
let jsonlint = new NPMExecutable("jsonlint");
Install NPM dependencies defined in the package.json
file located inside your extension bundle.
See Defining Extension Dependencies for more information.
↩️ Returns Promise
, which resolves or rejects depending on the success of installation
Whether the package has already been installed inside the extension bundle.
↩️ Returns boolean
{Object} options
{[string]} [options.args]
{string} [options.cwd]
{Object} [options.env]
{string|boolean} [options.shell]
{[string]} [options.stdio]
Helper function for instantiating Process
object with options needed to run the module executable using npx
.
In addition to constructing Process
arguments as ["npx","<binName>"]
, process()
automatically augments the user's $PATH
to create a preferential cascade of possible executable locations:
- Current Workspace
- Global Installation
- Extension Bundle
💡 If the user is working in a project, for example, which defines a specific version of your extension's executable, that installation will be preferred, followed by any version they may have installed globally via
npm install -g
, followed finally by your extension's fallback.
Example:
/**
* Write a string to the JSONLint process's STDIN. Equivalent to running
* `echo <string> | npx jsonlint -c` on the command line.
*
* @param {String} string
* @param {String} fileURI
* @return {Promise}
*/
async lint( string, fileURI )
{
try
{
let process = await this.jsonlint.process( { args: ["-c"] } );
let output = "";
process.onStdout( line => output += line.trimRight() );
process.onStderr( line => output += line.trimRight() );
process.onDidExit( status =>
{
let results = status === 0 ? [] : this.parseOutput( output );
this.report( results, fileURI );
});
process.start();
let writer = process.stdin.getWriter();
writer.write( string );
writer.close();
↩️ Returns Promise
, which resolves with an pre-instantiated Process
object.