babel-plugin-elsa

2.3.1 • Public • Published

Elsa

Mutability is dangerous, let it go!

Babel plugin that replaces object and array literals with immutable versions… that have super powers!

Build Status

Usage

Elsa is a babel plugin, to make use of it, you need to install it:

npm install --save babel-plugin-elsa

Add elsa as a plugin to your .babelrc config file (or babel section of package.json):

{
  "plugins": ["babel-plugin-elsa"]
}

Purpose

Immutability is cool these days. By never altering the contents of an object or array, and instead cloning them when you want to make a change, you avoid common bugs. It's especially popular in React development, but by no means exclusive to React.

There are great libraries out there like Immutable.js that provide a bunch of classes for making immutable objects, but wouldn't it be frosty to turn the default object and arrays into immutable objects?

Don't worry, there are no more puns past this point, they've been put on ice.

Elsa does two things:

  • It turns each object literal into a FrozenObject.
  • It changes each [array literal](array into a FrozenArray.

Both FrozenObjects and FrozenArrays are immutable classes included with Elsa. If you try to change their contents, they'll raise a TypeError since they've been frozen with Object.freeze. Assuming you have strict mode enabled (which you ought to do).

Elsa will:

// Turn this:
const person = {
  name: 'Jon',
  skills: ['ruby', 'javascript']
};

// into:
const person = new FrozenObject({
  name: 'Jon',
  skills: new FrozenArray('ruby', 'javascript')
});

Why create these new classes instead of just calling Object.freeze? To give them super powers, read on!

FrozenArray

Elsa turns all array literals (e.g. const coolNumbers = [1,5,-4,20];) into instances of FrozenArray.

FrozenArray inherits from JavaScript's built-in Array. This means it has a .length, is an instance of Array, and any of the methods that you'd expect like .forEach and .map.

The methods on Array that would typically mutate the array are reimplemented onFrozenArray to instead return a fresh instance of FrozenArray with changes applied. This includes push, pop, unshift, shift, sort, reverse, splice, and fill.

slice, map, and other methods that already return new arrays are still available, but return FrozenArray instances instead of a normal mutable array.

pop and shift return both the modified arrays and the shifted/popped values as two elements inside an array. That way you can do: [arr, poppedVal] = arr.pop().

Examples:

  • push: new FrozenArray(1,2,3).push(5) -> [1, 2, 3, 5]
  • pop: new FrozenArray(1,2,3).pop() -> [[1, 2], 3]
  • unshift: new FrozenArray(1,2,3).shift(0) -> [0,1,2,3]
  • shift: new FrozenArray(1,2,3).shift() -> [[2,3], 1]
  • sort: new FrozenArray(2,1,3).sort((a,b) => a - b) -> [1,2,3] Note: Return values are all instances of FrozenArray

FrozenObject

Elsa turns all object literals (e.g. const dog = { name: 'Loki', age: 4 };) into instances of FrozenObject.

FrozenObject is identical to a normal JavaScript object, but it has been frozen by Object.freeze and has a special method called update, provided by immutability-helper.

To see all the ways you can get a clone, with changes applied, using update see the immutability-helper docs: https://github.com/kolodny/immutability-helper

One example:

const dog = { name: 'Loki', age: 4, friends: ['Waffles', 'Mochi'] };
const dogClone = dog.update({ name: { $set: 'Loki 2.0' }, friends: { $push: ['Seamus'] } });
// dogClone now contains { name: 'Loki 2.0', age: 4, friends: ['Waffles', 'Mochi', 'Seamus'] }

Opting out of FrozenArray and FrozenObject

Elsa will ignore arrays created with new Array(1,2,3) or Array.of(1,2,3), which will produce old fashioned mutable arrays.

To create mutable objects, you can do new Object({ name: 'Loki' }), which Elsa will skip over, resulting in old fashioned mutable objects.

Gotchas and tips

  • Elsa will only alter object and array literals. If you create an object using a function of new constructor, it won't be frozen (at least not by Elsa). Only […] and {…} are frozen by Elsa.
  • Some libraries expect to receive mutable objects as their parameters. If you receive type errors in libraries that you use, try sending in an object created with new Object({…}).
  • Elsa only converts your code. Babel, and therefore Elsa, doesn't convert 3rd party modules. This means that any objects produced by libraries won't be frozen.
  • You can freeze objects returned by libraries by wrapping it with new FrozenObject(…).
  • If you don't use Elsa as a Baebl plugin, you can still use FrozenArray and FrozenObject with your code. Just do import FrozenArray from 'babel-plugin-elsa/frozen_array' and/or import FrozenObject from 'babel-plugin-elsa/frozen_object'.

Sample App

I've written a very basic todo app (of course) that makes use of Elsa.

License

ISC

Package Sidebar

Install

npm i babel-plugin-elsa

Weekly Downloads

3

Version

2.3.1

License

ISC

Last publish

Collaborators

  • jonabrams