extends-mixin

ES6 mixins brought to you by inheritance

Usage no npm install needed!

<script type="module">
  import extendsMixin from 'https://cdn.skypack.dev/extends-mixin';
</script>

README

extends-mixin

npm package build code climate coverage issues dependencies devDependencies downloads

The purpose of this package is to provide a function for reducing a collection of mixins into a single mixin that applies each of the mixins. Let's take an example:

Lets assume we have a Person class with a name field that we want to augment to include accessors for accessing a person's first and last name.

class Person {
  constructor(name) {
    this.name = name;
  }
}

const john = new Person('John Doe');
assert.equal(john.name, 'John Doe');

We can create a mixin to get the first name like so:

const canGetFirstName = Base => class extends Base {
  get first() {
    return this.name.split(' ').shift();
  }
};

const PersonWithFirstName = canGetFirstName(Person);
const john = new PersonWithFirstName('John Doe');

assert.equal(john.name, 'John Doe');
assert.equal(john.first, 'John');

We can also create another mixin to get the last name like so:

const canGetLastName = Base => class extends Base {
  get last() {
    return this.name.split(' ').pop();
  }
};

const PersonWithLastName = canGetLastName(Person);
const john = new PersonWithLastName('John Doe');

assert.equal(john.name, 'John Doe');
assert.equal(john.last, 'Doe');

If we want to combine the mixins, we would typically do something like this:

const PersonWithFirstAndLastName = canGetFirstName(canGetLastName(Person));
const john = new PersonWithFirstAndLastName('John Doe');

assert.equal(john.name, 'John Doe');
assert.equal(john.first, 'John');
assert.equal(john.last, 'Doe');

While this appears ok for two mixins, it becomes difficult to read as the number of mixins increase. Consider the following:

const CustomPerson = canGetFirstName(canGetLastName(canGetChildren(canGetSiblings(Person))));

The purpose of this package is to make combining mixins easier by allowing you to do this:

const mix = require('extends-mixin');

const canGetAncestry = mix([
  canGetFirstName,
  canGetLastName,
  canGetChildren,
  canGetSiblings
]);

const CustomPerson = canGetAncestry(Person);

You can also pass each mixin as an argument if it is more convenient:

const mix = require('extends-mixin');

const canGetAncestry = mix(
  canGetFirstName,
  canGetLastName,
  canGetChildren,
  canGetSiblings
);

const CustomPerson = canGetAncestry(Person);

If your mixin list happens to be empty, the identity function is returned:

const mix = require('extends-mixin');
const identity = mix();
const JustAPerson = identity(Person);

const john = new JustAPerson('John Doe');
assert.equal(john.name, 'John Doe');

Because this package reduces many mixins to a single mixin, grouping mixins is easy:

const mix = require('extends-mixin');

const canGetFirstAndLastName = mix(canGetFirstName, canGetLastName);
const canGetChildrenAndSiblings = mix(canGetChildren, canGetSiblings);
const canGetAncestry = mix(canGetFirstAndLastName, canGetChildrenAndSiblings);

const CustomPerson = canGetAncestry(Person);

As a convenience, a function is provided for loading all mixins within a directory. Nested directories are required as normal. Only files with .js extensions are accepted and index.js is ignored. A typical index.js would be the following:

module.exports = require('extends-mixin/all')(__dirname);

Pull requests and bug reports are welcome, as always.