Skip to content

Plugin API Draft [ NO LONGER IN USE ]

Nate Fischer edited this page May 15, 2018 · 1 revision

Note: please see the final spec for plugins

Plugins

ShellJS v1.0.0 will contain a plugin API. This is the current working draft of that API.

/**
 * We're going to create shelljs-plugin-foo.
 *
 * shelljs-plugin-foo will expose two callable methods:
 * - shell.foo(['-q',] str): return a ShellString: "foo: <str>!". Don't append a '!' if -q is passed.
 * - shell.foo.bar.baz(num): Print: "foo bar baz x<num>". Return <num> times 3.
 *
 * We'll also make it so that you *cannot* call shell.foo.bar()
 */

// node_modules/shelljs-plugin-foo/index.js (plugin implementation)

// Notice how we don't require shelljs directly (it's a peerDependency)
var plugin = require('shelljs/plugin');
export default function (shell) {
  // First, let's implement our commands as standard JavaScript functions
  function foo (opts, str) {
    return 'foo: ' + str + (opts.quiet ? '' : '!');
  };
  function fooBarBaz (num) {
     shell.echo('foo bar baz x' + num);
     return num * 3; // return a number instead of a string, for example
  };

  // Now we can use `plugin.register()` to add these as ShellJS commands
  const fooTarget = plugin.register(
                            shell, // Target to put the command on (this allows shell.foo())
                            'foo', // Name of command
                            foo, // The implementation of the command
                            {
                              cmdOptions: { // The supported options for the command
                                q: 'quiet',
                              },
                            }
                          );
  const fooBarTarget = plugin.register(fooTarget, 'bar'); // Non-callable command.
  const fooBarBazTarget = plugin.register(
                            fooBarTarget, // Target to put the command on.
                            'baz', // Name of command
                            fooBarBaz, // The implementation of the command
                            {
                              retShellString: false,  // Don't ShellString-ify the return value.
                            } // this will not automatically parse options (.cmdOptions is missing)
                          );
};

// Now, let's use the plugin we wrote!
var shell = require('shelljs'); // No ideas yet for global mode.

shell.use(require('shelljs-plugin-foo'));

shell.foo('Plugins'); // 'foo: Plugins!'
shell.foo('-q', 'testing, 1, 2, 3.'); // 'foo: testing, 1, 2, 3.'
shell.foo.bar.baz(10); // Logs: 'foo bar baz x10', Returns 30.

shell.foo.bar(); // This would be an error, since this sub-command is un-callable

This also makes it easy to extend commands:

// Suppose there's a git() plugin already, but we want to extend it for the `git lfs` command:

var plugin = require('shelljs/plugin');
export default function (shell) {
  shell.use(require('shelljs-plugin-git')); // Our dependency. It's smart enough to only `use` it once.
  plugin.register(shell.git, 'lfs', gitLfs, ...);
  // ...
};

// Now other people can use the git-lfs plugin in other projects:
shell.use(require('shelljs-plugin-git-lfs'));

shell.git.lfs(...);

plugin.register()

plugin.register(target, name, impl, wrapOptions)
argument meaning
target The object onto which to place the command
name A string that will be the exposed name of the command. ex. 'cat', 'git', 'printf'
impl A function that serves as the implementation of the command
wrapOptions An object specifying various options for wrapping the command. See below for details

wrapOptions

option default value meaning
allowGlobbing false If true, perform wildcard expanding (based on values for globStart and globEnd. Otherwise, do not perform any wildcard expansion.
globStart 1 The first argument for which to begin wildcard expansion. ex. cat() has globStart=1 (don't expand the options, but do expand the filenames) while grep() has globStart=2 so that it doesn't expand wildcards in the regex argument either
globEnd end of arguments (not implemented) The last argument for which to begin wildcard expansion. If negative, it counts backward from the last argument
canReceivePipe false Set this to true if your command can appear on the right-hand side of a pipe expression. ex. shell.grep('a', 'file.txt').tr('a', 'b') (tr can be on the right-hand-side)
cmdOptions null An object serving as a dictionary describing available options. ex. {n: 'noOverwrite'} means this only takes the -n option. If this is any falsy value, then options will not be parsed