# in

> Plugin loader. Plays with Ware

Latest version **0.19.0** (published 2021-11-01) · 0 weekly downloads

## Install

```sh
npm install in
pnpm add in
yarn add in
bun add in
```

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support; pre 1.0.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 0.19.0 |
| Published | 2021-11-01 |
| First published | 2015-04-14 |
| Weekly downloads | 0 |
| TypeScript types | none |
| Module format | CommonJS |
| Node | >= 7.6 |
| Dependencies | 5 |
| Unpacked size | 31.8 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 1 |
| Author | goliatone |
| Maintainers | goliatone |
| Keywords | plugins, ware, plugin |

## Links

- npm: https://www.npmjs.com/package/in
- Repository: https://github.com/goliatone/in
- Issues: https://github.com/goliatone/in/issues
- npm.io page: https://npm.io/package/in

## Dependencies (5)

- [verror](https://npm.io/package/verror.md) ^1.10.0
- [gextend](https://npm.io/package/gextend.md) ^0.6.0
- [multimatch](https://npm.io/package/multimatch.md) ^4.0.0
- [noop-console](https://npm.io/package/noop-console.md) ^0.8.0
- [recursive-readdir-async](https://npm.io/package/recursive-readdir-async.md) ^1.1.6

## Recent versions

- 0.19.0 (latest) — 2021-11-01
- 0.18.2 — 2020-06-05
- 0.18.0 — 2020-06-05
- 0.17.0 — 2019-09-09
- 0.16.2 — 2019-08-26
- 0.16.0 — 2019-07-14
- 0.15.0 — 2019-07-14
- 0.14.0 — 2019-01-19
- 0.13.2 — 2019-01-14
- 0.13.0 — 2018-12-25
- 0.12.2 — 2018-08-27
- 0.12.0 — 2017-11-22
- 0.11.4 — 2017-10-09
- 0.11.3 — 2017-10-02
- 0.11.2 — 2017-09-27
- … 19 more at https://npm.io/package/in/versions

## README

# in

Generic plugin loader facility.


<!-- toc orderedList:0 -->

- [in](#in)
	- [Getting Started](#getting-started)
	- [Documentation](#documentation)
		- [constructor options](#constructor-options)
		- [context](#context)
		- [mountDirectory(directory,options,context)](#mountdirectorydirectoryoptionscontext)
		- [find(directory)](#finddirectory)
		- [sort(plugins)](#sortplugins)
			- [sortFilter](#sortfilter)
				- [sortByDependencies](#sortbydependencies)
		- [normalize(plugins)](#normalizeplugins)
			- [String](#string)
			- [Array](#array)
			- [Object](#object)
			- [Mixed](#mixed)
		- [filter(plugins)](#filterplugins)
		- [load(plugins, options={})](#loadplugins-options)
		- [mount](#mount)
		- [mountHandler](#mounthandler)
		- [afterMount(context)](#aftermountcontext)
	- [Examples](#examples)
	- [Release History](#release-history)
	- [License](#license)

<!-- tocstop -->


## Getting Started

Install the module with: `npm install in`

```js
const PluginLoader = require('in');
```

A plugin should expose a `init` function.

```js
module.exports.init = function(app, config){};
```

A module can expose a `priority` value:

```js
module.exports.priority = 5000;
```
A negative value indicates a higher priority

A module can expose a 'dependencies' value:

```js
module.exports.dependencies = ['logger'];
```

## Documentation

A plugin is nothing more than a regular Node module. By default, we expect plugins to expose an `init` function that takes two arguments:

* [context](#context)
* config

### constructor options

* [context](#context)
* [basepath](#basepath)
* [normalize](#normalizeplugins)
* [mountHandler](#mounthandler)
* [sortFilter](#sortfilter)
* [afterMount](#aftermountcontext)

### context

This is where all plugins will be mounted. This would normally be your application instance.

### mountDirectory(directory,options,context)

It will mount all plugins found in directory into the provided context.

This is in effect applying [find](#finddirectory), [filter](#filterplugins), [load](#loadplugins-options), [sort](#sortplugins), and [mount](#mount) in that order.

### find(directory)

Scans a directory for files and directories, returning a list of absolute paths to the files.
It `target` is not an absolute path, we resolve it against `basepath`.

### sort(plugins)

Sorts an array of plugins after they have been loaded. By default it uses `sortFilter`:

#### sortFilter

It will looks for `module.exports.priority` and sort based on that:

```js
function _sortFilter(plugins){
	function filter(a, b) {
		function p(i){
			return i.priority === undefined ? 0 : i.priority;
		}
		return p(a) < p(b) ? -1 : 1;
	}
	return plugins.sort(filter);
}
```
##### sortByDependencies

The library also exposes a [sortByDependencies][sortbydependencies] filter, which you can use instead of the default `sortFilter`.

```js
const loader = new PluginLoader({
    sortFilter: require('in').sortByDependencies
});
```

Modules should expose a `dependencies` array listing the ids of depended modules.

```js
module.exports.dependencies = ['logger', 'persistence'];
```

### normalize(plugins)

When we call load we apply the `normalize` function which will ensures that `plugins` can be any of the following:

#### String

```js
const plugins = '/Users/application/plugins/authentication';
```

Output after calling `normalize`:

```js
[
    {
        "id": "authentication",
        "path": "/Users/application/plugins/authentication",
        "config": {}
    }
]
```

#### Array

```js
const plugins = ['/Users/application/plugins/authentication'];
```

Output after calling `normalize`:

```js
[
    {
        "id": "authentication",
        "path": "/Users/application/plugins/authentication",
        "config": {}
    }
]
```

#### Object

```js
const plugins = {
    '/Users/application/plugins/authentication': { hash: 'sh1' }
};
```

Output after calling `normalize`:

```js
[
    {
        "id": "authentication",
        "path": "/Users/application/plugins/authentication",
        "config": {
            "hash": "sh1"
        }
    }
]
```

#### Mixed

```js
const plugins = [
    {'/Users/application/plugins/authentication':{ hash: 'sh1' }},
    'debug'
];
```

Output after calling `normalize`:

```js
[
    {
        "id": "authentication",
        "path": "/Users/application/plugins/authentication",
        "config": {
            "hash": "sh1"
        }
    },
    {
        "id": "debug",
        "path": "debug",
        "config": {}
    }
]
```

### filter(plugins)

Public: Apply `minimatch` patterns against `paths`, an array of paths. The default pattern is `['**', '!node_modules', '!.git']`
Returns a `Promise` which once resolved will contain an Array of filtered paths.

### load(plugins, options={})

Given a list of plugins, create a plugin object with metadata and the result of `require`ing the module.

We create a bean per plugin:

```js
{
    id: 'logger',
    path: '/Users/in/examples/plugins/logger.js',
    config: {},
    plugin: { init: [Function], priority: -100 },
    isLocal: true
}
```

### mount

Makes plugins available to the provided context by calling `mountHandler` to previously loaded plugins.

### mountHandler

Adds a `plugin` to the provided `context`.

```js
function _mount(bean, context, config={}){
	config = extend({}, bean.config, config);
	var plugin = bean.plugin;
	if(typeof bean.config === 'function') return bean.config(plugin, context, config);
	if(typeof bean.config.mount === 'function') return bean.config.mount(plugin, context, config);
	if(typeof plugin.init === 'function') return plugin.init(context, config);
	return context[bean.id] = plugin;
}
```

### afterMount(context)

Function that will be called right after `mount`

## Examples

Look at the [examples][examples] directory. Run it with `node examples/index.js`.

Directory structure:

- index.js
- plugins
    - repl.js
    - pubsub.js
    - logger.js
    - authentication
        - index.js

```js
const PluginManager = require('..');
const EventEmitter = require('events');

const app = new EventEmitter();

app.on('plugins.ready', _ => {
    app.logger.info('Application plugins loaded');
});

const manager = new PluginManager({
    context: app,
    basepath: __dirname,
	afterMount: (context) => context.emit('plugins.ready')
});

manager.mountDirectory('./plugins')
    .catch(console.error);
```

`logger.js`:

```js
module.exports.init = function(app, config) {
    app.logger = console;
    app.logger.info('Plugin logger loaded!');
};

module.exports.priority = -100;
```

`repl.js`:

```js
module.exports.init = function(app, config) {

    app.repl = {
        context: {app}
    };

    app.logger.info('Plugin REPL loaded!');
};

```

`pubsub.js`:

```js
module.exports.init = function(app, config) {
    app.pubsub = {
        publibsh: function(type, event){
            app.logger.warn('publish: %s. payload: %s', type, event);
        },
        subscribe: function(type, handler){
            app.logger.warn('subscribe to %s', type);
        }
    };
    app.logger.info('Plugin pubsub loaded!');
};
```

`authentication/index.js`:

```js
module.exports.init = function(app, config) {
    app.auth = {
        check: function(){}
    };
    app.logger.info('Plugin auth loaded!');
};

module.exports.priority = 500;
```

`node examples/load/index.js`:

```
Plugin logger loaded!
Plugin REPL loaded!
Plugin pubsub loaded!
Plugin auth loaded!
Application plugins loaded
```


## Release History

* 2020-06-04: v0.18.2 hotfix release
* 2020-06-04: v0.18.0 Add support for sub directories in plugins target dir
* 2019-09-08: v0.17.0 Update version of dependencies
    * Export `normalizePath` from `lib/normalizeArguments.js`
    * Export `getIdFromPath` from `lib/normalizeArguments.js`
* 2019-08-26: v0.16.2 Update version of dependencies
* 2019-07-13: v0.16.0 Remove synchronous file access
* 2019-07-13: v0.15.0 Update version of dependencies
* 2016-11-24: v0.9.0  Added `sortByDependencies`
* 2016-11-18: v0.8.0  Update mount to take in `afterMount` in options
* 2016-11-14: v0.7.0  `normalizePath` use `basepath` from argument
* 2016-11-13: v0.6.0  Refactoring mount
* 2016-10-24: v0.5.0  Added `afterMount`
* 2016-10-23: v0.4.0  Big update
    * Added examples
    * Added documentation
    * Added `mountDirectory`

## License
Copyright (c) 2015 goliatone  
Licensed under the MIT license.

[examples]: ./examples
[sortbydependencies]: ./lib/sortbydependencies.js

---
_Source: https://npm.io/package/in · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
