Skip to content

Latest commit

 

History

History
148 lines (125 loc) · 5.42 KB

README.md

File metadata and controls

148 lines (125 loc) · 5.42 KB

plugin-use


A simple Event Emitter, tuned to be used as a plugin driver.

license:mit npm:? build:? coverage:? dependencies:? devDependencies:?
Join the Slack chat Join the Gitter chat

Supported Browsers
Chrome Edge Firefox Safari IE
9, 10, 11

What is plugin-use?

"Plugin Use" is a small module which you can use to make a plugin system for a project. It essentially creates an Event Emitter with special properties which make it useful for writing encapsulated plugins:

  • Individual plugins can't subscribe to their own events emitted, only events from other plugins.
  • While each plugin gets its own event emitter, all plugins receive events from other registered plugins.
  • Every emitted event is stored in a buffer, and replayed to newly registered plugins, so they can handle past messages.
  • The central library can mutate any emitted events, allowing it to coerce values or change behaviours (e.g. throw on an error event with no listeners).
  • Plugins can also pass a plain object, which the library can decide what to do with.

Why?

A simple EventEmitter, such as the one provided by default in Node.js is not sufficient for a plugin system as some events need to be special cased.

Installation

Node.js

plugin-use is available on npm. To install it, type:

$ npm install plugin-use

Deno

plugin-use can be imported with the following line:

import createUse from 'https://deno.land/x/[email protected]/index.ts'

Usage

The primary export of plugin-use is the createUse function that can gets called by the library that wants a plugin system:

import createUse from 'plugin-use'

// Create a mapping of well known events and the arguments they have, this will help
// for TypeScript type checking:
interface EmitMap {
  'error': [Error],
  'assert': [boolean],
}

// Create a type which represents the value of each property in the object pattern
type PluginObjectValue = (...args: any[]) => any

const use = createUse<EmitMap, PluginObjectValue>({
  
  // If a plugin is instantiated with a plain object, then `handleObject` is
  // called for each property, allowing you to map them to events to be emitted
  handleObject(emitter: Emitter<EmitMap>, key: string | number, value: PluginObjectValue) {
    emitter.emit(key, value)
  },

  // We can special case some events by using `handleEmit`. Return `true` to
  // mark this event as handled, meaning it won't be emitted by this library.
  handleEmit<K extends keyof EmitMap>(emitter: Emitter<EmitMap>, name: K, ...args: EmitMap[K]): boolean {
    // Throw on an `error` event if there are no listeners for it, just like NodeJS!
    if (name === 'error' && emitter.count('error') === 0) {
      throw args[0]
    }
    // Let this library handle the rest of the events.
    return false
  },

  // If a plugin function returns a value, then `handleReturn` will be called to deal with it.
  handleReturn(emitter: Emitter<EmitMap>, value: any) {
    emitter.emit('assert', value)
  },

})