cycle-plugins

0.1.1 • Public • Published

cycle-plugins

Provides observable-based plugins to cycle.js applications.

Installation

npm i cycle-plugins --save

Scripts

NOTE: Make sure you've installed all dependencies using npm install first.

To generate documentation: npm run doc. This will create documentation in the build/docs folder.

To run unit tests: npm test

API

Plugins

Static class for registering and consuming Plugin instances dynamically.

Kind: global namespace

plugins.register(plugins)

Makes one or more Plugins available to consumers.

Kind: instance method of Plugins

Param Type Description
plugins Plugin | Array.<Plugin> One or more Plugin instances to make available to consumers.

Example

Plugins.register(new Plugin({
  name: 'console',
  log: function log(msg) { ... }
}));

Plugins.get({name: 'console'}).first()
  .tap(console => console.log('hello'));

plugins.unregister(plugins)

Makes a Plugin unavailable to consumers.

Kind: instance method of Plugins

Param Type Description
plugins Plugin | Array.<Plugin> One or more Plugin instances to unregister.

Example

var plugin = new Plugin({name: 'temp'});
Plugins.register(plugin); // available to consumers
Plugins.unregister(plugin); // unavailable to consumers

plugins.get(criteria)

Returns an Observable populated with an array of Plugin instances matching the specified criteria. The array contains a utility method called toDAG that will return a DAG instance you can use to iterate safely over the returned Plugin instances in a way that respects the index and after properties of each Plugin.

Kind: instance method of Plugins
Throws:

  • Error Invalid criteria was specified.
Param Type Description
criteria Object A map of criteria to apply against each registered Plugin. Only Plugin instances matching the specified criteria will be included in the resulting Observable.

Example

// retrieve a single Plugin by name
var single$ = Plugins.get({name: 'my-one-plugin'}).first();

Example

// retrieve all registered Plugin instances
var allPlugins$ = Plugins.get(); // or Plugins.get({})

Example

// retrieve all Plugin instances targeting a specific type
var targeted$ = Plugins.get({targetType: MyClass});

Example

// retrieve Plugin instances matching a specific filter;
// the Plugin would need 'my-criteria' in its `filter.any`
// string array and NOT in its `filter.none` string array.
var filtered$ = Plugins.get({filter: 'my-criteria'});

Example

// iterating through Plugins concurrently and in a
// dependency-safe order:
let savePlugins$ = Plugins.get({
  targetType: MyClass, filter: 'save'
});

function save() {
  return savePlugins$.map(plugins =>
    new Observable(observer =>
      plugins.toDAG().forEach(
        (plugin, next) => plugin.doSomething(), next(),
        (err) => err ? observer.error(err) : observer.next()
      );
    ));
}

Plugin

Kind: global class
Inherits: Broker
Properties

Name Type Default Description
name String The name of this plugin.
index Number 0 Provides a way to order multiple Plugins whenever a sequence is requested.
after Array.<String> [] Provides a way to order multiple Plugins based on dependencies. Ensures that this Plugin will be sequenced after the specified Plugin names. If you prepend a name with ?, it will be treated as an optional dependency.
enabled Boolean true Some consumers may use this property to determine which Plugins should be consumed or which can be skipped during iteration.
targetType function Object Used in conjunction with Plugins.get to ensure both Plugin creators and Plugin consumers agree on who can consume this Plugin instance.
filter Filter {any:[], none:[]} A way to restrict the list of Plugins retrieved by Plugins.get at runtime.

new Plugin(props)

An extensible object.

Param Type Description
props Object A map of property names and values to apply to the Plugin instance. The only required property is name.

Example

import {extend, matches} from 'lodash';

const COMMAND_PROPS = { ... };

class Command extends Plugin
  constructor(props) {
    super(extend({}, COMMAND_PROPS, props));
    Plugins.register(this);
  }
  execute() {}
  undo() {}
}

class RecordCommand extends Command {
  constructor(props) {
    super({
      targetType: Record,
      enabled: User.hasPrivilege(props.name)
    });
  }
}

class SaveRecord extends RecordCommand
  constructor() {
    super({name: 'save-record');
  }
  execute() { ... }
  undo() { ... }
}

class DeleteRecord extends RecordCommand
  constructor() {
    super({name: 'delete-record');
  }
  execute() { ... }
  undo() { ... }
}

class Record extends Broker {
  constructor() {
    this.commands$ = Plugins.get({
      baseType: RecordCommand,
      targetType: Record,
      enabled: true
    });
  }

  save() {
    return this.commands$
      .filter(matches({name: 'save-record'}))
      .map(command => command.execute(this))
      .tap(() => this.emit('record-saved'))
      .toPromise();
  }

}

Plugin.Events : Object

Events specific to Plugins.

Kind: static property of Plugin
Properties

Name Type Description
PLUGIN_CHANGED String A property on the plugin has changed. Emit this event when you wish for any search criteria passed to Plugins.get to be re-evaluated, with observers notified of any changes.

DAG (Directed Acyclic Graph)

Kind: global class

new DAG(plugins)

Provides a dependency-safe way to iterate through plugins.

Throws:

  • Error If a dependent Plugin is not optional and not in the set of Plugins provided to the constructor, an error will be thrown. You can mark a dependency as optional by prepending it with a question mark. See the documentation for Plugin for more information.
Param Type Description
plugins Plugin | Array.<Plugin> One or more Plugin instances the DAG should manage.

Example

var dag = new DAG(pluginA, pluginB, pluginC);
dag.forEach(function iterate(plugin, next) {
  // do something with plugin
  next(); // invoke this callback with the next plugin
  // if you wish to stop iteration immediately, invoke
  // next with an argument: next(0) or next('stop') or
  // next(new Error()) -- the argument will be passed
  // to your success handler function
}, function finished(err) {
  if (err) {
    console.log('An error occurred:', err);
  }
});

daG.toArray() ⇒ Array.<Plugin>

Converts the DAG into a dependency-safe sequence of Plugin instances.

Kind: instance method of DAG
Returns: Array.<Plugin> - An array of Plugin instances in dependency-safe order.
Example

var dag = new DAG(pluginA, pluginB, pluginC);
var names = dag.toArray().map(function(plugin) {
  return plugin.name;
});
log(names);

daG.forEach(callback, [finish], [concurrency])

Iterates through the DAG in dependency-safe order using the specified callback function and concurrency settings.

Kind: instance method of DAG
Throws:

  • Error Parameter callback must be a function.
  • Error Parameter concurrency must be a positive integer.
Param Type Default Description
callback function A method that will be invoked for each Plugin instance. Arguments will be: - {Plugin} plugin - the current plugin - {Function} next - method to invoke to continue iteration - {Number} percent - a number between 0 and 100 indicating how much of the DAG has been processed
[finish] function An optional method to invoke when the DAG has been completely processed. If an error has occurred or the iteration ended early, the only argument will be the exit reason.
[concurrency] Number 5 How many Plugins to iterate concurrently. The number must be a positive integer.

Example

new DAG(pluginA, pluginB, pluginC)
  .forEach((plugin, next, percent) => {
    log(`running ${plugin.name} - ${percent}% complete`);
    next('stop'); // stop iterating early
  }, err => {
    if (err) {
      log('stopped early because:', err);
    }
  });

Package Sidebar

Install

npm i cycle-plugins

Weekly Downloads

6

Version

0.1.1

License

MIT

Last publish

Collaborators

  • ihateregistration