npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

plugorg

v1.0.2

Published

manages plugins and plugin types

Downloads

73

Readme

plugorg Build Status Coverage Status

PlugOrg is a plugin organiser/manager. You can manage multiple sets of plugins (by way of plugin types, optional if you only care about one homogenous set of plugins), plugins can be loaded dynamically at any time and thereafter listed or otherwise managed.

Plugin types can automatically verify plugins of that type when they are added.

Plugins, and plugin types, may have attributes, to distinguish them in arbitrary fashions.

Quick example use case

Say you have an application with multiple components, and a menu to select each one and want to separate the components as extensions, even allowing for users or integrators to add their own.

One way to do this is as follows, first create a plugin type like this:

let plugorg_widget_pltype = (function() {

    let plugorg_widget_pltype = function plugorg_widget_pltype (menu) {
		this.menu = $(menu);
    };

    plugorg_widget_pltype.prototype.po_name = function () {
        return 'widget';
    };

    plugorg_widget_pltype.prototype.po_validplugin = function (plugin) {
		if (typeof plugin.menu_text !== 'function')
			throw new Error('bad widget plugin "'+plugin.po_name()+'", no "menu_text" method');
		if (typeof plugin.render !== 'function')
			throw new Error('bad widget plugin "'+plugin.po_name()+'", no "render" method');
		this.menu.append($('<ul><a href="component.html?name='+plugin.po_name()+'">'+plugin.menu_text()+'</a></ul>'));
        return true;
    };

    return plugorg_widget_pltype;

})();

module.exports = plugorg_widget_pltype;

This saves a DOM element menu when it is instantiated, verifies any plugin added has certain methods available and when a conformant plugin is added it appends a list item to the menu DOM.

Now create an actual plugin:

let plugorg_log_widget_plugin = (function() {

    let plugorg_log_widget_plugin = function plugorg_log_widget_plugin (pltype, params) {
		this.pltype = pltype;
    };

    plugorg_log_widget_plugin.prototype.po_type = function (ref) {
        return 'widget';
    };

    plugorg_log_widget_plugin.prototype.po_name = function (ref) {
        return 'log';
    };

	plugorg_log_widget_plugin.prototype.menu_text = function () {
		return 'Activity log';
	};

	plugorg_log_widget_plugin.prototype.render = function (container) {
        $(container)
            .empty()
            .append($('<div class="log_widget">blah blah blah</div>'));
	};

    return plugorg_log_widget_plugin;

})();

module.exports = plugorg_log_widget_plugin;

This declares a 'widget' plugin of name 'log', with menu_text and render methods to support its use.

Now, in the app initialisation, the plugin organiser and widget plugin type can be initialised like this:

let plugorg = require('plugorg');

let plugins = new plugorg();

plugins.add_type(require('plugorg_widget_pltype'), menu);

Note the 'menu' DOM element is passed when the plugin type is initialised. This is passed as a parameter to the plugin type constructor.

Now, a routine could take steps to see what plugins are available and add them, or by some user action at any time thereafter a plugin may be added, but in any case simply adding a plugin will modify the DOM such that the menu is extended:

plugins.add_plugin(require('plugorg_widget_plugin'));

And, given the link added to the menu, a DOM element may be rendered:

// gets 'name' query string param
let component_name = get_name_param();

let component_plugin = plugins.get_plugin({
    type: 'widget',
    name: component_name,
});

component_plugin.render(container);

Here, the query parameter 'name' is sought and used to get the correct plugin, which is invoked to render the page/element.

A fully working and more advanced version of this, with multiple plugins is to be found in the demo directory, run a HTTP server for it and check it out.

Usage walk through

An instance of the plugin organiser is instantiated like this:

let plugorg = require('plugorg');

let plugins = new plugorg();

Adding a plugin can be done like this:

plugins.add_plugin(require('my_first_plugin'));

Minimum plugin implementation

The implementation for my_first_plugin should, minimally, look something like this:

let my_first_plugin = (function() {

    let my_first_plugin = function my_first_plugin (params) {
    };

    my_first_plugin.prototype.po_name = function (ref) {
        return 'my_first_plugin';
    };

    return my_first_plugin;

})();

module.exports = my_first_plugin;

The export must be a constructor with a prototype function po_name, which returns a string identifying the plugin, distinguishing it from all other plugins of the same type (see below).

There are two implied functions, which because they are not included above are taken as follows:

    my_first_plugin.prototype.po_type = function (ref) {
        return 'default';
    };

    my_first_plugin.prototype.po_attribs = function (ref) {
        return {};
    };

The first, declares the name of the plugin type, default, which is the only plugin type that exists out of the box.

The second, declares a set of key value pairs, and the plugin will be indexed by them (see below).

Plugin types

If the plugin example above implemented po_type as follows...

    my_first_plugin.prototype.po_type = function (ref) {
        return 'my_first_pltype';
    };

...then when it is added, the plugin organiser expects to find a plugin type with a name of 'my_first_pltype', and if it is not found an error will be thrown.

Note that a plugin name is required to be unique for a given plugin type, so you may not add two plugins with the same name if they are the same type, but you may add two plugins with the same name if they are different types.

Minimum plugin type implementation

The implementation of the out of the box plugin type called 'default' is minimal (existing only to satisfy the demand for a type to exist for all plugins for consistency in cases where the user does not actually require plugin types) as follows:

let plugorg_pt_default = (function() {

    let plugorg_pt_default = function plugorg_pt_default () {
    };

    plugorg_pt_default.prototype.po_name = function () {
        return 'default';
    };

    plugorg_pt_default.prototype.po_validplugin = function (plugin) {
        return true;
    };

    return plugorg_pt_default;

})();

module.exports = plugorg_pt_default;

So, an implementation of 'my_first_pltype' can copy this, changing the name. The po_validplugin function may be omitted, which presumes the plugin type has nothing to do to validate a newly added plugin of its type.

Finding plugins

Getting a complete list of all plugins can be achieved by calling get_plugins. This call returns an array of zero or more instantiated plugins:

let all_plugins = plugins.get_plugins();

If you are using plugin types this probably never makes sense, as a list of a particular type of plugin would generally be the most you would want. To get all the plugins of a type with name 'jquery_widgets' do this:

let all_plugins = plugins.get_plugins({type:'jquery_widgets'});

To get a particular plugin, of known name say, you can call the singular method get_plugin, which is like get_plugins but returns a plugin instance, not a list of plugins:

let editor_plugin = plugins.get_plugin({type:'jquery_widgets',name:'editor'});

Omitting the type criteria here works as well, but this is technically dangerous if you have multiple types, since there may be a cross type plugin name clash!

Note that when you call get_plugin, if there are multiple matches, an error is thrown, so you must know there is no more than one possible match or you should use get_plugins. If there is no match, undefined is retuened.

Finding by attributes

If a plugin po_attribs method was implemented as follows...

    jquery_widgets.prototype.po_attribs = function (ref) {
        return {
            group: 'interactive',
			size:  4
		};
    };

...then this plugin could also be 'found' using the attributes:

let editor_plugin = plugins.get_plugin({type:'jquery_widgets',size:4});

Or, all 'interactive jQuery widgets could be found:

let inter_jq_plugins = plugins.get_plugins({type:'jquery_widgets',group:'interactive'});

Any number of clauses may be added to get_plugins or get_plugin.

Finding plugin types

This is much the same as finding plugins, the only different being types do not have a type. Two methods exist, get_type and get_types, and valid keys are 'name', and anything that may be returned by a type's po_attribs method.